對於web系統而言,因爲HTTP協議無狀態的特性,用戶登陸時須要服務端生成通行證返回給瀏覽器。瀏覽器保存該通行證並在接下來的請求中攜帶該通行證。一般來說,web系統使用http cookie來保存和傳輸通行證。本文介紹http cookie的原理、特性、並分析用其保存通行證可能遇到的安全問題。javascript
本文假設使用cookie的客戶端是瀏覽器,雖然還有其它客戶端也使用cookie,但普通用戶使用更多的仍是瀏覽器。html
一種Http狀態管理機制,最先由Lou Montulli發明於1994年,最新的標準是2011年發佈的RFC 6265 - HTTP State Management Mechanism。由於保存信息到客戶端的本質,也有系統用cookie來緩存信息,但這並非Http Cookie的主要用途。java
Cookie既指整個狀態保存機制,也指用戶保存狀態的數據自己,由String類型的name和value以及若干屬性組成。追根溯源,其名字來源於fortune cookie,一種內含寫有幸運文字小紙條的餅乾。git
Cookie由服務端生成,保存在瀏覽器。經過兩個Http Header:Set-Cookie和Cookie進行傳輸。Set-Cookie Header用於服務端傳輸登陸通行證等cookie鍵值對及屬性給瀏覽器,瀏覽器收到並驗證合法性後會作相應保存。Cookie Header用於瀏覽器傳遞cookie鍵值對給服務端,服務端依次來鑑別用戶身份等狀態信息。github
RFC6265定義了Cookie的一些屬性,包含Expires、Max-Age、Domain、Path、Secure、HttpOnly。也有一些還沒定義到RFC,但已經實際應用的屬性,好比SameSite。Cookie寫時有屬性讀時無屬性,屬性僅在設置時即Set-Cookie Header中指定,瀏覽器依此來決定是否接受該cookie如何使用該cookie,而一旦瀏覽器決定了將cookie放到Cookie Header中傳遞到服務端,那麼瀏覽器不會傳遞更多的的信息到服務端,只會傳遞鍵值對name和value。web
不少瀏覽器會提供讀Cookie和寫Cookie的api給運行在其上Javascript腳本使用,一般的api是操做docment.cookie:算法
document.cookie=「SID=31d4d; domain=example.com; path=/;」;
Domain、Path、Name三者惟一肯定一個cookie。其它屬性僅用做讀寫時的權限控制,不做爲cookie標識。在瀏覽器在使用cookie時:sql
這相比瀏覽器同源策略更加寬鬆,帶來不少安全問題。chrome
Domain是向上通配的:數據庫
Set-Cookie: sid1=a; domain=example.com; path=/; 接受 Set-Cookie: sid2=b; domain=www.example.com; path=/; 接受 Set-Cookie: sid3=c; domain=pay.example.com; path=/; 拒絕
訪問pay.example.com Cookie: sid1=a 訪問www.example.com Cookie: sid1=a; sid2=b;
不少系統寫cookie,習慣在域名前加一個點,寫成.example.com,覺得這麼寫纔是通配的,其實這個點是多餘的,沒有必要的。
Path是向下通配的:
Set‐Cookie: sid1=a; domain=example.com; path=/; Set‐Cookie: sid2=b; domain=example.com; path=/test/;
訪問http://example.com/ Cookie: sid1=a; 訪問http://example.com/test/ Cookie: sid1=a; sid2=b
這兩個屬性指定cookie有效期。不指定有效期時,cookie默認爲當前session有效,當前session有效指關閉瀏覽器時cookie失效。
Cookie的有效期過長可能致使通行證泄露。好比用戶使用了公用電腦,關閉瀏覽器時,沒有點擊註銷。這樣Cookie就留存在這臺電腦上,其它人只需打開瀏覽器便可獲取其在網站上的cookie。
通常保存通行證的cookie應該設置爲session有效的cookie,並在用戶選擇記住登陸狀態時,提醒用戶,不要再公用電腦上作這樣的勾選。
HTTP明文傳輸數據的特性,使得攻擊者可從網路上抓包獲取Cookie。
解決方案:
假如網站存在XSS漏洞,那麼惡意JS可直接讀取Cookie中的通行證。能夠經過指定Cookie的HttpOnly屬性。對於指定了HttpOnly的Cookie,瀏覽器會拒絕JS讀寫。
XSS仍有可能利用服務端漏洞獲取cookie:
- 服務端有可能在請求的正常響應中包含通行證。不要笑,這真的有,尤爲如今不少公司app和web共用一套後臺;
- 服務端可能有漏洞致使cookie包含在請求響應中,從而被竊取。好比:Apache CEV-2012-005
因此HttpOnly不是銀彈,XSS也有不少其它的危害。但至少,HttpOnly能夠避免通行證在瀏覽器被JS直接讀取。
保存了通行證的cookie由於是HttpOnly,因此XSS沒法讀取。但XSS仍是能夠寫Cookie,因爲domain、path、name三者才惟一標識一個cookie,XSS能夠寫一個跟通行證cookie name相同,但domain或path不一樣的cookie。
這樣當瀏覽器發送請求給服務端時,服務端就會收到兩個相同name的cookie。由於cookie讀時無屬性,因此服務端無從判斷哪個纔是正確的。這樣會使用哪個cookie,就要看具體web server的實現,多是第一個也多是第二個。
這樣經過寫cookie,XSS能夠輕易地使已登陸用戶退登。
惡意JS可針對特定的域名和path寫入一個攻擊者的cookie通行證。好比針對某電商網站的餘額充值domain和path,寫入攻擊者的通行證。該攻擊者cookie在用戶正常購物的請求中不會帶出,當用戶充值時會帶出,從而使用戶充值到了攻擊者的帳號。
對於HTTP,公共wifi可劫持用戶全部的流量,竊取cookie通行證天然不在話下。
對於HTTPS,由於能夠在DNS上作手腳,能夠在路由器上截取和篡改流量,在公共wifi上很容易誘導用戶發出到網站的HTTP請求,幾遍該網站是全站HTTPS也是如此。
所以,對於XSS寫cookie的危害,公共wifi都能作到。並且能力更強,危害更大。
對於設置了secure屬性的cookie,雖然不會在http請求中帶出,但卻可被http請求的Cookie設置覆蓋。所以,設置了secure也不安全。
Although seemingly useful for protecting cookies from active network
attackers, the Secure attribute protects only the cookie's
confidentiality. An active network attacker can overwrite Secure
cookies from an insecure channel, disrupting their integrity
---- from RFC 6265
公共wifi的危害,有一個關鍵點,就是誘導用戶對指定網站發出HTTP請求。這一點經過HSTS - HTTP Strict Transport Security能夠避免。
HSTS經過設置strict‐transport‐security頭,來告知瀏覽器,對當前域名以及全部子域名,都只使用HTTPS訪問。
讓瀏覽器對當前域名及子域名,強制進行HTTPS訪問: strict‐transport‐security: max‐age=15552000;includeSubDomains;
但HSTS在現實中難以被利用。由於:
因此,真正全站部署HSTS的網站,少之又少。
o At least 4096 bytes per cookie (as measured by the sum of the
length of the cookie's name, value, and attributes).
o At least 50 cookies per domain.
o At least 3000 cookies total.
---- From RFC 6265
設置超大cookie,超多cookie,都是典型的攻擊手段。上文提到的Apache CEV-2012-005漏洞,便是利用了Apache對Cookie大小的限制。
在訪問惡意網站時,網站的頁面代碼中,可能包含到你銀行帳號或是其它什麼帳號的請求。因爲這時瀏覽器會自動帶出到相應域名的cookie,因此用戶的登陸通行證,就很容易被惡意網站偷用。
這個問題,能夠經過設置Cookie的SameSite屬性來解決。設置了SameSite屬性的cookie,只會在當前正在訪問(瀏覽器地址欄)的域名與cookie的domain可匹配時,纔會帶出。
以下截圖,是Chrome支持的cookie屬性:
有人會說,cookie不就是存放在硬盤,我直接從硬盤上竊取不能夠嗎?
答案是能夠。好比Chrome的cookie就存放在目錄:C:\Users<username>\AppData\Local\Google\Chrome\User Data\Default\下,是一個sqllite的數據庫文件,雖然cookie內容都進行了加密,但也是能夠破解的。
只是,當你攻破一個用戶的電腦,破解了chrome的加密算法,最終只是竊取到了一個用戶的登陸憑證而已。這種攻擊,性價比很低。
Github推出的github pages功能,一開始的時候使用的是github.com主站域名,後來由於上面提到的cookie安全問題,不得不爲github pages單獨啓動了github.io域名。
具體可看Github的官方blog,裏面提到了上面部分的cookie安全問題。blog連接:Yummy Cookies across Domains