回顧
-
通過前幾篇文章的內容, 我們已經基於 Python 的 Flask 框架搭建了一個基本 Web 應用,
~/webapp/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 header
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'] = 'max-age=15768000; includeSubDomains; preload'
. 因此可以得到如下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
, 這是在瀏覽器內部進行的重定向, 不許要經過我們的redirect.py
, 減少了一次不必要的訪問. 這也是HSTS
帶來的好處之一. - 如果想了解更多關於
HSTS
的內容, 可以參考這篇博客: HSTS學習筆記.