2025 年 JWT 安全最佳實踐

10 min read
JWT, Security, Authentication

JWT 安全簡介

隨著我們進入 2025 年,JWT(JSON Web Token)仍然是現代網頁應用程式認證的基石。然而,不斷演變的安全威脅情勢需要開發者採用最新的最佳實踐來保護他們的應用程式。本綜合指南涵蓋了安全實施 JWT 認證的基本安全實踐。

1. 演算法選擇與密鑰管理

選擇正確的簽章演算法對 JWT 安全至關重要。到 2025 年,加密標準已經演進,某些演算法現在被認為更安全。

推薦的演算法

  • EdDSA (Ed25519):最新且最安全的選擇,提供出色的效能
  • ES256 (ECDSA with P-256):優異的安全性與效能平衡
  • RS256 (RSA with SHA-256):廣泛支援,適合遺留系統

要避免的演算法

  • 無 ("alg": "none"):絕不在生產環境中使用
  • HS256 與弱密鑰:如果使用,確保密鑰至少有 256 位元的熵

2. 權杖儲存策略

權杖的儲存位置顯著影響您應用程式的安全狀態。

儲存選項

儲存方法 安全等級 優點 缺點
記憶體 (變數) 最高 免於 XSS 和 CSRF 頁面重新整理時遺失
HttpOnly Cookie 免於 XSS 易受 CSRF 攻擊
SessionStorage 中等 標籤關閉時清除 易受 XSS 攻擊
LocalStorage 持久儲存 易受 XSS 攻擊

3. 權杖過期與重新整理

實施適當的權杖生命週期管理對於維持安全至關重要。

// 建議的權杖配置
const tokenConfig = {
  accessToken: {
    expiresIn: '15m',  // 短期存取權杖
    algorithm: 'ES256'
  },
  refreshToken: {
    expiresIn: '7d',   // 較長期的重新整理權杖
    algorithm: 'ES256',
    rotation: true     // 啟用權杖輪換
  }
};

4. 實施權杖輪換

權杖輪換透過在每次使用時發行新的重新整理權杖來增加額外的安全層。

async function rotateRefreshToken(oldRefreshToken) {
  // 驗證舊的重新整理權杖
  const decoded = await verifyRefreshToken(oldRefreshToken);

  // 使舊權杖失效
  await revokeToken(oldRefreshToken);

  // 產生新權杖
  const newAccessToken = generateAccessToken(decoded.userId);
  const newRefreshToken = generateRefreshToken(decoded.userId);

  return {
    accessToken: newAccessToken,
    refreshToken: newRefreshToken
  };
}

5. 防範常見攻擊

XSS (跨站指令碼攻擊) 防護

  • 實施內容安全政策 (CSP)
  • 清理所有使用者輸入
  • 使用 HttpOnly cookies 儲存敏感權杖

CSRF (跨站請求偽造) 防護

  • 實施雙重提交 cookie
  • 對狀態更改操作使用 CSRF 權杖
  • 驗證 Origin 和 Referer 標頭

6. 權杖撤銷策略

儘管 JWT 是無狀態的,但實施撤銷機制對於安全至關重要。

撤銷方法

  • 黑名單:維護已撤銷權杖的清單
  • 版本控制:在使用者記錄中包含版本號
  • 短期權杖:使用非常短的過期時間

7. 監控與稽核

實施全面的記錄和監控以檢測可疑活動。

// 稽核記錄範例
function logAuthEvent(event) {
  console.log({
    timestamp: new Date().toISOString(),
    event: event.type,
    userId: event.userId,
    ip: event.ip,
    userAgent: event.userAgent,
    success: event.success
  });
}

結論

JWT 安全需要仔細考慮多個因素。透過遵循這些 2025 年最佳實踐,您可以建立強大且安全的認證系統。記住,安全不是一次性的實施,而是一個持續的過程,需要定期審查和更新。

Share this article

Back to Blog