Web 開發學習筆記(4) --- 重定向與HSTS

回顧

  • 通過前幾篇文章的內容, 我們已經基於 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 Code301 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學習筆記.


參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章