繁体   English   中英

在 Flask+Heroku 上将 HTTP 重定向到 HTTPS

[英]Redirect HTTP to HTTPS on Flask+Heroku

当我尝试将传入流量重定向到 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 的piggyback ssl 来最小化成本。

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)

在 Heroku 上,SSL (https) 在到达您的应用程序之前已终止,因此您的应用程序实际上从未看到 SSL 流量。 要检查请求是否是使用 https 发出的,您必须检查x-forwarded-proto标头。 更多信息: How to make python on Heroku https only?

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

我尝试了 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))

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

我能够将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 

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

这里是对运行在 heroku 上的 Flask 应用程序上的所有调用强制执行 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)

你可以这样做:

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

在我对另一个问题的回答中,我已经说明了最新的 Flask 建议。 使用 Talisman 而不是 SSLify。

对于 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。 为此,请参阅文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM