使Flask的url_for在AWS负载均衡器中使用'https'方案而不会弄乱SSLify [英] Make Flask's url_for use the 'https' scheme in an AWS load balancer without messing with 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 发送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=True
的url_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.
- 客户帖子
https://example.com/form
- 服务器向
http://example.com/form-posted
发出 - SSLify然后向
https://example.com/form-posted
发出
303 SEE OTHER
301 PERMANENT REDIRECT
- Client posts
https://example.com/form
- Server issues a
303 SEE OTHER
tohttp://example.com/form-posted
- SSLify then issues a
301 PERMANENT REDIRECT
tohttps://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屋!