如何使Heroku上的Python仅支持HTTPS?
我在Heroku上有一个用Python/Django写的应用(使用Cedar堆栈),我想让它只能通过https访问。我已经开启了“ssl piggyback”选项,现在可以通过https连接到它。
但是,怎么才能最好地禁用http访问,或者把http的请求自动转到https呢?
6 个回答
不确定 @CraigKerstiens 的回答是否考虑到了,如果在 Heroku 的反向代理后面,request.is_secure()
总是返回 False
,而且没有“修复”。如果我没记错的话,这会导致 HTTP 重定向循环。
如果你在用 gunicorn 运行 Django,另一种方法是在 gunicorn 的配置中添加以下内容:
secure_scheme_headers = {
'X-FORWARDED-PROTO': 'https'
}
在你的 Procfile 中运行类似这样的命令:
web: python manage.py run_gunicorn -b 0.0.0.0:$PORT -c config/gunicorn.conf
通过设置 gunicorn 的 secure-scheme-header
,request.is_secure()
在处理 https 请求时会正确返回 True
。可以查看 Gunicorn 配置。
这样一来,@CraigKerstiens 的中间件就能正常工作,包括你应用中对 request.is_secure()
的任何调用。
注意:Django 也有同样的配置设置,叫做 SECURE_PROXY_SSL_HEADER
,不过是在开发版本中。
Django 1.8将会支持非HTTPS的重定向,这个功能是从django-secure集成过来的。
SECURE_SSL_REDIRECT = True # [1]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
要让SECURE_SSL_REDIRECT
这个设置生效,你需要使用SecurityMiddleware
这个中间件。
MIDDLEWARE = [
...
'django.middleware.security.SecurityMiddleware',
]
[1] https://docs.djangoproject.com/en/1.8/ref/settings/#secure-ssl-redirect
把@CraigKerstiens和@allanlei的回答结合起来,做成了一个我测试过并且确认有效的内容。Heroku在请求使用ssl时,会把HTTP_X_FORWARDED_PROTO设置为https,我们可以用这个来进行检查:
from django.conf import settings
from django.http import HttpResponseRedirect
class SSLMiddleware(object):
def process_request(self, request):
if not any([settings.DEBUG, request.is_secure(), request.META.get("HTTP_X_FORWARDED_PROTO", "") == 'https']):
url = request.build_absolute_uri(request.get_full_path())
secure_url = url.replace("http://", "https://")
return HttpResponseRedirect(secure_url)