【问题标题】:How to make python on Heroku https only?如何仅在 Heroku https 上制作 python?
【发布时间】:2012-01-16 05:23:24
【问题描述】:

我在 Heroku(Cedar 堆栈)上有 python/django 应用程序,并希望仅通过 https 访问它。我启用了“ssl piggyback”选项,并且可以通过 https 连接到它。

但是禁用 http 访问或重定向到 https 的最佳方法是什么?

【问题讨论】:

    标签: python django ssl https heroku


    【解决方案1】:

    将@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)
    

    【讨论】:

    • 赞成把 github... 谢谢!正是我今天要找的。​​span>
    • 附带说明,如果您将 DEBUG 设置为 True,这将不起作用。花了一个小时弄清楚那个,所以希望这可以节省一些时间。
    • 在这种情况下,请记住将其添加到设置中以让 django 知道请求是安全的:SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    • 您似乎无法使用该中间件为 Django 提供静态文件。我仍然不知道为什么,因为我是通过 https 访问它的
    • request.is_secure() 已经处理了 HTTP_X_FORWARDED_PROTO 标头,您不应该再次检查它,请参阅 github.com/return1/django-sslify-admin/issues/1目前,始终检查 HTTP_X_FORWARDED_PROTO。然而;此标头可以伪造。正如 django 的开发人员所指出的,您应该非常明确地使用这些选项:docs.djangoproject.com/en/dev/ref/settings/…
    【解决方案2】:

    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

    【讨论】:

    • 这是否意味着从 Django 1.8 开始 pip 包 sslify 已过时?
    • @dfrankow django-sslify 听起来与 django-secure 相似,但您必须与包作者确认
    • @dfrankow 不,如果你想自动将用户从 http 重定向到 https,你仍然需要 Django 1.8 的 sslify。
    • sslify 的作者确认here @dfrankow 是正确的,对于 Django >= 1.8,sslify 已过时
    • 为本地服务器设置 SECURE_SSL_REDIRECT=False,为生产设置 True。这可以通过设置环境变量来完成。 os.environ.get("SECURE_SSL_REDIRECT")
    【解决方案3】:

    不确定@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-headerrequest.is_secure() 将在 https 请求上正确返回 True。见Gunicorn Config

    现在@CraigKerstiens 的中间件可以正常工作,包括在您的应用中对request.is_secure() 的任何调用。

    注意:Django 也有相同的配置设置调用SECURE_PROXY_SSL_HEADER,但在开发版本中。

    【讨论】:

    • django SECURE_PROXY_SSL_HEADER 设置现在在主线中可用(当然在 1.6 中,可能更早)。
    • 我把这个放在哪里?在什么文件中?
    【解决方案4】:

    您的应用程序使用什么框架?如果您使用的是 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)
    

    【讨论】:

    • 是的,我正在使用 django。感谢您的回答:除非出现更简单的东西(例如隐藏的heroku选项),否则我会尝试一下..
    • 我不得不对你的回答做一些小调整,但版主拒绝了我的编辑。我创建了自己的答案,它解决了当前答案中永无止境的重定向问题。无论如何,谢谢,如果没有您的贡献,永远不会想到中间件解决方案。
    【解决方案5】:

    2020 年更新:

    如果您使用的是 Flask,我会推荐以下内容:

    @app.before_request
    def before_request():
        if 'DYNO' in os.environ:
            if request.url.startswith('http://'):
                url = request.url.replace('http://', 'https://', 1)
                code = 301
                return redirect(url, code=code)
    

    以上在 Heroku 上运行良好,并允许您在本地开发中使用 httpheroku local

    Flask-SSLify 不再维护,也不再受到 Flask 社区的官方支持。

    2014 年原始答案:

    如果您使用的是 Flask,则效果很好:

    1. 执行“pip install flask-sslify”

    (github在这里:https://github.com/kennethreitz/flask-sslify

    1. 包括以下行:
    from flask_sslify import SSLify
    if 'DYNO' in os.environ: # only trigger SSLify if the app is running 
    on Heroku
        sslify = SSLify(app)
    

    【讨论】:

    【解决方案6】:

    对于 Flask 使用 Talisman。 FlaskHerokuSSLify 文档支持使用 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-30
      • 1970-01-01
      • 1970-01-01
      • 2014-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      相关资源
      最近更新 更多