Cannot login, CSRF error. 无法登陆,提示CSRF错误。


#1

Problem

问题描述

After a clean docker run with my own SSL certificate, I cannot log in with web service, always got csrf error.
使用我自己提供的有效SSL证书,通过 Docker 安装全新的 Seafile,无法登入系统,总是提示CSRF错误。

Here is error detail:
错误详情:

Forbidden (403)
CSRF verification failed. Request aborted.

More information is available with DEBUG=True.

Reproduce

重现

First, get a valid certificate.
首先,获取一个有效的证书。

Then, run docker.
然后,运行 Docker。

docker run -d --name seafile --restart=always \
  -e SEAFILE_SERVER_LETSENCRYPT=true \
  -e SEAFILE_SERVER_HOSTNAME=cloud.example.com \
  -e SEAFILE_ADMIN_EMAIL=root \
  -e SEAFILE_ADMIN_PASSWORD=123456 \
  -v /data/seafile:/shared \
  -v /root/.acme.sh/*.example.com/*.example.com.cer:/shared/ssl/cloud.example.com.crt:ro \
  -v /root/.acme.sh/*.example.com/*.example.com.key:/shared/ssl/cloud.example.com.key:ro \
  -p 11080:80 \
  -p 11443:443 \
  seafileltd/seafile:latest

Then visit https://cloud.example.com:11443/, cannot login.
然后访问https://cloud.example.com:11443/,无法登陆。

Help
Reason given for failure:

    Referer checking failed - https://cloud.example.com:11443/accounts/login/?next=/ does not match any trusted origins.
    
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:

Your browser is accepting cookies.
The view function passes a request to the template's render method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.

You can customize this page using the CSRF_FAILURE_VIEW setting.

Notice

注意

After serval tries, I find that this problem only appears when use https, field csrfmiddlewaretoken in the committed form is not the same as using http. Maybe django got something wrong when use https and port not at 443?
尝试过几次之后我发现,只有在使用https方式配置的时候才会出现这个错误,使用http方式配置一点问题都没有,是不是django在处理非443端口的https请求时候,防止跨站攻击的csrf数据处理有误?

Thanks, waiting for your reply.
感谢!静候回应!


#2

问题怎么解决的啊?我也遇到了


#3

找了好久,找到一个不是很完美的解决方法,
可以搜索 “django 禁用CSRF 的方法”
我找到的是修改middleware\csrf.py文件,使用
grep -R 'CsrfViewMiddleware' . |grep csrf.py
找到它。
#找到如下代码:
if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
#修改为:
if request.method not in ('GET','POST', 'HEAD', 'OPTIONS', 'TRACE'):
并且找到settings.py
grep -R ''django.middleware.csrf.CsrfViewMiddleware'' . |grep seahub/seahub/settings.py
注释或者删掉掉'django.middleware.csrf.CsrfViewMiddleware',
修改文件后需要删掉同名的pyc文件,并且重启
这样改完后,登录不会再提示错误,但是管理后台修改某些东西的时候可能还会出现,比如修改用户的最大空间。

看起来这是由于一个安全验证导致的问题。
如果程序不能适应端口变化,为什么不把是否打开验证的选择权交给用户呢?


#4

编辑nginx的conf文件,将
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
替换为
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host:xxxx;
xxxx为你设定的https的端口号


#7

这样可以解决,比上面修改csrf.py,settings.py的方法好用