Django1.x升级3.1后局域网跨机访问报CSRF验证失败问题
问题描述
报错信息:
CSRF cookie not sent
- 待恢复站点原生基于Django 1.x开发,已完成Python 2.7到Python 3的版本适配,当前运行环境为Django 3.1.2
- 站点共包含3个POST提交表单,本地启动Django服务访问时所有表单提交功能运行正常
- 使用局域网内其他设备访问服务时,所有表单提交均触发上述CSRF错误
- 已确认模板内正确添加
{% csrf_token %}标签,初步判断为Django 3.1版本CSRF相关配置适配问题,需要明确排查方向与解决方案
相关代码片段
表单示例代码
<form action="/blog/upload" method="POST" enctype="multipart/form-data"> <ul> <li><label for="id_title">Title:</label> <input type="text" name="title" maxlength="50" required id="id_title"></li> <li><label for="id_file">File:</label> <input type="file" name="file" required id="id_file"></li> </ul> <input type="hidden" name="csrfmiddlewaretoken" value="eYpdkogXUvof1IqJzgMvJcEGMBpXbvoNLTZNfEjz6aY7WebxbxsvId3nPmT7S4PF"> <input type="submit" value="Go" /> </form>
视图函数代码
def handle_uploaded_file(f, to_filename): print("In handle_uploaded_file") with open(f'uploads/{to_filename}', 'wb+') as destination: for chunk in f.chunks(): destination.write(chunk) print(f"wrote {to_filename}") def upload_file(request): print("in upload_file") if request.method == 'POST': print("request.method == 'POST'") form = UploadFileForm(request.POST, request.FILES) if form.is_valid(): print("form is valid") print(request) handle_uploaded_file(request.FILES['file'], request.POST['title']) return HttpResponseRedirect('upload') else: print("in upload_file else clause") form = UploadFileForm() return render(request, 'blog_app/upload_form.html', {'form': form})
模板代码
{% extends 'base.html' %} {% block head %} <title>joelgoldsick.com - {{entry.title}}</title> {% endblock %} {% block content %} <form action="{% url 'upload_file' %}" method="POST" enctype="multipart/form-data"> {% csrf_token %} <ul>{{ form.as_ul }}</ul>{% csrf_token %} <input type="submit" value="Go" /> </form> {% endblock %}
排查方向与解决方案
按优先级从高到低排查:
- 配置
CSRF_TRUSTED_ORIGINS项
Django 3.1版本正式收紧了跨源请求的CSRF校验规则,通过局域网IP访问属于非localhost的外部请求源,必须显式加入信任列表才能正常下发CSRF Cookie。在settings.py中添加如下配置,替换为实际的服务器局域网IP和服务端口:# 示例:服务器局域网IP为192.168.3.12,服务运行在8000端口 CSRF_TRUSTED_ORIGINS = [ 'http://192.168.3.12:8000', ] - 校验CSRF Cookie相关配置
检查settings.py中如下配置项,本地HTTP调试时需保证:CSRF_COOKIE_SECURE = False:如果设为True,CSRF Cookie只会在HTTPS连接下下发,HTTP访问的局域网客户端无法拿到CookieCSRF_COOKIE_DOMAIN = None:不要手动设置Cookie域,默认配置即可适配局域网IP访问场景SESSION_COOKIE_SECURE = False:和CSRF Cookie逻辑一致,HTTP环境下不要开启Secure标记
- 检查服务启动绑定地址
启动Django服务时不能默认绑定127.0.0.1,否则局域网设备虽然能连通但Cookie的域校验会异常,启动命令需指定绑定0.0.0.0:python manage.py runserver 0.0.0.0:8000 - 清理模板冗余代码
现有模板中同一个表单内重复写了两次{% csrf_token %},虽然不会直接触发报错,但属于无效冗余,保留表单标签内任意一处即可。
注意:修改配置后需要清理浏览器缓存、重启Django服务再测试,避免旧Cookie缓存影响校验结果。
内容的提问来源于stack exchange,提问作者joel goldstick
相关产品推荐
相关产品推荐

