微服務架構將單體應用拆分為眾多獨立服務後,安全認證機制面臨根本性的轉變:傳統基於 Session-Cookie 的有狀態認證不再適用,取而代之的是以 Token 為核心的授權框架。本章涵蓋以下主題:
- 微服務安全挑戰
- OAuth2 核心概念與四種授權流程
- JWT 機制
- OpenID Connect
- 生產環境的 Token 校驗架構方案
微服務安全挑戰#
從單體到微服務的安全演進#
在傳統單體架構中,安全認證相對簡單:使用者登入後,伺服器建立 Session,瀏覽器透過 Cookie 維持狀態。然而在微服務架構下,這套模式面臨三大核心挑戰:
| 挑戰領域 | 問題描述 |
|---|---|
| 開放系統授權 | 第三方應用需要存取受保護資源(如聯合登入、開放 API),傳統的帳密共享方式極不安全 |
| 多樣化用戶端 | 接入端不再僅限於瀏覽器,還包括 SPA、Mobile App、伺服器端應用等多種形態 |
| 服務間認證 | 服務拆分後,服務與服務之間也需要認證與鑑權,Session 機制無法跨服務共享 |
微服務環境下,安全機制從「使用者名稱/密碼 + Session」轉變為依賴獨立的 Authorization Server(授權伺服器),核心技術從有狀態 Session 轉變為 無狀態的 Token 授權機制。
傳統授權方式的侷限#
在 OAuth2 出現之前,讓第三方應用存取受保護資源的方式都存在明顯缺陷:
- 帳密複製:將使用者帳號密碼直接交給第三方,權限過大且無法保證不被濫用
- 通用開發者金鑰:合作夥伴共享萬能金鑰,一旦洩露所有資源都面臨風險
- 特殊令牌:方向正確但缺乏標準化,令牌的頒發、管理、吊銷都無統一規範
將使用者帳號密碼直接交給不受信的第三方應用,是開放系統授權中必須避免的反模式。OAuth2 正是為了解決這個問題而誕生。
OAuth2 核心概念#
定義與本質#
OAuth 2.0 是一個用於 REST API 的代理授權框架(Delegated Authorization Framework),定義於 RFC 6749。其核心在於 Token(令牌)——在不暴露使用者帳號密碼的前提下,使第三方應用能夠獲取對使用者資料的有限存取權限。
核心概念比喻:僕從鑰匙(Valet Key)
OAuth2 的 Token 可比喻為高級轎車的僕從鑰匙:
- 常規鑰匙(Master Key):擁有完全權限(相當於使用者帳號密碼)
- 僕從鑰匙(Token):只能用來開車(有限權限),不能打開後備箱(保護隱私),可能限制行駛里程(Scope/有效期限制)
你不需要把所有權限都交給泊車員,只需給他一把「剛好夠用」的鑰匙。
四大核心角色#
flowchart TB
RO["Resource Owner<br/>資源擁有者(使用者)"]
C["Client<br/>客戶應用(第三方)"]
AS["Authorization Server<br/>授權伺服器"]
RS["Resource Server<br/>資源伺服器"]
RO -->|授權同意| AS
C -->|1. 請求授權| AS
AS -->|2. 頒發 Token| C
C -->|3. 攜帶 Token 存取| RS
RS -->|4. 校驗 Token 後回傳資料| C
style AS fill:#fff3e0
style RS fill:#e8f5e9| 角色 | 說明 | 範例 |
|---|---|---|
| Resource Owner | 資料的擁有者(使用者本人) | 你在雲端硬碟上的照片,你是擁有者 |
| Client | 需要存取受保護資源的第三方應用 | 雲端沖印服務 |
| Authorization Server | 負責驗證身分、頒發與管理令牌 | 授權伺服器 |
| Resource Server | 託管受保護資源的伺服器 | Google Photos API |
關鍵術語#
| 術語 | 說明 |
|---|---|
| Client Credentials | Client ID + Client Secret,用戶端在授權伺服器註冊後的「身分證」 |
| Access Token | 短期有效的存取憑證,用於直接存取受保護資源 |
| Refresh Token | 長期有效的重新整理憑證,用於在 Access Token 過期後換取新 Token |
| Scope | 權限的細粒度控制,如「只讀」、「讀寫」等 |
| Authorization Code | 中間狀態的臨時憑證,用於換取 Access Token |
令牌的兩種形態#
| 類型 | 別名 | 特性 | 校驗方式 |
|---|---|---|---|
| 透明令牌 | Reference Token(引用令牌) | 隨機字串,不包含業務資訊 | 必須回調授權伺服器校驗 |
| 自包含令牌 | Value Token(值令牌) | 內部攜帶完整資訊(如 JWT) | 可在本地校驗 |
四種授權流程#
授權碼模式(Authorization Code Flow)#
最複雜、最安全,也是應用最廣泛的模式。引入「授權碼」中間層,避免 Access Token 直接暴露在瀏覽器端。
sequenceDiagram
participant U as 使用者(瀏覽器)
participant C as 用戶端(後端)
participant AS as 授權伺服器
U->>C: 1. 發起請求
C->>U: 2. 重定向至授權伺服器
U->>AS: 3. 登入認證 + 授權同意
AS->>U: 4. 重定向回 Client(攜帶授權碼)
U->>C: 5. 傳遞授權碼
C->>AS: 6. 後端渠道:用授權碼換取 Token
AS->>C: 7. 返回 Access Token(+ Refresh Token)- 適用場景:有後端伺服器的 Web 應用
- 安全性:最高,Token 不經過瀏覽器,僅在 Client 後端與授權伺服器間流轉
簡化模式(Implicit Flow)#
省去授權碼交換,Access Token 直接通過 URL Fragment 返回給瀏覽器。
- 適用場景:無後端伺服器的 SPA
- 安全性:較弱,Token 暴露在瀏覽器端
Implicit Flow 在 OAuth 2.1 草案中已被不推薦使用。現代最佳實踐傾向於使用**授權碼模式 + PKCE(Proof Key for Code Exchange)**來取代簡化模式。
密碼模式(Resource Owner Password Credentials Flow)#
使用者直接將帳號密碼提供給用戶端,用戶端再向授權伺服器換取 Token。
- 適用場景:僅限高度信任的第一方應用(如公司自家 App 存取自家 API)
- 安全性:使用者密碼暴露給用戶端,僅適用於同一信任域
用戶端模式(Client Credentials Flow)#
最簡單的模式,完全不需要使用者參與。用戶端直接以自身的 Client ID 和 Secret 獲取 Token。
- 適用場景:機器對機器(M2M)通訊,如微服務間呼叫、CI/CD 工具
- 安全性:Token 代表用戶端自身的權限,而非某個具體使用者
選型決策樹#
flowchart TD
START["開始選型"] --> Q1{"令牌擁有者是誰?"}
Q1 -->|機器| CC["用戶端模式<br/>Client Credentials"]
Q1 -->|使用者| Q2{"用戶端類型?"}
Q2 -->|Web 伺服器端應用| AC1["授權碼模式<br/>Authorization Code"]
Q2 -->|原生 App / SPA| Q3{"開發方關係?"}
Q3 -->|第一方(內部開發)| PW["密碼模式<br/>Password Credentials"]
Q3 -->|第三方| Q4{"應用類型?"}
Q4 -->|原生 App| AC2["授權碼模式 + PKCE"]
Q4 -->|SPA| AC3["授權碼模式 + PKCE<br/>(取代 Implicit)"]
style CC fill:#e8f5e9
style AC1 fill:#e3f2fd
style AC2 fill:#e3f2fd
style AC3 fill:#e3f2fd
style PW fill:#fff3e0快速選型原則:
- 有後端的 Web 應用 -> 授權碼模式
- SPA 或 Mobile App -> 授權碼模式 + PKCE
- 內部信任的第一方應用 -> 密碼模式(但應逐步過渡到授權碼模式)
- 服務間呼叫 / 排程任務 -> 用戶端模式
前端渠道 vs 後端渠道#
理解授權流程的關鍵在於區分兩種通訊渠道:
| 渠道 | 參與角色 | 特徵 |
|---|---|---|
| 前端渠道(Front-channel) | 使用者、用戶端、授權伺服器 | 透過瀏覽器重定向,使用者可見 |
| 後端渠道(Back-channel) | 用戶端、授權伺服器、資源伺服器 | 伺服器對伺服器通訊,使用者不可見 |
授權碼模式之所以最安全,正是因為 Token 的交換發生在後端渠道。
OAuth2 安全風險防護#
OAuth2 協議的初衷是解決授權與安全問題,但在實際實作中若設定不當,仍存在嚴重的安全風險。以下是架構師在設計 OAuth2 系統時必須落實的防護措施。
核心防護原則#
| 防護措施 | 說明 |
|---|---|
| 強制使用 HTTPS | Client、Authorization Server、Resource Server 之間的通訊必須全程加密,防止 Token 在傳輸過程中被竊聽 |
| 保護 Client Secret | 必須盡最大努力防止用戶端密碼洩露。對於無法保守秘密的公開用戶端(SPA、Mobile),應使用 PKCE 替代 |
| 嚴格驗證 Redirect URI | 註冊 Client 時必須明確指定合法的重定向 URL,授權伺服器收到請求時必須嚴格比對,防止授權碼或 Token 被重定向至惡意站點 |
| 強制使用 state 參數 | 防止 CSRF 攻擊與 Token 劫持的關鍵手段(詳見下方) |
| Token 綁定 | 針對進階攻擊場景,可將 Token 請求與用戶端的授權方式進行綁定,減輕 Token 被劫持的風險 |
CSRF 攻擊與 state 參數防禦#
OAuth2 流程中最典型的安全風險是跨站點請求偽造(CSRF)。攻擊者可利用自己的合法授權碼誘導受害者完成授權流程,導致受害者的操作(如存款、上傳資料)實際上綁定到攻擊者的帳號。
sequenceDiagram
participant A as 攻擊者
participant AS as 授權伺服器
participant V as 受害者(已登入)
participant C as 用戶端應用
A->>AS: 1. 以自己帳號登入並授權
AS->>A: 2. 返回授權碼(綁定攻擊者身分)
Note over A: 3. 攔截授權碼,不讓流程完成
A->>V: 4. 發送偽造回調連結(含攻擊者授權碼)
V->>C: 5. 點擊連結,觸發授權碼交換
C->>AS: 6. 用攻擊者的授權碼換取 Token
AS->>C: 7. 返回攻擊者的 Token
Note over C: 受害者的後續操作<br/>都綁定了攻擊者身分state 參數的防禦機制:
- 用戶端在發起授權請求時生成一個隨機的
state值,並儲存於 Session 中 - 授權伺服器在回調時原封不動地返回
state值 - 用戶端校驗回傳的
state是否與 Session 中的一致 - 攻擊者構造的偽造連結因缺少正確的
state,將被用戶端拒絕
缺乏
state參數校驗的用戶端無法區分授權碼是由使用者自己發起的,還是由外部惡意連結注入的。務必確保所有 OAuth2 用戶端在請求授權碼時帶上state參數,並在回調時進行嚴格校驗。
JWT(JSON Web Token)#
結構解析#
JWT 是一種標準化的自包含令牌,由三個部分組成,以 . 連接:
Header.Claims.Signatureflowchart LR
subgraph JWT["JWT 結構"]
H["Header<br/>演算法 + 類型<br/><code>alg: HS256</code>"]
C["Claims<br/>使用者資訊 + 後設資料<br/><code>sub, exp, aud, iss</code>"]
S["Signature<br/>防篡改簽章<br/><code>HMAC(H+C, secret)</code>"]
end
H --- C --- S
style H fill:#e3f2fd
style C fill:#fff3e0
style S fill:#e8f5e9Header(頭部):
typ:令牌類型(JWT)alg:簽名演算法(如 HS256、RS256)
Claims(宣告/載荷):
| 欄位 | 全稱 | 說明 |
|---|---|---|
iss | Issuer | 頒發者 |
exp | Expiration Time | 過期時間 |
aud | Audience | 預期接收者 |
sub | Subject | 主題(如使用者 ID) |
iat | Issued At | 頒發時間 |
Signature(簽名):
- 使用密鑰對 Header + Claims 進行簽名,確保內容未被篡改
- 只有持有密鑰的授權伺服器才能簽發有效 Token
簽名是 JWT 安全性的基石。沒有簽名,任何人都可以偽造 JSON 宣告自己擁有管理員權限。資源伺服器在驗證 JWT 時,首先驗簽,再檢查
aud是否匹配、exp是否過期。
JWT 的校驗邏輯#
資源伺服器收到 JWT 後的處理流程:
- 驗證簽名:確認由信任的授權伺服器頒發
- 檢查過期時間:確認
exp未過期 - 檢查 Audience:確認
aud與當前服務匹配 - 提取權限資訊:從 Claims 中讀取使用者角色與 Scope
JWT 的核心優勢在於去中心化校驗。資源伺服器可以在本地完成所有合法性校驗,完全不需要與授權伺服器進行網路通訊,這在高併發場景下具有顯著的效能優勢。
Reference Token vs JWT 對比#
| 比較維度 | Reference Token | JWT(Self-contained Token) |
|---|---|---|
| 內容 | 隨機字串,不含資訊 | 包含完整使用者與權限資訊 |
| 校驗方式 | 回調授權伺服器 Introspection 端點 | 本地驗簽即可 |
| 效能 | 每次校驗需網路請求 | 本地校驗,無網路開銷 |
| 即時吊銷 | 支援(授權伺服器可直接失效) | 不支援(須等待自然過期) |
| Token 大小 | 小 | 較大(攜帶完整資訊) |
OpenID Connect(OIDC)#
OIDC 與 OAuth2 的關係#
OAuth2 本質上是一個**授權(Authorization)**協議,不負責驗證使用者身分。OpenID Connect 在 OAuth2 之上增加了標準化的身份認證層。
flowchart TB
subgraph Stack["協議堆疊"]
direction TB
OIDC["OpenID Connect<br/>身份認證 + ID Token + UserInfo"]
OAuth["OAuth 2.0<br/>授權流程 + Access Token"]
JWT_Layer["JWT / JWS / JWE<br/>資料格式 + 簽名 + 加密"]
end
OIDC --> OAuth --> JWT_Layer
style OIDC fill:#e3f2fd
style OAuth fill:#fff3e0
style JWT_Layer fill:#e8f5e9OIDC = OAuth 2.0 + Identity + Authentication。它利用 OAuth2 作為底層基礎,明確增加了身份認證功能。
OIDC 的關鍵特徵#
| 特徵 | 說明 |
|---|---|
| ID Token | 新增的令牌類型,經過簽名,專門包含使用者身份認證資訊 |
| UserInfo Endpoint | 標準化端點,可用 Token 存取以獲取額外使用者資訊 |
| 標準化 Scopes/Claims | profile、email、phone 等欄位已被標準化 |
| 會話管理 | 支援 SSO(單點登入)場景,統一的會話管理與吊銷 |
| 用戶端發現 | 簡化用戶端組態流程 |
OAuth2 vs OIDC 的核心差異
| 比較維度 | OAuth 2.0 | OpenID Connect |
|---|---|---|
| 定位 | 授權框架(Authorization) | 身份認證層(Authentication) |
| 回答的問題 | 「這個應用能做什麼?」 | 「這個使用者是誰?」 |
| 核心 Token | Access Token | Access Token + ID Token |
| 使用者資訊 | 不提供標準化方式 | UserInfo Endpoint |
| 典型場景 | API 授權存取 | 聯合登入、SSO |
生產環境 Token 校驗架構#
在真實的企業微服務架構中,授權伺服器需要與 API 閘道、內部微服務群緊密協作。以下是三種主流的 Token 校驗與傳遞方案。
方案一:閘道集中校驗與 Token 交換#
核心思想是將「有狀態」與「無狀態」的界線劃分在 API 閘道層。
sequenceDiagram
participant C as 用戶端
participant GW as API 閘道
participant AS as 授權伺服器
participant MS as 微服務
C->>GW: 1. 攜帶 Access Token 請求
GW->>AS: 2. 校驗 Access Token
AS->>GW: 3. 校驗通過 + 使用者資訊
Note over GW: 4. 將 Access Token<br/>交換為 JWT
GW->>MS: 5. 攜帶 JWT 轉發請求
Note over MS: 6. 本地驗簽 JWT<br/>無需再訪問授權伺服器
MS->>GW: 7. 返回業務資料
GW->>C: 8. 回傳結果特點:
- 閘道負責集中校驗,將不透明的 Access Token 交換為自包含的 JWT
- 後端微服務進行無狀態的本地 JWT 校驗,無需再訪問授權伺服器
- 職責清晰:閘道外是有狀態的 Access Token,閘道內是無狀態的 JWT
方案二:全鏈路無狀態 JWT#
追求極致效能,所有校驗在本地完成。
sequenceDiagram
participant C as 用戶端
participant GW as API 閘道
participant MS as 微服務
C->>GW: 1. 攜帶加密 JWT
Note over GW: 2. 本地解密 + 驗簽<br/>(無需遠端請求)
GW->>MS: 3. 轉發解密後的 JWT
Note over MS: 4. 本地解碼 + 權限填充
MS->>GW: 5. 返回業務資料
GW->>C: 6. 回傳結果特點:
- 用戶端直接持有加密 JWT,閘道與微服務均在本地校驗
- 極大降低授權伺服器壓力
全鏈路 JWT 方案最大的問題在於無法即時吊銷。若 Token 被盜或發現惡意使用者,因為閘道不回調授權伺服器,無法集中指令讓 Token 失效,只能等待 JWT 自然過期。若採用此方案,務必將 JWT 過期時間設定得非常短。
方案三:閘道 + Redis 快取(推薦)#
在方案一的基礎上引入快取層,兼顧安全性與效能。
sequenceDiagram
participant C as 用戶端
participant GW as API 閘道
participant Redis as Redis 快取
participant AS as 授權伺服器
participant MS as 微服務
Note over AS,Redis: 預先:頒發 Token 時<br/>同步寫入 Redis
AS->>Redis: Token -> JWT 映射
C->>GW: 1. 攜帶 Access Token 請求
GW->>Redis: 2. 查詢 Token 對應的 JWT
Redis->>GW: 3. 返回 JWT
GW->>MS: 4. 攜帶 JWT 轉發請求
Note over MS: 5. 本地驗簽 JWT
MS->>GW: 6. 返回業務資料
GW->>C: 7. 回傳結果特點:
- 授權伺服器頒發 Token 時,將 Access Token 與對應 JWT 的映射寫入 Redis
- 閘道直接查詢 Redis 完成校驗與 Token 轉換,不再直接請求授權伺服器
- 支援即時吊銷(從 Redis 刪除 Token 即可)
此方案是目前生產環境中最常見的架構選擇。Redis 的高讀取效能完美契合高頻 Token 校驗場景,同時保留了閘道集中管控與後端無狀態的優點,解決了頻繁呼叫授權伺服器的效能瓶頸。
三種方案對比#
| 比較維度 | 方案一:閘道集中校驗 | 方案二:全鏈路 JWT | 方案三:閘道 + Redis |
|---|---|---|---|
| 授權伺服器壓力 | 高(每次請求需校驗) | 極低(無需校驗) | 低(Redis 承擔) |
| 即時吊銷能力 | 支援 | 不支援 | 支援 |
| 後端微服務複雜度 | 低(本地驗簽) | 低(本地驗簽) | 低(本地驗簽) |
| 整體效能 | 中等 | 最高 | 高 |
| 推薦程度 | 適用於低流量場景 | 適用於對吊銷無強需求場景 | 生產環境推薦 |
生產部署最佳實踐#
授權伺服器監控#
授權伺服器是微服務安全的核心,必須建立完善的監控體系:
業務指標:
| 指標類別 | 監控項目 |
|---|---|
| 認證與授權 | 登入次數、授權請求次數 |
| 令牌生命週期 | 頒發數量、活躍令牌總數、吊銷次數 |
| 校驗頻率 | Token Introspection 呼叫 QPS |
| 用戶端統計 | 已註冊 OAuth Client 數量 |
關鍵 API 效能監控:
| 端點 | 重要性 | 說明 |
|---|---|---|
/oauth/authorize | 高 | 授權介面 |
/oauth/token | 高 | 令牌頒發介面 |
/oauth/introspect | 極高 | 令牌校驗介面(最高頻) |
/oauth/revoke | 高 | 令牌吊銷介面 |
高可用與效能最佳化#
在高併發場景下,如果每個請求的 Token 校驗都直接查詢資料庫,關聯式資料庫通常無法承受。務必引入 Redis 等快取層來處理令牌校驗與存取。
- 快取策略:引入 Redis 快取 Token 與 JWT 的映射關係,大幅提升校驗吞吐量
- 水平擴容:授權伺服器設計為無狀態或支援叢集模式,部署多台實例實現負載均衡
- 單點防護:避免授權伺服器成為單點故障,確保單台故障不影響整體認證服務
安全設計原則#
微服務安全設計檢查清單
| 原則 | 說明 |
|---|---|
| Token 短時效 | Access Token 有效期設定為較短(如 1 小時),降低洩露風險 |
| Refresh Token 機制 | 透過長效 Refresh Token 換取新的 Access Token,兼顧安全與體驗 |
| Scope 最小權限 | 為每個用戶端設定最小必要的存取範圍 |
| HTTPS 強制 | 所有 Token 傳輸必須透過 HTTPS,防止中間人攻擊 |
| CSRF 防護 | 所有授權請求強制使用 state 參數,回調時嚴格校驗 |
| Redirect URI 驗證 | 授權伺服器嚴格比對註冊的 Redirect URI,禁止開放式重定向 |
| Client Secret 保護 | 妥善保管用戶端密碼,公開用戶端使用 PKCE 替代 |
| 密鑰輪換 | 定期輪換 JWT 簽名密鑰,降低密鑰洩露的影響 |
| 閘道集中認證 | 在 API 閘道層統一處理認證,後端微服務專注業務邏輯 |
| 即時吊銷機制 | 採用 Redis 方案確保可以即時讓 Token 失效 |