具有CSRF / CORS的TokenAuthentication问题的Django REST框架 [英] Django REST Framework w/ TokenAuthentication issue with CSRF/CORS
问题描述
我在Django REST框架中使用TokenAuthentication让脚本远程访问我的API。运行API的域位于TLS证书后面。
我已经通过多个来源浏览过,并尝试了许多选项,然后再来看看我的问题。总之,我继续得到 CSRF验证失败。请求中止。
当我尝试发布时出错。
这是我的观点:
#@csrf_exempt
@api_view(['POST'])
@authentication_classes((TokenAuthentication,))
@permission_classes((permissions.IsAuthenticated ,))
def create_object(request):
csrf_exempt
decorator这里什么也没做。所以,我也试过我的 urls.py
:
url(r'^ create_object /',csrf_exempt(views.create_object),),
我甚至试过编写自定义装饰器,并使用此建议。即使我这样做,我甚至不能让这个装饰师在得到失败之前执行。也许中间件的订购有问题吗?
'sslify.middleware.SSLifyMiddleware',
'django .middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django .middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib .auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages .middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
这里是我的django cors设置:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST =('example。 com',)
CORS_REPLACE_HTTPS_REFERER = True
按照承诺,这里是我想出的解决方案。诚然,这并不完美。我无法弄清楚底层的问题(为什么在应用程序没有回应 c> csrf_exempt 或 CORS_REPLACE_HTTPS_REFERER
,但是想出了这个有限的解决方案。
步骤1
我将整个 CsrfViewMiddleware
类分成我自己的版本,并将其放入我的中间件(从原始查询标记的更改):
,
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware'
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',# #CHANGE
'myapp.csrf.CsrfViewMiddleware',## CHANGE
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware。 AuthenticationMiddleware',
django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django。中间件.clickjacking.XFrameOptionsMiddleware',
在我的版本的 CsrfViewMiddleware
,我将现有条件替换为:
acceptable_referers = ['https://%s'%u for u in settings.CORS_ORIGIN_WHITELIST] + ['http://%s'%u for u in settings.CORS_ORIGIN_WHITELIST]
if not same_origin(referer,good_referer)and引用者不在可接受的提交者中:
这让我过去了无效的引用者问题,这是很好的,因为我是白名单这些域都没关系它基本上得到与 CORS_REPLACE_HTTPS_REFERER
相同的结果。我的版本与 settings.CORS_ORIGIN_WHITELIST
交叉引用引用标头,而 CORS_REPLACE_HTTPS_REFERER
方法暂时更改请求
引用。对我来说,似乎没有足够的安全解决方案 - 但这是另一个对话。
步骤2
在这一点上,我还是得到了csrf cookie找不到错误。为了规避这个问题,由于 csrf_exempt
没有重新启动(似乎中间件执行得太早),我添加了一个新的中间件:
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib。 session.middleware.SessionMiddleware',
'myapp.csrf.CsrfSkipMiddleware'## ADDED
'corsheaders.middleware.CorsMiddleware',
' django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',## REMOVED
'myapp.csrf.CsrfViewMiddleware',## ADDED
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django .contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware ,
'django.middleware.clickjacking.XFrameOptionsMiddleware',
这个新的中间件本质上在 CsrfViewMiddleware
的库存版本上已经存在的请求对象( _dont_enforce_csrf_checks
)上设置一个标志,并告诉脚本忽略csrf检查的其余部分。为了做到这一点,它检查页面路径与我选择从设置中的csrf中删除的路径列表.CSRF_SKIP_URLS
。
class CsrfSkipMiddleware(object):
def process_request(self,request):
CSRF_SKIP_URLS = [re.compile(expr )for CBRF_SKIP_URLS]
path = request.path_info.lstrip('/')
如果有的话(CSRF_SKIP_URLS中的m的m.match(路径)):
setattr(request,'_dont_enforce_csrf_checks',True)
THOUGHTS p>
再次,不是最好的实现。但是,为了我的目的,它的作品。仍然欢迎有想法。
I am using TokenAuthentication in Django REST Framework to have a script remotely access my API. The domain running the API is behind a TLS certificate.
I have scoured through MANY sources, and tried many options before coming here to figure out what my problem is. In short, I continue to get the CSRF verification failed. Request aborted.
error when I attempt to post.
Here is my view:
# @csrf_exempt
@api_view(['POST'])
@authentication_classes((TokenAuthentication,))
@permission_classes((permissions.IsAuthenticated,))
def create_object(request):
csrf_exempt
decorator has done nothing here. So, I have also tried it on my urls.py
:
url(r'^create_object/', csrf_exempt(views.create_object),),
I even tried writing a custom decorator, and using this suggestion. Even when I do this, I cannot even seem to get that decorator to execute before getting the failure. Perhaps there is an issue with the ordering of my middleware?
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
Here are my django cors settings:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = ('example.com',)
CORS_REPLACE_HTTPS_REFERER = True
As promised, here is the solution that I came up with. Admittedly, this is not perfect. I was not able to figure the underlying problem (why on HTTPS the app was not responding to csrf_exempt
, or CORS_REPLACE_HTTPS_REFERER
), but came up with this limited solution.
STEP 1
First, I subclassed the entire CsrfViewMiddleware
class into my own version, and placed it into my middleware (changes from original quertion marked):
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', ##CHANGE
'myapp.csrf.CsrfViewMiddleware', ##CHANGE
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
At about line 160 of my version of CsrfViewMiddleware
, I replaced the existing conditional to this:
acceptable_referers = ['https://%s' % u for u in settings.CORS_ORIGIN_WHITELIST] + ['http://%s' % u for u in settings.CORS_ORIGIN_WHITELIST]
if not same_origin(referer, good_referer) and referer not in acceptable_referers:
This got me past the invalid referer issue, which is fine because I am whitelisting the domains that are okay. It essentially comes to the same result as CORS_REPLACE_HTTPS_REFERER
. My version cross-references the referer header with settings.CORS_ORIGIN_WHITELIST
, while the CORS_REPLACE_HTTPS_REFERER
method temporarily changes the request
referer. Neither seems to me a sufficient enough security solution--but that is another conversation.
STEP 2
At this point, I was still getting the csrf cookie not found error. To circumvent this problem, and since csrf_exempt
was not respoding (it seemed as if the middleware was executing too early), I added a new piece of middleware:
'sslify.middleware.SSLifyMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'myapp.csrf.CsrfSkipMiddleware' ##ADDED
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', ##REMOVED
'myapp.csrf.CsrfViewMiddleware', ##ADDED
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
This new piece of middleware essentially sets a flag on the request object (_dont_enforce_csrf_checks
) that already exists on the stock version of CsrfViewMiddleware
and tells the script to ignore the rest of the csrf check. In order to do that, it checks the page path against a list of paths that I have selected to remove from csrf in settings.CSRF_SKIP_URLS
.
class CsrfSkipMiddleware(object):
def process_request(self, request):
CSRF_SKIP_URLS = [re.compile(expr) for expr in settings.CSRF_SKIP_URLS]
path = request.path_info.lstrip('/')
if any(m.match(path) for m in CSRF_SKIP_URLS):
setattr(request, '_dont_enforce_csrf_checks', True)
THOUGHTS
Again, not the best implementation. But, for my purposes it works. Thoughts are still welcome.
这篇关于具有CSRF / CORS的TokenAuthentication问题的Django REST框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!