Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

HTTPS 工作原理和前端相關知識

HTTPS 已經是現代 Web 的標配,但具體是怎麼工作的?和前端開發有什麼關聯?整理一下。

HTTP vs HTTPS

HTTP:明文傳輸,中間人可以看到和修改所有內容

HTTPS = HTTP + TLS(傳輸層安全協議)
  - 加密:數據對中間人不可讀
  - 驗證:確認連接的服務器是真的,不是仿冒的
  - 完整性:數據傳輸中沒有被篡改

TLS 握手簡化版

1. 客户端 → 服務器:我支持的 TLS 版本、加密算法列表
2. 服務器 → 客户端:選定的加密算法 + 數字證書(含公鑰)
3. 客户端:驗證證書合法性(CA 簽名)
4. 客户端 → 服務器:用公鑰加密一個隨機數
5. 雙方:用隨機數派生出對稱加密密鑰
6. 之後通信:用對稱密鑰加密(速度快)

數字證書

證書包含:
  - 域名(你的網站地址)
  - 公鑰
  - 頒發機構(CA)
  - 有效期
  - CA 的數字簽名

瀏覽器驗證證書:
  1. 域名是否和當前訪問的一致
  2. 有效期是否過期
  3. CA 簽名是否合法(是否是受信任的 CA 簽發)

前端開發中的 HTTPS 問題

混合內容(Mixed Content)

html
<!-- HTTPS 頁面里加載 HTTP 資源 → 被瀏覽器阻止 -->
<img src="http://example.com/image.jpg" />
<!-- 被阻止 -->
<script src="http://cdn.com/lib.js"></script>
<!-- 被阻止 -->

<!-- 修復:改成 HTTPS 或者用相對協議 -->
<img src="https://example.com/image.jpg" />
<img src="//example.com/image.jpg" />
<!-- 相對協議,自動使用當前頁面協議 -->

本地開發的 HTTPS

bash
# 用 mkcert 創建本地可信證書(不需要 --ignore-certificate-errors)
mkcert -install
mkcert localhost 127.0.0.1

# webpack devServer 配置
devServer: {
  https: {
    key: fs.readFileSync('./localhost-key.pem'),
    cert: fs.readFileSync('./localhost.pem')
  }
}

Secure Cookie

javascript
// 只在 HTTPS 下才發送這個 Cookie
document.cookie = "token=xxx; Secure; HttpOnly";

HSTS(HTTP 嚴格傳輸安全)

服務器告訴瀏覽器:以後都用 HTTPS 訪問我,不要用 HTTP

響應頭:
Strict-Transport-Security: max-age=31536000; includeSubDomains

瀏覽器會記住這個指令,即使用户輸入 http://example.com,也會自動改成 HTTPS。

證書類型

DV(域名驗證):只驗證域名所有權,幾分鐘申請,免費
  - Let's Encrypt 就是這種
  - 適合個人網站、博客

OV(組織驗證):驗證域名 + 組織信息,需要幾天
  - 顯示公司名,適合企業網站

EV(擴展驗證):最嚴格,需要 1-2 周
  - 瀏覽器地址欄顯示綠色公司名(現在大多數瀏覽器取消了綠色)
  - 銀行、大型電商用

小結

  • HTTPS = HTTP + TLS,提供加密、身份驗證、完整性保證
  • TLS 握手:非對稱加密交換密鑰,然後用對稱加密通信
  • 混合內容:HTTPS 頁面必須所有資源都是 HTTPS
  • 本地開發:用 mkcert 生成可信證書,避免證書警告
  • Let's Encrypt 提供免費 DV 證書,沒理由不上 HTTPS

MIT Licensed