回顧
-
通過前幾篇文章的內容, 我們已經搭建了基於
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 " % (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學習筆記.