【问题标题】:Redirect HTTP to HTTPS on Flask+Heroku在 Flask+Heroku 上将 HTTP 重定向到 HTTPS
【发布时间】:2013-02-13 12:13:19
【问题描述】:

当我尝试将传入流量重定向到 https 时,我得到一个无限重定向循环。

@app.route('/checkout/')                                                                                                                                                                                        
def checkout():                                                                                                                                                                                                 
    checkout = "https://myapp.herokuapp.com/checkout/"                                                                                                                                              
    if checkout != request.url:                                                                                                                                                                             
        print checkout, request.url                                                                                                                                                                             
        return redirect(checkout)                                                                                                                                                                               
    return render_template('checkout.html', key=keys['publishable_key']) 

request.url 永远不会更改为 https 前缀。我想使用 heroku 的背驮式 ssl 来最小化成本。

【问题讨论】:

    标签: python heroku https flask


    【解决方案1】:

    在 Heroku 上,SSL (https) 在到达您的应用程序之前就被终止了,因此您的应用程序永远不会真正看到 SSL 流量。要检查是否使用 https 发出请求,您必须检查 x-forwarded-proto 标头。更多信息在这里:How to make python on Heroku https only?

    更新:为了您的使用,您应该只检查 request.url 中的“myapp.herokuapp.com/checkout/”;并验证标头是“https”

    【讨论】:

    • 谢谢朋友。我已经看过 flask-sslify 包。除了我使用自定义域和heroku的子域之外,这将满足我的需求。我只想将 SSL 放在一页上。不过谢谢你的文档,我会通读的。
    • 您应该只检查request.url 中的“myapp.herokuapp.com/checkout”并验证标头是否为“https”
    • 谢谢,就是这样。
    • 我已在答案中添加了评论 - 请考虑接受答案。
    • 我会认真考虑 :) 如果您在回答中提到 flask-sslify,我会更加重视。
    【解决方案2】:

    我能够将 flask-sslify 代码重新用于单个视图。只需要检查是否使用 SSL 发出请求并将正确的标头添加到响应中。 https://github.com/kennethreitz/flask-sslify

    @app.route('/checkout/')                                                                                                                                                                                        
    def checkout():                                                                                                                                                                                                 
        checkout = "https://myapp.herokuapp.com/checkout/"                                                                                                                                              
        if request.headers.get('X-Forwarded-Proto', 'http') == 'https':                                                                                                                                             
            resp = make_response(render_template('checkout.html', key=keys['publishable_key']))                                                                                                              
            return set_hsts_header(resp)                                                                                                                                                                            
        return redirect(checkout, code=302)                                                                                                                                                                         
    
    def set_hsts_header(response):                                                                                                                                                                                  
        """Adds HSTS header to each response."""                                                                                                                                                                    
        response.headers.setdefault('Strict-Transport-Security', hsts_header)                                                                                                                                       
        return response                                                                                                                                                                                             
    
    def hsts_header():                                                                                                                                                                                              
        """Returns the proper HSTS policy."""                                                                                                                                                                       
        hsts_policy = 'max-age={0}'.format(31536000) #year in seconds                                                                                                                                               
        if self.hsts_include_subdomains:                                                                                                                                                                            
            hsts_policy += '; includeSubDomains'                                                                                                                                                                    
            return hsts_policy 
    

    【讨论】:

      【解决方案3】:

      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)
      

      【讨论】:

      • 'DYNO' in os.environ 提示特别有用。
      【解决方案4】:

      我尝试了 SSLify、url_for _scheme,并设置了 PREFERRED_URL_SCHEME;但是没有一个成功,至少在发布级别..(在本地工作得很好)然后我想;

      @app.before_request
      def beforeRequest():
          if not request.url.startswith('https'):
              return redirect(request.url.replace('http', 'https', 1))
      

      这本质上是另一种无需任何配置或扩展即可完成的方法。

      【讨论】:

      • 这导致我“这个网页有一个重定向循环”
      • @tdc 有趣,在有人编辑此答案之前,您是否尝试过我给出的答案?我没有试过这个,虽然它看起来应该是一样的;我知道原版肯定效果很好。
      • 我没看过原版! SSLify 最终为我工作
      【解决方案5】:

      您只需要检查X-Forwarded-Proto 标头。如果为 false,则重定向到等效的 https url。

      这里是对运行在 heroku 上的烧瓶应用程序的所有调用强制执行 https 的代码:

      @app.before_request
      def enforceHttpsInHeroku():
        if request.headers.get('X-Forwarded-Proto') == 'http':
        url = request.url.replace('http://', 'https://', 1)
        code = 301
        return redirect(url, code=code)
      

      【讨论】:

        【解决方案6】:

        你可以这样做:

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

        【讨论】:

          【解决方案7】:

          在我对another question 的回答中,我已经说明了最新的 Flask 建议。使用 Talisman 代替 SSLify。

          对于 Flask,请使用 TalismanFlaskHerokuSSLify 文档倾向于使用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.

          【讨论】:

            猜你喜欢
            • 2021-08-31
            • 2019-03-24
            • 1970-01-01
            • 2014-05-14
            • 1970-01-01
            • 1970-01-01
            • 2017-11-05
            • 2014-11-24
            • 1970-01-01
            相关资源
            最近更新 更多