为什么Django的CSRF不能通过HTTPS工作?

Wil*_*hes 3 django https django-csrf

我在http://example.com上有一个Django网站,工作正常,包括帖子请求.我添加了HTTPS,因此我的网站也可以通过https://example.com访问.

我可以在HTTPS上加载任何页面,但是当我尝试POST时,我总是遇到CSRF验证错误.POST请求在HTTP上正常工作.

我的Django进程在nginx后面运行gunicorn,我有nginx设置X_Forwarded_For.因此,HTTPS请求具有以下标头(取自request.META):

'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.5',
'HTTP_CONNECTION': 'close',
'HTTP_COOKIE': 'redacted',
'HTTP_HOST': 'example.com:80',
'HTTP_REFERER': 'https://example.com/user/delete/49/',
'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0',
'HTTP_X_FORWARDED_FOR': '1.2.3.4, 192.168.252.22',
'HTTP_X_FORWARDED_PROTO': 'https',
'HTTP_X_REAL_IP': '1.2.3.4',
Run Code Online (Sandbox Code Playgroud)

并且HTTP请求具有以下标头:

'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.5',
'HTTP_CONNECTION': 'close',
'HTTP_COOKIE': 'redacted',
'HTTP_HOST': 'example.com.com:80',
'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0',
'HTTP_X_FORWARDED_FOR': '1.2.3.4, 192.168.252.22',
'HTTP_X_FORWARDED_PROTO': 'http',
'HTTP_X_REAL_IP': '1.2.3.4',
Run Code Online (Sandbox Code Playgroud)

当我在HTTP上没有问题时,为什么CSRF不能在HTTPS上工作?

Wil*_*hes 10

原来这是一个nginx配置问题.我的服务器设置是:

nginx - > nginx - > gunicorn

在第二个nginx系统上,我有

proxy_set_header        Host            $host:$server_port;
Run Code Online (Sandbox Code Playgroud)

但是,由于HTTPS在第一个nginx处终止,$server_port因此始终为80.

在HTTPS上,Django会进行严格的引用检查(参见第4点).看看Django来源:

good_referer = 'https://%s/' % request.get_host()
if not same_origin(referer, good_referer):
    reason = REASON_BAD_REFERER % (referer, good_referer)
    logger.warning('Forbidden (%s): %s', reason, request.path,
        extra={
            'status_code': 403,
            'request': request,
        }
    )
    return self._reject(request, reason)
Run Code Online (Sandbox Code Playgroud)

CSRF验证失败是因为"https://example.com/" != "https://example.com:80/".

  • 解决办法是什么? (9认同)