如何使用Django / nginx部署仅HTTPS站点?

我原来的问题是如何启用HTTPS的Django的login页面 ,唯一的回应,build议我 – 使整个网站只有HTTPS

鉴于我正在使用Django 1.3和nginx,有什么正确的方法,使网站HTTPS的?

一个响应提到了一个中间件解决scheme ,但有一个警告:

Django在维护POST数据时不能执行SSLredirect。 请构build您的意见,使redirect只发生在GET。

关于nginx重写为https的服务器故障的一个问题,也提到了POSTs丢失数据的问题,而且我对nginx不够熟悉,无法确定解决scheme的效果。

而EFF的build议是仅使用HTTPS ,注意到:

设置时,应用程序必须在Cookie上设置“安全”属性。 该属性指示浏览器仅通过安全(HTTPS)传输发送cookie,从不安全(HTTP)。

像Django-auth这样的应用程序能够将cookies设置为Secure? 还是我必须写更多的中间件?

那么,什么是configurationDjango / nginx的组合来实现仅HTTPS的最佳方式,具体如下:

  • 安全
  • 保存POST数据
  • cookies正确处理
  • 与其他Django应用程序(如Django-auth)的交互,工作正常
  • 任何其他问题,我不知道:)

编辑 – 我刚刚发现的另一个问题,同时testing多个浏览器。 说我有urlhttps://mysite.com/search/ ,它有一个search表单/button。 我点击button,像往常一样在Django中处理表单,然后执行Django HttpResponseRedirect到http://mysite.com/search?results="foo" 。 Nginx根据需要将它redirect到https://mysite.com/search?results="foo"

但是 – Operaredirect发生时,Opera具有可见的闪存 。 它发生每一个search,即使对于相同的search术语(我猜https实际上不caching:)更糟糕的是,当我在IE中testing它时,我首先得到的消息:

您即将被redirect到一个不安全的连接 – 继续?

点击“是”之后,紧接着是:

您即将通过安全连接查看网页 – 继续?

虽然第二个IE警告有一个选项可以closures – 第一个警告不会,所以每次有人进行search并被redirect到结果页面时,他们至less会收到一条警告消息。

对于约翰C的答案,和Django 1.4 +的第二部分…

而不是扩展HttpResponseRedirect,您可以将request.scheme更改为https 。 由于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://...等等…

这是迄今为止我所做出的解决方案。 有两部分,配置nginx,并为Django编写代码。 nginx部分处理外部请求,将http页面重定向到https ,Django代码处理具有http前缀的内部 URL生成。 (至少,从HttpResponseRedirect() )。 综合起来,它似乎运作良好 – 据我所知,客户端浏览器从来没有看到一个用户没有自己输入的http页面。

第一部分,nginx配置

 # 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; } } 

第二部分A,来自settings.py的各种安全Cookie设置

SERVER_TYPE =“DEV”
SESSION_COOKIE_HTTPONLY =真
SESSION_COOKIE_SECURE =真
CSRF_COOKIE_SECURE = True#目前只在Django的Dev分支。
SESSION_EXPIRE_AT_BROWSER_CLOSE =真

第二部分B,Django代码

 # 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() 。 缺点 – 你必须把装饰器放在django.http.__init__.py Django中的HttpResponseRedirect() django.http.__init__.py 。 我不想修改Django的代码,但这取决于你自己 – 这当然是一个选择。

如果你坚持你的整个网站后面的https,你不需要担心它在Django结束。 (假设你不需要保护nginx和django之间的数据,只能在用户和你的服务器之间)