紀錄工作經驗、相關知識,解決技術相關問題。

HTML, Javascript, Node JS, React, 工作雜談, 新手 Jamp Holes, 網站相關

HTTPOnly Cookie 怎麼設定?新手工程師常見 XSS 防禦實作

HTTPOnly Cookie 怎麼設定?新手工程師常見 XSS 防禦實作 特色圖片

在開發 Web 應用程式時,身分驗證憑證與敏感資料的存放安全性一直是工程師必須嚴格把關的環節。本文將深入探討 HTTPOnly Cookie 的核心防禦規則,說明如何透過後端設定阻絕跨站腳本攻擊(XSS),並釐清前端與後端的權責分工與常見實作盲點,幫助新手工程師建立正確的資安防護觀念。若想了解更多網站安全防護的基礎原理,亦可參考 XSS 跨站腳本攻擊三大類型與現代化防禦實作要點。

一、 什麼是 HTTPOnly 與核心防禦優勢

HTTPOnly 是一種設置在 Cookie 上的安全屬性。當 Cookie 被標記為 HTTPOnly 後,它僅能透過伺服器端的 HTTP 回應標頭傳輸與讀取,完全被禁止透過客戶端的 JavaScript 進行存取。這與一般預設的 Cookie 不同,後者若未特別限制,可以輕易地被瀏覽器端的腳本讀取或修改。

使用 HTTPOnly 可以顯著提升對跨站腳本攻擊(XSS)的防禦能力。當網站不幸遭受 XSS 攻擊,攻擊者成功注入惡意 JavaScript 腳本時,若使用一般的 Cookie(如存放在 localStorage 或非 HTTPOnly 的 Cookie 中),惡意腳本便能直接執行 document.cookie 2竊取使用者的 Session ID 或 Token。

由於開啟 HTTPOnly 的 Cookie 對於 JavaScript 來說是完全隱形且無法讀取的,這大大降低了攻擊者利用 XSS 漏洞直接劫持使用者帳號的風險。

二、 實作設定與前端權責分工

設定 HTTPOnly Cookie 必須在伺服器端進行。以 PHP 語言為例,您可以透過 setcookie 函式傳入對應的參數來設定:

setcookie("session_id", "secret_value", [
    'expires' => time() + 3600,
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

這段伺服器端程式碼確保了 Cookie 帶有 HttpOnly 屬性,從而阻絕前端指令碼的存取。

前端開發者注意事項:前端無法透過 JavaScript 設定 HTTPOnly

在現代前端開發中,工程師習慣使用各種 JavaScript 框架與 API 來處理資料。然而在資安架構上,前端 JavaScript 是絕對無法直接設定或修改帶有 HttpOnly 屬性的 Cookie 的。

因為 HTTPOnly 的核心目的正是為了「防止 JavaScript 訪問 Cookie」,如果允許前端程式碼隨意建立或更改這個屬性,將會破壞整體的防禦機制。因此,所有涉及 HttpOnly 的 Cookie 都必須由後端伺服器透過 HTTP 回應標頭(Response Headers)來寫入與控制。

三、 屬性測試驗證與安全組合實務

確認您的網站正確實施了 HTTPOnly 屬性是非常重要的一步。您可以透過以下兩種方式進行檢驗:

  1. 使用瀏覽器開發者工具 (F12):
    • 打開瀏覽器訪問您的網站,按下 F12 開啟開發者工具。
    • 切換至「網路」(Network)標籤,重新整理頁面以捕捉伺服器回應。
    • 在請求列表中點擊對應的頁面或 API 請求,查看「回應標頭」(Response Headers)。
    • 尋找 Set-Cookie 標頭,若該 Cookie 正確啟用保護,結尾處應會帶有 HttpOnly 標記。
    • 另外,您也可以切換至「應用程式」(Application)或「儲存空間」(Storage)標籤下的「Cookie」清單,若 HttpOnly 欄位打勾,即代表設定成功。
  2. 透過前端主控台(Console)驗證:
    • 在同一個分頁的開發者工具主控台中輸入 document.cookie。
    • 如果該 Cookie 已成功設定 HTTPOnly,它將不會出現在 document.cookie 的回傳字串中,藉此驗證前端腳本無法讀取該敏感資料。

結合 Secure 與 SameSite 屬性使用

為了進一步提升傳輸安全性,建議將 HTTPOnly 與 Secure 及 SameSite 標誌結合使用:

Set-Cookie: session_id=secret_value; Secure; HttpOnly; SameSite=Strict
  • Secure 屬性:確保該 Cookie 僅能在 HTTPS 加密連接中被傳輸,防止在不安全的 HTTP 網路上遭中間人攻擊(Man-in-the-Middle Attack)攔截。
  • SameSite 屬性:設定為 Strict 或 Lax,以有效防範跨站請求偽造(CSRF)攻擊。

四、 常見排查盲點與伺服器端除錯步驟

在實際將應用程式部署至正式環境(Production)後,工程師常會遇到「明明程式碼有寫 httponly => true,但 Cookie 卻沒有生效」的狀況。以下整理 3 個最常見的防禦失效盲點與對應的排查步驟:

1. 跨網域(Cross-Domain)或子網域 Cookie 設定錯誤

若前端與後端部署在不同的網域(例如前端在 app.example.com、後端 API 在 api.example.com),當後端在設定 Cookie 時若未正確指定 domain 參數,或者瀏覽器因現代瀏覽器的 SameSite 限制阻擋了第三方 Cookie,會導致瀏覽器直接拒絕寫入。

  • 排查方法:檢查伺服器回應的 Set-Cookie 標頭中的 Domain 與 Path 數值是否與當前請求網域相符。若涉及跨來源資源共用(CORS),後端 API 必須明確設定 Access-Control-Allow-Credentials: true,且前端請求(如 fetch 或 axios)必須帶上 withCredentials: true。

2. 開發環境與正式環境的 HTTPS 協定落差

當 Secure 屬性與 HttpOnly 同時啟用時,Cookie 僅允許在 HTTPS 連線中傳輸。如果在本地開發環境(Localhost)使用純 HTTP 連線進行測試,瀏覽器會直接忽略並丟棄該 Cookie,導致開發者誤以為程式碼寫錯。

  • 排查方法:在本地開發時,若無法使用 SSL 憑證,可暫時將 Secure 設為 false(僅限開發環境),或透過本地自簽憑證建立 HTTPS 測試環境,確保正式環境(Production)上線時一定要開啟 Secure。

3. 代理伺服器(Proxy / Load Balancer)攔截或覆寫標頭

在微服務或雲端架構中,請求常會經過 Nginx、Cloudflare 或負載平衡器。若代理伺服器的設定不當,可能會過濾掉自訂的 HTTP 回應標頭,或者在處理 SSL 終端(SSL Termination)時未正確傳遞協議狀態,導致後端判斷錯誤。

  • 排查方法:直接透過伺服器本機發送 curl 請求檢查原始回應標頭:
curl -I -X POST https://api.example.com/login

觀察回傳結果中是否完整包含 Set-Cookie: ...; HttpOnly; Secure,藉此判斷是後端程式碼漏掉參數,還是中介的代理伺服器將標頭過濾。

五、 限制與全方位防禦策略

雖然 HTTPOnly 提供了強大的 XSS 防禦保障,但在實際開發中仍須注意其侷限性與多層次防護的重要性:

  • 無法完全阻絕 CSRF 攻擊:HTTPOnly 能防止 Cookie 被 JavaScript 讀取,但當瀏覽器向伺服器發送請求時,瀏覽器仍會自動帶上這些 Cookie。因此,若未配合 SameSite 屬性或 CSRF Token,網站仍可能遭受跨站請求偽造攻擊。
  • 功能性取捨:若某些應用程式需要讓前端 JavaScript 讀取特定的使用者偏好設定(例如深色模式開關),則不能將該 Cookie 設為 HTTPOnly。因此,開發者必須妥善分類敏感憑證與一般狀態資料,進行安全層級的區隔。

除了強制啟用 HTTPOnly 之外,建構穩固的資安防線還需要多管齊下:

  1. 實施內容安全政策(CSP):透過嚴格的 CSP 標頭限制瀏覽器載入與執行不受信任的腳本,從源頭降低 XSS 發生機率。
  2. 落實輸入驗證與輸出編碼:在前後端交界處對所有使用者輸入進行嚴格過濾與跳脫處理,避免惡意腳本注入。
  3. 定期更新與依賴套件盤點:保持後端框架與前端依賴套件為最新版本,修補已知的安全漏洞。

總結

HTTPOnly 是一種實作成本低且效果顯著的網頁資安防禦機制。透過強制將身分驗證 Cookie 鎖定在伺服器端,能有效阻絕惡意 JavaScript 竊取憑證的風險。將 HTTPOnly 與 Secure、SameSite 等屬性結合,並落實現代化的網頁安全規範與全方位防護策略,才能為使用者打造更為穩固的瀏覽環境。

參考資料與延伸閱讀

發表迴響