使Flask的url_for在AWS负载均衡器中使用'https'方案而不会弄乱SSLify [英] Make Flask's url_for use the 'https' scheme in an AWS load balancer without messing with SSLify

查看:147
本文介绍了使Flask的url_for在AWS负载均衡器中使用'https'方案而不会弄乱SSLify的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近向我的Web应用程序添加了SSL证书.它使用负载平衡器部署在Amazon Web Services上.负载平衡器充当反向代理,处理外部HTTPS并发送内部HTTP.因此,尽管连接是安全的,但我Flask应用程序的所有流量都是HTTP,而不是HTTPS.

I've recently added a SSL certificate to my webapp. It's deployed on Amazon Web Services uses load balancers. The load balancers work as reverse proxies, handling external HTTPS and sending internal HTTP. So all traffic to my Flask app is HTTP, not HTTPS, despite being a secure connection.

因为该网站在HTTPS迁移之前已经在线,所以我使用 SSLify 发送到HTTP连接.尽管所有连接都是HTTP,它仍然有效,因为反向代理将X-Forwarded-Proto请求标头设置为原始协议.

Because the site was already online before the HTTPS migration, I used SSLify to send 301 PERMANENT REDIRECTS to HTTP connections. It works despite all connections being HTTP because the reverse proxy sets the X-Forwarded-Proto request header with the original protocol.

url_for不在乎X-Forwarded-Proto.当方案不可用时,它将使用my_flask_app.config['PREFERRED_URL_SCHEME'],但是在请求期间,方案可用.与反向代理连接的HTTP方案.

url_for doesn't care about X-Forwarded-Proto. It will use the my_flask_app.config['PREFERRED_URL_SCHEME'] when a scheme isn't available, but during a request a scheme is available. The HTTP scheme of the connection with the reverse proxy.

因此,当有人连接到https://example.com时,它会连接到负载均衡器,然后使用http://example.com连接到Flask. Flask看到了http并假定该方案是HTTP,而不是原来的HTTPS.

So when someone connects to https://example.com, it connects to the load balancer, which then connects to Flask using http://example.com. Flask sees the http and assumes the scheme is HTTP, not HTTPS as it originally was.

对于大多数模板中使用的url_for来说这不是问题,但是任何_external=Trueurl_for都将使用http而不是https.就个人而言,我将_external=True用作rel=canonical,因为听说这是推荐的做法.除此之外,由于重定向标头必须是完全限定的URL,因此使用Flask.redirect将在非外部url之前加上http://example.com.

That isn't a problem in most url_for used in templates, but any url_for with _external=True will use http instead of https. Personally, I use _external=True for rel=canonical since I heard it was recommended practice. Besides that, using Flask.redirect will prepend non-_external urls with http://example.com, since the redirect header must be a fully qualified URL.

例如,如果您重定向到一个表单发布,则会发生这种情况.

If you redirect on a form post for example, this is what would happen.

  1. 客户帖子https://example.com/form
  2. 服务器向http://example.com/form-posted
  3. 发出303 SEE OTHER
  4. SSLify然后向https://example.com/form-posted
  5. 发出301 PERMANENT REDIRECT
  1. Client posts https://example.com/form
  2. Server issues a 303 SEE OTHER to http://example.com/form-posted
  3. SSLify then issues a 301 PERMANENT REDIRECT to https://example.com/form-posted

由于SSLify,每个重定向都变为2个重定向.

Every redirect becomes 2 redirects because of SSLify.

https://stackoverflow.com/a/26636880/1660459

my_flask_app.config['PREFERRED_URL_SCHEME'] = 'https'

不起作用,因为在请求期间有一种方案,而是使用一种方案.参见 https://github.com/mitsuhiko/flask/issues/1129#issuecomment- 51759359

Doesn't work because there is a scheme during a request, and that one is used instead. See https://github.com/mitsuhiko/flask/issues/1129#issuecomment-51759359

https://stackoverflow.com/a/28247577/1660459

def _force_https(app):
    def wrapper(environ, start_response):
        environ['wsgi.url_scheme'] = 'https'
        return app(environ, start_response)
    return wrapper
app = Flask(...)
app = _force_https(app)

按原样,这不起作用,因为我以后需要该应用程序.因此,我改用了 wsgi_app .

As is, this didn't work because I needed that app later. So I used wsgi_app instead.

def _force_https(wsgi_app):
    def wrapper(environ, start_response):
        environ['wsgi.url_scheme'] = 'https'
        return wsgi_app(environ, start_response)
    return wrapper
app = Flask(...)
app.wsgi_app = _force_https(app.wsgi_app)

因为wsgi_app在任何app.before_request处理程序之前被调用,所以这样做会使SSLify认为该应用程序已经在安全请求之后,因此它将不执行任何HTTP到HTTPS重定向.

Because wsgi_app is called before any app.before_request handlers, doing this makes SSLify think the app is already behind a secure request and then it won't do any HTTP-to-HTTPS redirects.

(我什至找不到我从哪里买到的)

(I can't even find where I got this one from)

from functools import partial
import Flask
Flask.url_for = partial(Flask.url_for, _scheme='https')

这可能有效,但是如果您设置_scheme而不是_external,则Flask将给出错误.由于我的大多数应用程序url_for都是内部应用程序,因此根本无法正常工作.

This could work, but Flask will give an error if you set _scheme but not _external. Since most of my app url_for are internal, it doesn't work at all.

推荐答案

我最近在AWS Elastic Load Balancer后面遇到了与`redirect(url_for('URL'))'相同的问题.我使用 werkzeug.contrib.fixers.ProxyFix 解决了这个问题 调用我的代码. 例如:

I was having these same issues with `redirect(url_for('URL'))' behind an AWS Elastic Load Balancer recently & I solved it this using the werkzeug.contrib.fixers.ProxyFix call in my code. example:

from werkzeug.contrib.fixers import ProxyFix
app = Flask(__name__)

app.wsgi_app = ProxyFix(app.wsgi_app)

ProxyFix(app.wsgi_app)将HTTP代理支持添加到未考虑HTTP代理设计的应用程序中.它从X-Forwarded标头中设置REMOTE_ADDR,HTTP_HOST.

The ProxyFix(app.wsgi_app) adds HTTP proxy support to an application that was not designed with HTTP proxies in mind. It sets REMOTE_ADDR, HTTP_HOST from X-Forwarded headers.

示例:

from werkzeug.middleware.proxy_fix import ProxyFix
# App is behind one proxy that sets the -For and -Host headers.
app = ProxyFix(app, x_for=1, x_host=1)

这篇关于使Flask的url_for在AWS负载均衡器中使用'https'方案而不会弄乱SSLify的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆