【发布时间】:2019-08-15 12:46:57
【问题描述】:
我的 Django 版本是 2.2,我已经配置 httpd.conf (Apache/2.4.39 (Unix) mod_auth_gssapi/1.6.1 mod_wsgi/4.6.5 Python/3.7) 来启动一个进程池,如下所示:
WSGIDaemonProcess my_app processes=6 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${MY_ENV_VAR}
使用此设置,当我发出 POST 请求时,我会收到 Forbidden 403 errors 和 CSRF verification failed 消息。
如果我不断刷新页面,当我幸运的时候,我的 POST 请求就会成功。现在我猜这是因为请求可能已经通过具有“正确缓存”的 Django 实例到达 wsgi 进程。
为了测试上述理论,如果我将 httpd.conf 更改为只有 1 个池进程,如下所示,我不会收到 403 错误。
WSGIDaemonProcess my_app processes=1 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${MY_ENV_VAR}
我已按照Django documentation 上的 CSRF 特定说明进行操作,并在 CSRF_USE_SESSIONS 设置为 True 或 False 时尝试了两种方案
如果我打算为每个将运行我的 Django 应用程序的 wsgi 进程启动一个池,那么配置 Django 的推荐方法是什么?
我做了一些测试,并确认我的 views.py 在 403 错误发生时没有被调用。所以 Django 在尝试调用 views.py 之前就拒绝了 POST 请求。下面是views.py的sn-p:
def my_func(request):
if request.is_ajax() and request.method == 'POST':
# some logic
try:
response = ... # some logic to build response
return HttpResponse(json.dumps(response), content_type="application/json")
except Exception as e:
return HttpResponseBadRequest('\n'.join(errors))
return render(request, 'my_app/my_template.html', locals())
使用的模板有一个简单的形式:
<form class="form-horizontal" role="form">{% csrf_token %}
要提交表单,有一个 AJAX 调用:
$.ajax({
type: "post",
url: ".",
data: data,
cache: false,
processData: false,
contentType: false,
success: function(response) {
// some code
},
error: function(xhr, status, e) {
// some code
}
});
这是我的 httpd.conf 的 sn-p
LimitRequestFieldSize 50000
LimitRequestLine 50000
TimeOut 600
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule alias_module modules/mod_alias.so
LoadModule auth_gssapi_module modules/mod_auth_gssapi.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule filter_module modules/mod_filter.so
LoadModule info_module modules/mod_info.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule status_module modules/mod_status.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule wsgi_module modules/mod_wsgi.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule env_module modules/mod_env.so
LoadModule include_module modules/mod_include.so
WSGISocketPrefix ${MY_SOCKET_PREFIX}
WSGILazyInitialization On
WSGIRestrictEmbedded On
WSGIScriptReloading On
WSGIDaemonProcess my_app processes=6 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${HTTPD_my_app_PYTHONPATH}
#If I use the below that has processes=1 instead I do not get CSRF verification failure
#WSGIDaemonProcess my_app processes=1 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${HTTPD_my_app_PYTHONPATH}
Listen ${HTTPD_my_app_PORT}
<VirtualHost *:${HTTPD_my_app_PORT}>
Redirect / http://${MY_HOST}:${HTTPD_my_app_PORT_REDIRECT}/
</VirtualHost>
Listen ${HTTPD_my_app_PORT_REDIRECT}
<VirtualHost *:${HTTPD_my_app_PORT_REDIRECT}>
WSGIScriptAlias / ${HTTPD_my_app_BASE_DIR}/my_app_dir/wsgi.py
WSGIProcessGroup my_app
WSGIApplicationGroup %{GLOBAL}
<Directory "${HTTPD_my_app_BASE_DIR}/my_app_dir/">
<Files wsgi.py>
AuthType GSSAPI
AuthName "MY_ENTITY/GSSAPI"
GssapiCredStore keytab:${MY_KEYTAB}
GssapiAllowedMech krb5
GssapiPublishErrors On
SetHandler wsgi-script
Require valid-user
</Files>
</Directory>
<Directory ${HTTPD_my_app_BASE_DIR}/my_app_dir/media>
Require all granted
</Directory>
<Directory ${HTTPD_my_app_BASE_DIR}/static_files>
Require all granted
</Directory>
</VirtualHost>
【问题讨论】:
-
“右缓存”是什么意思? Django CSRF 保护不使用缓存。如果您显示您的视图和模板,它可能会显示问题所在。如果您认为可能是
mod_auth_gssapi导致了问题,那么我会添加有关您如何实现该问题的更多信息。 -
感谢您的评论。我添加了更多信息。 django 进程必须以某种方式知道令牌才能进行验证 - 所以“正确的缓存”只是指 django 进程知道的关于令牌的任何知识。因为有一个 django 进程池,我只是猜测并非所有 django 进程都知道令牌。最后,我只是好奇为什么当我设置 processes=1 时没有 CSRF 验证问题,而我将进程设置为多个我开始看到问题?
-
Django 不跟踪令牌。它将 cookie 与隐藏表单字段/HTTP 标头中的值进行比较。见how it works。
-
从您提供的链接中了解以上内容,为什么processes参数设置为大于1时不起作用,而processes=1时起作用?
-
我相信我只是想通了 - 添加了一个答案。请让我知道你的想法。非常感谢您的帮助。
标签: django apache mod-wsgi wsgi