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

查看:19
本文介绍了使 Flask 的 url_for 使用 'https'AWS 负载均衡器中的方案,而不会与 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 发送301 永久重定向到 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,因为我听说这是推荐的做法.除此之外,使用 Flask.redirect 将在非 _external url 前面加上 http://example.com,因为重定向标头必须是完全限定的 URL.

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

由于 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-to-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 使用 'https'AWS 负载均衡器中的方案,而不会与 SSLify 混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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