我在Heroku(Cedar堆栈)上有python / django应用程序,并希望只通过https访问它。我启用了“ssl piggyback”-option,并可以通过https连接到它。
但是,禁用http访问或重定向到https的最佳方法是什么?
答案 0 :(得分:64)
将@CraigKerstiens和@allanlei的答案结合到我测试过的内容中,并验证可行。当请求是ssl时,Heroku将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)
答案 1 :(得分:47)
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
答案 2 :(得分:13)
不确定@ CraigKerstiens的答案是否考虑到request.is_secure()
总是返回False
,如果在Heroku的反向代理后面而不是“修复”。如果我没记错的话,这将导致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 Config。
现在,@ CraigKerstiens的中间件可以正常运行,包括在您的应用中对request.is_secure()
的任何来电。
注意:Django也有相同的配置设置调用SECURE_PROXY_SSL_HEADER
,但是在开发版本中。
答案 3 :(得分:6)
您使用的是什么框架?如果你正在使用Django,你可以简单地使用一些类似于:
的中间件import re
from django.conf import settings
from django.core import urlresolvers
from django.http import HttpResponse, HttpResponseRedirect
class SSLMiddleware(object):
def process_request(self, request):
if not any([settings.DEBUG, request.is_secure()]):
url = request.build_absolute_uri(request.get_full_path())
secure_url = url.replace("http://", "https://")
return HttpResponseRedirect(secure_url)
答案 4 :(得分:4)
如果你正在使用Flask,这很有效:
1)“pip install flask-sslify”
(github在这里:https://github.com/kennethreitz/flask-sslify)
2)包括以下几行:
from flask_sslify import SSLify
if 'DYNO' in os.environ: # only trigger SSLify if the app is running on Heroku
sslify = SSLify(app)
答案 5 :(得分:0)
对于 Flask,请使用 Talisman。 Flask、Heroku 和 SSLify 文档倾向于使用 Talisman 而不是 SSLify,因为后者不再维护。
来自SSLify:
<块引用>扩展不再维护,更喜欢使用 Flask-Talisman 作为 Flask 安全指南鼓励这样做。
通过 pip 安装:
$ pip install flask-talisman
启动扩展(示例):
from flask import Flask
from flask_talisman import Talisman
app = Flask(__name__)
if 'DYNO' in os.environ:
Talisman(app)
Talisman 默认启用 CSP(内容安全策略),仅允许加载来自同一域的资源。如果您想禁用它并处理影响:
Talisman(app, content_security_policy=None)
如果您不想禁用它,则必须设置 content_security_policy
参数以允许来自外部域的资源,例如 CDN。为此,请参阅 documentation。