我有一个使用python3.4和烧瓶的网站构建...我已经生成了自己的自签名证书,我目前正通过localhost测试我的网站。
我正在使用python ssl模块以及此烧瓶扩展:https://github.com/kennethreitz/flask-sslify
context = ('my-cert.pem', 'my-key.pem')
app = Flask(__name__)
sslify = SSLify(app)
...
if __name__ == '__main__':
app.debug = False
app.run(
host="127.0.0.1",
port=int("5000"),
ssl_context=context
)
但这似乎并不奏效。我查看了sslify源代码,这行似乎不起作用
def init_app(self, app):
"""Configures the configured Flask app to enforce SSL."""
app.before_request(self.redirect_to_ssl)
app.after_request(self.set_hsts_header)
具体是对redirect_to_ssl的函数调用(我在redirect_to_ssl函数下添加了自己的print语句,我的语句从未打印过)
def redirect_to_ssl(self):
print("THIS IS WORKING")
"""Redirect incoming requests to HTTPS."""
Should we redirect?
criteria = [
request.is_secure,
current_app.debug,
request.headers.get('X-Forwarded-Proto', 'http') == 'https'
]
if not any(criteria) and not self.skip:
if request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 302
if self.permanent:
code = 301
r = redirect(url, code=code)
return r
我对python很新。有什么想法吗?
答案 0 :(得分:29)
对我来说,似乎你让它变得比它需要的更复杂。以下是我在views.py脚本中使用的代码,用于强制用户进行HTTPS连接:
@app.before_request
def before_request():
if request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
答案 1 :(得分:13)
根据docs,在pip install Flask-SSLify
之后,您只需要插入以下代码:
from flask import Flask
from flask_sslify import SSLify
app = Flask(__name__)
sslify = SSLify(app)
我做到了,效果很好。我在讨论中遗漏了什么吗?
答案 2 :(得分:5)
标准解决方案是使用enforce_ssl
装饰器包装请求,在检查应用程序配置中的一些标志(根据您的调试需求可以设置的标志)后,使用{{{{}修改请求的URL。 1}}。
写成here。
根据@ kelly-keller-heikkila
的建议,您可以修改代码以使其与request.url
一起使用
答案 3 :(得分:5)
Flask Security Guide建议使用Flask-Talisman。
$ pip install flask-talisman
用法示例:
from flask import Flask
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app)
默认情况下(自述文件)它强制HTTPS
:
force_https
,默认为True
,强制所有未调试的连接都连接到https
。
我个人遇到了一些与CSP(内容安全策略)有关的错误,这些错误已由我禁用:
Talisman(app, content_security_policy=None)
但是使用此方法需要您自担风险:)
答案 4 :(得分:2)
我使用一个简单的额外应用程序,该应用程序在端口80上运行,并将人们重定向到https:
from flask import Flask,redirect
app = Flask(__name__)
@app.route('/')
def hello():
return redirect("https://example.com", code=302)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
答案 5 :(得分:2)
这里是烧瓶解决方案,如果您在双脚上并且在负载均衡器后面。将其放在您的views.py
@app.before_request
def before_request():
scheme = request.headers.get('X-Forwarded-Proto')
if scheme and scheme == 'http' and request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
答案 6 :(得分:1)
感谢Kelly Keller-Heikkila的回答和jaysqrd的评论,我最终在Flask应用程序中做到了这一点:
from flask import request, redirect
...
@app.before_request
def before_request():
if not request.is_secure and app.env != "development":
url = request.url.replace("http://", "https://", 1)
code = 301
return redirect(url, code=code)
我尝试了Rodolfo Alvarez建议的flask_sslify
解决方案,但遇到了this issue并选择了上述解决方案。
使用app.env
检查可以在不使用https的情况下运行单元测试和本地开发。
答案 7 :(得分:1)
我遇到了在负载均衡器后面的AWS Elastic Beanstalk中运行Flask应用程序的相同解决方案。以下AWS文档提供了两个步骤来配置http重定向的环境:https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-httpredirect.html完成上述两个步骤后,解决了我的问题。
要注意的一件事是,您必须在应用程序源包的根目录级别创建.ebextenions文件夹,并将配置文件添加到该.ebextensions文件夹。这里的自述文件:https://github.com/awsdocs/elastic-beanstalk-samples对此进行了更详细的说明。
答案 8 :(得分:1)
我已经成功使用的其他答案的替代方法:
from http import HTTPStatus
from typing import Optional
from flask import Response, redirect, request, url_for
def https_redirect() -> Optional[Response]:
if request.scheme == 'http':
return redirect(url_for(request.endpoint,
_scheme='https',
_external=True),
HTTPStatus.PERMANENT_REDIRECT)
# ..
if app.env == 'production':
app.before_request(https_redirect)
# ..
答案 9 :(得分:0)
我正在使用在负载均衡器后面的cloud Foundry python应用程序(例如https://stackoverflow.com/users/5270172/kelly-keller-heikkila说)。 此解决方案通过添加(_external和_Scheme到url_for函数中)对我有所帮助。 https://github.com/pallets/flask/issues/773
答案 10 :(得分:0)
出于某种原因,来自具有VPC端点的私有AWS API网关的请求似乎不包含“ X-Forwarded-Proto”标头。这可能会破坏其他一些解决方案(要么不起作用,要么不断重定向到相同的URL)。以下中间件在大多数烧瓶生成的内部重定向上强制使用https:
class ForceHttpsRedirects:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ["wsgi.url_scheme"] = "https"
return self.app(environ, start_response)
# Usage
app = flask.Flask(__name__)
app.wsgi_app = ForceHttpsRedirects(app.wsgi_app) # Add middleware to force all redirects to https
答案 11 :(得分:0)
我遇到了同样的问题,我的是一个蛮力解决方案,但它有效。
Heroku 过去建议使用 flask_sslify
,现在不再维护。现在 Flask 中的正确方法应该是 flask-talisman
,但我尝试过,它与 boostrap 模板的交互很差。
我尝试了 anulaibar 解决方案,但它并不总是对我有用。
以下是我想出的:
@app.before_request
def before_request():
# If the request is sicure it should already be https, so no need to redirect
if not request.is_secure:
currentUrl = request.url
if currentUrl.startswith('http://'):
# http://example.com -> https://example.com
# http://www.example.com -> https://www.example.com
redirectUrl = currentUrl.replace('http://', 'https://', 1)
elif currentUrl.startswith('www'):
# Here we redirect the case in which the user access the site without typing any http or https
# www.example.com -> https://www.example.com
redirectUrl = currentUrl.replace('www', 'https://www', 1)
else:
# I do not now when this may happen, just for safety
redirectUrl = 'https://www.example.com'
code = 301
return redirect(redirectUrl, code=code)
我在 Godaddy 中注册了域,该域也重定向到 https://www.example.com。
答案 12 :(得分:0)
在应用引擎 flex 上,添加:
from werkzeug.middleware.proxy_fix import ProxyFix
def create_app(config=None):
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
除了解决方案:
@app.before_request
def before_request():
if not request.is_secure:
url = request.url.replace('http://', 'https://', 1)
code = 301
return redirect(url, code=code)
否则它会导致无限重定向,因为 SSL 在代理后面被解开,但会在标头中注明。