具有CSRF / CORS的TokenAuthentication问题的Django REST框架 [英] Django REST Framework w/ TokenAuthentication issue with CSRF/CORS

查看:235
本文介绍了具有CSRF / CORS的TokenAuthentication问题的Django REST框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆