cookie 概念
cookie 的英文意思有兩個一個是餅干效床,另一個是堅強的人。將數(shù)據(jù)信息命名為 cookie 的原因可以看這個
cookie 是服務(wù)器產(chǎn)生的數(shù)據(jù)信息(部分 cookie 也可能是由網(wǎng)頁 javascript 代碼注入)迂猴,存儲在瀏覽器中,常用來存儲用戶信息等背伴。
cookie 的存儲是通過一個字符串來完成的
"name=xxx;age=123"
既然 cookie 這個概念代表一部分?jǐn)?shù)據(jù)沸毁,那么下面我們將討論數(shù)據(jù)的來源、存儲以及應(yīng)用
cookie 的來源
- 服務(wù)器: 服務(wù)器可以通過設(shè)置 cookie 直接在瀏覽器中存儲相關(guān)數(shù)據(jù)
- javascript 可以新增傻寂、修改(部分 cookie)
cookie 的存儲
cookie 的存儲以及修改會涉及到 cookie 的配置問題息尺,下面對相關(guān)配置進(jìn)行總結(jié)
Expires
cookie 的最長有效時間,如果沒有設(shè)置這個屬性疾掰,瀏覽器關(guān)閉時 cookie 會被清除
Max-Age
經(jīng)過多少秒 cookie 過期搂誉,如果也存在 Expires 屬性,已 Max-Age 為準(zhǔn)静檬。也就是說 Max-Age 比 Expires 權(quán)重要高炭懊。
Domain
域名規(guī)定 cookie 可被發(fā)送的域名,如果不設(shè)置,默認(rèn)為當(dāng)前頁面的 host拂檩。如果設(shè)置了侮腹,子域名都是允許的。
比如 Domain = a.com稻励,那么域名 b.a.com 就是允許訪問這個 cookie 的父阻。
Path
頁面路徑和域名的設(shè)置原理基本一致,/ 字符被認(rèn)為是文件名的分隔符望抽。 如果你設(shè)定 Path=/docs 那么
- /docs
- /docs/web
都是可以訪問 cookie 的
Secure
設(shè)定之后加矛,只有是 http 協(xié)議才能訪問這個 cookie
HttpOnly
設(shè)置后 javascript 無法訪問這個 cookie
SameSite
- Strict 嚴(yán)格模式,禁止所有跨域的 cookie 發(fā)送
- None 完全允許煤篙,允許所有跨域的 cookie 發(fā)送
- Lax 寬松模式斟览,允許部分跨域 cookie 發(fā)送
cookie 的跨域使用
在瀏覽器存儲由接口返回的 cookie 后,此后的每一個請求辑奈,只要是滿足 cookie 的設(shè)置苛茂,cookie 都會被 http 請求攜帶。
我在這一部分會重點對跨域請求的 cookie 攜帶做一個總結(jié)身害。
cors 接口跨域請求
對于cookie 的使用味悄,一個主動地使用場景就是請求跨域的接口草戈,如果這個跨域的接口需要攜帶 cookie 有以下兩個方面需要考慮
withCredentials
跨域請求接口塌鸯,瀏覽器默認(rèn)是不會攜帶 cookie 的
在調(diào)用接口后,我們需要指定一個屬性 withCredentials
const invocation = new XMLHttpRequest();
const url = 'https://bar.other/resources/credentialed-content/';
function callOtherDomain() {
if (invocation) {
invocation.open('GET', url, true);
// 在指定這個屬性后唐片,接口調(diào)用才有可能攜帶 cookie
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
cors 跨域請求分兩種一種是簡單請求,一種是復(fù)雜請求 (不理解請自行baidu)
- 如果是簡單請求,當(dāng)設(shè)置此屬性后,跨域請求會直接攜帶相關(guān)的 cookie
- 復(fù)雜請求會等待 option 預(yù)請求回來后丙猬,才會攜帶相關(guān) cookie
SameSite
SameSite 屬性是瀏覽器除了 withCredentials 判斷跨域請求是否可以攜帶此 cookie 的另一個機制涨颜。
瀏覽器的跨域請求必須同時滿足這兩個機制,才能將 cookie 發(fā)出茧球。
除了我們在 javascript 中使用 XMLHttpRequest 以及 fetch庭瑰。我們還會在 html 中引入一下標(biāo)簽,常用的比如 img抢埋、iframe 等弹灭。其中這些資源也會涉及到 cookie 發(fā)送的問題,這些問題往往被我們所忽視:
請求類型 | 示例 | strict | None | lax |
---|---|---|---|---|
鏈接 | < a href=""></a> | 否 | 是 | 是 |
預(yù)加載 | <link ref="prerender" href="" /> | 否 | 是 | 是 |
get 表單 | <form method="get"> | 否 | 是 | 是 |
post 表單 | <form method="post"> | 否 | 是 | 否 |
iframe | <iframe src=""> | 否 | 是 | 否 |
AJAX | get("") | 否 | 是 | 否 |
image | <img src=""> | 否 | 是 | 否 |
其中需要特別注意的就是 a 標(biāo)簽揪垄,當(dāng)點擊標(biāo)簽后穷吮,如果 same-site 屬性為 strict,跳轉(zhuǎn)過去的頁面是不會攜帶 cookie 的饥努。所以會造成很多網(wǎng)頁的登錄狀態(tài)失效捡鱼,這個要特別注意。
所以我覺得默認(rèn)的 lax 其實是比較合適的酷愧,在安全性以及易用性上保持平衡
cookie 與安全
在學(xué)習(xí)使用 egg 的過程中驾诈,會涉及到一些關(guān)于 cookie 安全的問題。下面對這些 cookie的安全問題做一個總結(jié)
csrf-token
csrf (cross-site request forgery) 跨站請求偽造溶浴。一句話解釋就是乍迄,攻擊者會利用 cookie 信息,在第三方網(wǎng)頁上偽造真實請求士败,進(jìn)行網(wǎng)絡(luò)攻擊就乓。
特點:
- 攻擊一般發(fā)生在第三方網(wǎng)站,而不是被攻擊的網(wǎng)站拱烁。
- 攻擊者利用受害者 cookie 信息生蚁,冒充受害者身份,進(jìn)行網(wǎng)絡(luò)交互戏自。
解決方式
第一種就是 same-site 屬性邦投。當(dāng)然只有支持這個屬性的瀏覽器才可以。如果是版本較老的瀏覽器就不行了擅笔。
第二種方式就是 csrf-token
csrf-token 簡單說就是在 cookie 中存儲一個新的字段志衣,通過網(wǎng)絡(luò)請求頁面時服務(wù)器注入一個加密的字符串,在之后的網(wǎng)絡(luò)請求時猛们,都會攜帶這個字符串念脯,如果服務(wù)器判斷字符串不合法,就不會返回真實數(shù)據(jù)以及數(shù)據(jù)交互弯淘。
csrf-token 的實現(xiàn)也有兩種方式绿店。
- 第一種就是 session 存儲, 服務(wù)器會在內(nèi)存或者數(shù)據(jù)庫存儲 session 數(shù)據(jù)。
- 第二種方式是規(guī)定所有接口都要攜帶一個新的請求頭攜帶 csrf-token 數(shù)值,并且瀏覽器也會自動在 cookie 字段中攜帶 csrf-token 數(shù)值假勿。服務(wù)器會在收到請求時比對這兩個 token 是否一致來判斷是否來自于第三方頁面借嗽。
我比較喜歡第二種方式,因為可以減輕服務(wù)器的壓力转培,實現(xiàn)也比較簡單恶导。
cookie 防篡改
cookie 存儲在瀏覽器中,javascript浸须、用戶手動都是可以進(jìn)行修改的惨寿。
為了防止 cookie 被篡改,可以在服務(wù)器下發(fā) cookie 的時候删窒,同時下發(fā)一個根據(jù)內(nèi)容加密的 cookie 字段缤沦。
set-cookie name=008; path=/; httponly
set-cookie name.sig=BKz_FtEld6gVjNwSzdNZAXZCq3n2Vf7VcHISiEBp7oc; path=/; httponly
其中 name.sig 就是防止篡改的字段。當(dāng)服務(wù)器接收到 name 時會同時和 name.sig 進(jìn)行比對易稠,如果不一致缸废,就意味著 cookie 被篡改了