CSRF 令牌上的 Django 错误
Posted
技术标签:
【中文标题】CSRF 令牌上的 Django 错误【英文标题】:Django bug on CRSF token 【发布时间】:2018-04-10 17:24:55 【问题描述】:我使用 django 作为后端的 web API,使用 React JS 作为前端的 web UI。用户将从 Web UI 注册,该 UI 将向 django 发送 POST 请求以使用用户详细信息进行注册。我想用 CSRF 保护注册视图。因此,我提出了以下步骤。
首先,加载注册页面后,我会发出一个虚拟的GET
请求来存储csrf 令牌,代码如下。
handleSend()
let req =
url: 'http://localhost:9000/vcubes/retrieve_token/',
method : 'GET',
withCredentials: true
axios(req)
然后,当用户提交注册表单时,会触发另一个 POST 请求。
const data = JSON.stringify(
'first_name': this.state.first_name,
'last_name': this.state.last_name,
'email': this.state.email,
'contact_number': this.state.contact_number,
'password1': this.state.password1,
'password2': this.state.password2,
)
let req =
url: 'http://localhost:9000/vcubes/signup/',
method : 'POST',
headers:
'Content-Type': 'text/plain'
,
data: data
axios.defaults.headers.common['X-CSRF-TOKEN'] = this.getCookie('vcubes')
使用上面的代码,会先向django发送一个OPTIONS,然后在django返回一个200 OK
之后,才会触发实际的POST请求。
惊喜! Django说我没有设置CSRF cookie。
Forbidden (CSRF cookie not set.): /vcubes/signup/
[30/Oct/2017 01:30:48] "POST /vcubes/signup/ HTTP/1.1" 403 2857
我的settings.py
在下面。 (我只展示了一些与 CORS 和 CSRF 相关的代码)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'corsheaders',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'custom_user',
'vcubes',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CSRF_TRUSTED_ORIGINS = (
'localhost:8000',
'127.0.0.1:8000'
)
CSRF_COOKIE_NAME = 'vcubes'
CSRF_HEADER_NAME = 'HTTP_X_CSRF_TOKEN'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'127.0.0.1:8000'
)
CORS_ALLOW_HEADERS = (
'access-control-allow-credentials',
'access-control-allow-origin',
'access-control-request-method',
'access-control-request-headers',
'accept',
'accept-encoding',
'accept-language',
'authorization',
'connection',
'content-type',
'dnt',
'credentials',
'host',
'origin',
'user-agent',
'X-CSRF-TOKEN',
'X-CSRFToken',
'x-requested-with',
)
在views.py中
@ensure_csrf_cookie
def retrieve_token(request):
return HttpResponse(status=200)
def signup(request):
print request.META
form = UserCreationForm(json.loads(request.body))
# user = form.save(commit=False)
# user.is_active = False
# user.save()
#
# mail_subject = 'Activate your account.'
# message = render_to_string('acc_active_email.html',
# 'name': user.get_full_name(),
# 'domain': 'localhost:9000',
# 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
# 'token': account_activation_token.make_token(user),
# )
# to_email = user
# email = EmailMessage(
# mail_subject, message, to=[to_email]
# )
# email.send()
return HttpResponse(status=200)
我花了一整天的时间从 google 和 *** 找出问题,但几乎没有得到任何帮助。请赐教!
【问题讨论】:
是CSRF_COOKIE_SECURE
也设置了吗?
如果你没有看到这篇文章,有很多你可以修复的,试试看this
CSRF_COOKIE_SECURE 默认设置为 false,这对我来说很好
您能显示/vcubes/retrieve_token/
的视图吗?另外,CSRF_header_NAME
应该全部大写。
@knbk CSRF_HEADER_NAME 也不起作用(调试过程中的错字哈哈)并且已经添加到retrieve_token 视图中
【参考方案1】:
您的 post 请求缺少 withCredentials: true
,这意味着您的 CSRF cookie 未随请求一起发送。
【讨论】:
有效!为什么我必须与axios.defaults.headers.common['X-CSRF-TOKEN'] = this.getCookie('vcubes')
一起发送 withCredentials: true ?如果没有后面的代码,请求标头中仍然有Cookie:vcubes=3HqESj1ea9Pw6gAah6CvlGOlvUDYURW1MBbwsXYpzIJWvXT6Sjiylpf2hDlSZgLh
。
CSRF 保护始终要求您将令牌作为 cookie 发送。它还要求您在请求正文中或作为标头发送令牌。以上是关于CSRF 令牌上的 Django 错误的主要内容,如果未能解决你的问题,请参考以下文章
Django 1.9 AJAX 表单 CSRF 令牌 403 错误 - “未设置 CSRF cookie”
部署到 AWS 服务器时 django 应用程序的 CSRF 令牌错误