我最初的问题是如何enable HTTPS for a Django login page以及唯一的回复,建议我 - 将整个网站设为仅限HTTPS 。
鉴于我正在使用Django 1.3和nginx,那么使网站成为HTTPS的正确方法是什么?
一个回复提到了a middleware solution,但有一点需要注意:
Django在维护POST数据时无法执行SSL重定向。 请构建您的视图,以便重定向仅在GET期间发生。
有关nginx rewriting to https的服务器故障的问题,还提到POST丢失数据的问题,我对nginx不太熟悉,无法确定解决方案的工作情况。
和EFF's recommendation to go HTTPS-only,注意到:
应用程序必须在cookie上设置Secure属性 设置它。此属性指示浏览器发送cookie 仅通过安全(HTTPS)传输,从不安全(HTTP)。
像Django-auth这样的应用程序是否能够将Cookie设置为安全?或者我是否必须编写更多中间件?
那么,根据以下几点,配置Django / nginx组合以实现仅HTTPS的最佳方法是什么:
编辑 - 我在测试多个浏览器时发现的另一个问题。假设我有一个URL https://mysite.com/search/
,它有一个搜索表单/按钮。我点击按钮,像往常一样处理Django中的表单,并执行Django HttpResponseRedirect到http://mysite.com/search?results="foo"
。 Nginx根据需要将其重定向到https://mysite.com/search?results="foo"
。
但是 - 重定向发生时,Opera有一个可见的 flash 。它发生在每次搜索,即使是相同的搜索词(我猜https真的不缓存:)更糟糕的是,当我在IE中测试它时,我首先得到消息:
您将被重定向到不安全的连接 - 继续吗?
点击“是”后,紧接着是:
您即将通过安全连接查看网页 - 继续吗?
虽然第二个IE警告可以选择将其关闭 - 第一个警告没有,所以每当有人进行搜索并被重定向到结果页面时,他们至少会收到一个警告消息。
答案 0 :(得分:51)
对于John C的回答的第二部分,以及Django 1.4 + ......
您可以将request.scheme
更改为https
,而不是扩展HttpResponseRedirect。
因为Django支持Nginx的反向代理,所以它不知道原始请求是安全的。
在Django设置中,设置SECURE_PROXY_SSL_HEADER设置:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
然后,您需要Nginx在反向代理中设置自定义标头。在Nginx网站设置中:
location / {
# ...
proxy_set_header X-Forwarded-Proto $scheme;
}
这种方式request.scheme == 'https'
和request.is_secure()
返回True。
request.build_absolute_uri()
会返回https://...
,依此类推......
答案 1 :(得分:20)
这是迄今为止我已经解决的解决方案。有两个部分,配置nginx,以及为Django编写代码。 nginx部分处理外部请求,将http
页面重定向到https
,Django代码处理内部 URL生成{{1} } 字首。 (至少是由http
产生的那些)。结合起来,似乎效果很好 - 据我所知,客户端浏览器永远不会看到用户自己没有键入的HttpResponseRedirect()
页面。
http
SERVER_TYPE =“DEV”
SESSION_COOKIE_HTTPONLY =正确
SESSION_COOKIE_SECURE =正确
CSRF_COOKIE_SECURE = True#目前仅在Django的Dev分支中
SESSION_EXPIRE_AT_BROWSER_CLOSE =真
# nginx.conf
# Redirects any requests on port 80 (http) to https:
server {
listen 80;
server_name www.mysite.com mysite.com;
rewrite ^ https://mysite.com$request_uri? permanent;
# rewrite ^ https://mysite.com$uri permanent; # also works
}
# django pass-thru via uWSGI, only from https requests:
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/mysite.com.chain.crt;
ssl_certificate_key /etc/ssl/private/mysite.com.key;
server_name mysite.com;
location / {
uwsgi_pass 127.0.0.1:8088;
include uwsgi_params;
}
}
请注意, 可以将# mysite.utilities.decorators.py
import settings
def HTTPS_Response(request, URL):
if settings.SERVER_TYPE == "DEV":
new_URL = URL
else:
absolute_URL = request.build_absolute_uri(URL)
new_URL = "https%s" % absolute_URL[4:]
return HttpResponseRedirect(new_URL)
# views.py
def show_items(request):
if request.method == 'POST':
newURL = handle_post(request)
return HTTPS_Response(request, newURL) # replaces HttpResponseRedirect()
else: # request.method == 'GET'
theForm = handle_get(request)
csrfContext = RequestContext(request, {'theForm': theForm,})
return render_to_response('item-search.html', csrfContext)
def handle_post(request):
URL = reverse('item-found') # name of view in urls.py
item = request.REQUEST.get('item')
full_URL = '%s?item=%s' % (URL, item)
return full_URL
重写为装饰器。优点是 - 不必遍历所有代码并替换HTTPS_Response()
。缺点 - 您必须将装饰器放在HttpResponseRedirect()
前面,HttpResponseRedirect()
位于Django中django.http.__init__.py
。我不想修改Django的代码,但这取决于你 - 这当然是一种选择。
答案 2 :(得分:5)
如果您将整个网站放在https后面,则无需担心django端。 (假设您不需要在nginx和django之间保护数据,仅在用户和服务器之间保护数据)