回顾
-
通过前几篇文章的内容, 我们已经搭建了基于
Flask
框架的一个简单的Web
应用,server.py
的代码如下from flask import Flask from flask.views import MethodView app = Flask(__name__) class IndexHandler(MethodView): def __init__(self, name): print(name) def get(self): return 'It is a GET request' def post(self): return 'It is a POST request' if __name__ == '__main__': app.add_url_rule('/', view_func=IndexHandler.as_view('index')) context = ('./server.cer', './server.key') app.run(port=443, host='0.0.0.0', debug=True, threaded=True, ssl_context=context)
此外, 我们还为其申请了公网 IP 和域名
www.awesome.com
, 并且部署了 Let's Encrypt 的 HTTPS 证书. 现在, 当我们在浏览器地址栏输入https://www.awesome.com
即可访问我们的网站. -
不过, 我们的网站目前还存在几个问题:
1.无法访问 http://www.awesome.com 2.每次都需要用户手动输入 https:// 前缀以制定 https 形式的访问
为此, 我们需要重新编写一个
server
并监听80
端口, 并对所有请求返回一个redirect
响应, 把所有http
请求都重定向为https
请求. 最后, 我们还将开启HSTS
, 方便用户、提高安全性的同时减少无效的访问.
监听 80
端口
-
考虑我们的目的只是为了进行重定向, 我们不如暂且撇开
Flask
, 用Python
自带的网络库写一个简单的server
, 把它当成一个练手的 demo.结合文档 wsgiref, 我们可以新建
~/webapp/redirect.py
并填写如下内容from wsgiref.util import setup_testing_defaults from wsgiref.simple_server import make_server def simple_app(environ, start_response): status = '200 OK' headers = [('Content-type', 'text/plain; charset=utf-8')] start_response(status, headers) ret = [("%s: %s\n" % (key, value)).encode("utf-8") for key, value in environ.items()] return ret with make_server('0.0.0.0', 80, simple_app) as httpd: httpd.serve_forever()
将 http
请求重定向为 https
请求
-
为了实现重定向(
redirect
), 我们需要构造这样一个http response
:- 它的
Status Code
是301 Moved Permanently
- 它的
headers
中包含了 redirect 的目标地址Location: https://...
, 其中 ... 是用户请求的URI
, 如首页的URI
就是https://www.awesome.com/
, 下面以这个URI
为例. - 最后将
response body
设为空即可
- 它的
-
因此我们可以得到这样的
response headers
HTTP/1.1 301 Moved Permanently Content-length: 0 Location: https://www.awesome.com/
我们可以据此修改
redirect.py
的内容from wsgiref.util import request_uri from wsgiref.simple_server import make_server def simple_app(environ, start_response): uri = request_uri(environ) # 获取 client 请求的地址 URI location = uri[:4] + 's' + uri[4:] # 将 http 替换成 https status = '301 Moved Permanently' # 设置 Status Code headers = [ ('Content-length', '0'), ('Location', location) ] # 设置 headers start_response(status, headers) return b'' httpd = make_server('0.0.0.0', 80, simple_app) httpd.serve_forever()
-
至此, 我们新编写的
server
已经完成了, 我们在~/webapp/
目录下打开一个Terminal
, 然后运行如下命令python3 redirect.py
接着, 我们打开浏览器的开发者工具, 并在地址栏输入
www.awesome.com
. 如果一切顺利, 我们将在开发者工具中看到一个301
跳转, 然后被重定向到https://www.awesome.com
开启 HSTS
-
为了开启
HSTS
, 我们需要在http response headers
中添加如下记录Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
以上内容在提供
https
服务的server
中添加即可, 因此我们需要修改~/webapp/server.py
. 首先引入make_response
, 然后在get()
方法中生成resp = make_response('It is a GET request')
, 以替换原来的生成响应的方法. 接着加上新的headers
记录resp.headers['Strict-Transport-Security']
. 因此可以得到如下server.py
from flask import Flask, make_response from flask.views import MethodView app = Flask(__name__) class IndexHandler(MethodView): def get(self): resp = make_response('It is a GET request') resp.headers['Strict-Transport-Security'] = 'max-age=15768000; includeSubDomains; preload' return resp if __name__ == '__main__': app.add_url_rule('/', view_func=IndexHandler.as_view('index')) context = ('./server.cer', './server.key') app.run(port=443, host='0.0.0.0', debug=True, threaded=True, ssl_context=context)
-
保存
server.py
之后, 我们运行server.py
python3 server.py
接着, 我们用无痕模式访问
www.awesome.com
, 在开发者工具中, 我们首先可以看到一个301
跳转, 然后在自动进行的对https://www.awesome.com
的请求之后, 我们就可以在response headers
看到新添加的Strict-Transport-Security
记录了.此时, 如果我们再次输入
www.awesome.com
, 从开发者工具中我们可以看到, 跳转码从301
变成了307
, 也就是Internal Redirect
, 这是在浏览器内部进行的重定向, 浏览器直接帮我们在本地把http
换成了https
, 而不需要经过我们的redirect.py
, 减少了一次不必要的访问. 这也是HSTS
带来的好处之一. - 限于篇幅, 本文只说明如何在
http response headers
中加入HSTS
. 如果想了解更多关于HSTS
的内容, 可以参考这篇博客: HSTS学习笔记.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。