好程式設計師web前端分享Cookie知識

好程式設計師IT發表於2019-07-03

  好程式設計師 web 前端分享 Cookie 知識 ,今天小編為大家帶來了一篇新手必看乾貨,接下來 讓我們一起來看一看

   一、 Cookie 的出現

   瀏覽器和伺服器之間的通訊少不了 HTTP 協議,但是因為 HTTP 協議是無狀態的,所以伺服器並不知道上一次瀏覽器做了什麼樣的操作,這樣嚴重阻礙了互動式 Web 應用程式的實現。

   針對上述的問題,網景公司的程式設計師創造了 Cookie

   二、 Cookie 的傳輸

   伺服器端在實現 Cookie 標準的過程中,需要對任意 HTTP 請求傳送 Set-Cookie HTTP 頭作為響應的一部分:

   1. Set-Cookie: name=value; expires=Tue, 03-Sep-2019 14:10:21 GMT; path=/; domain=.xxx.com;

   瀏覽器端會儲存這樣的 Cookie ,並且為之後的每個請求新增 Cookie HTTP 請求頭髮送回伺服器:

   1. Cookie: name=value

   伺服器透過驗證 Cookie 值,來判斷瀏覽器傳送請求屬於哪一個使用者。

   三、瀏覽器中的 Cookie

   瀏覽器中的 Cookie 主要由以下幾部分組成:

   · 名稱: Cookie 唯一的名稱,必須經過 URL 編碼處理。 ( 同名會出現覆蓋的情況 )

   · 值:必須經過 URL 編碼處理。

   · 域 (domain) :預設情況下 cookie 在當前域下有效,你也可以設定該值來確保對其子域是否有效。

   · 路徑 (path) :指定 Cookie 在哪些路徑下有效,預設是當前路徑下。

   · 失效時間 (expires) :預設情況下,瀏覽器會話結束時會自動刪除 Cookie; 也可以設定一個 GMT 格式的日期,指定具體的刪除日期 ; 如果設定的日期為以前的日期,那麼 Cookie 會立即刪除。

   · 安全標誌 (secure) :指定之後只允許 Cookie 傳送給 https 協議。

   瀏覽器在傳送請求時,只會將名稱與值新增到請求頭的 Cookie 欄位中,傳送給服務端。

   瀏覽器提供了一個非常蹩腳的 API 來操作 Cookie

   1. document.cookie

   透過上述方法可以對該 Cookie 進行寫操作,每一次只能寫入一條 Cookie 字串:

   1. document.cookie = 'a=1; secure; path=/'

   透過該方法還可以進行 Cookie 的讀操作:

   1. document.cookie // "a=1"

   由於上述方法操作 Cookie 非常的不直觀,一般都會寫一些函式來簡化 Cookie 讀取、設定和刪除操作。

   對於 Cookie 的設定操作中,需要以下幾點:

   對於名稱和值進行 URL 編碼處理,也就是採用 JavaScript 中的 encodeURIComponent() 方法 ; expires 要求傳入 GMT 格式的日期,需要處理為更易書寫的方式,比如:設定秒數的方式 ; 注意只有的屬性名的 secure;

   每一段資訊需要採用分號加空格。

   1. function setCookie (key, value, attributes) {

   2. if (typeof document === 'undefined') {

   3. return

   4. }

   5. attributes = Object.assign({}, {

   6. path: '/'

   7. }, attributes)

   8.

   9. let { domain, path, expires, secure } = attributes

   10.

   11. if (typeof expires === 'number') {

   12. expires = new Date(Date.now() + expires * 1000)

   13. }

   14. if (expires instanceof Date) {

   15. expires = expires.toUTCString()

   16. } else {

   17. expires = ''

   18. }

   19.

   20. key = encodeURIComponent(key)

   21. value = encodeURIComponent(value)

   22.

   23. let cookieStr = `${key}=${value}`

   24.

   25. if (domain) {

   26. cookieStr += `; domain=${domain}`

   27. }

   28.

   29. if (path) {

   30. cookieStr += `; path=${path}`

   31. }

   32.

   33. if (expires) {

   34. cookieStr += `; expires=${expires}`

   35. }

   36.

   37. if (secure) {

   38. cookieStr += `; secure`

   39. }

   40.

   41. return (document.cookie = cookieStr)

   42.}

   Cookie 的讀操作需要注意的是將名稱與值進行 URL 解碼處理,也就是呼叫 JavaScript 中的 decodeURIComponent() 方法:

   1. function getCookie (name) {

   2. if (typeof document === 'undefined') {

   3. return

   4. }

   5. let cookies = []

   6. let jar = {}

   7. document.cookie && (cookies = document.cookie.split('; '))

   8.

   9. for (let i = 0, max = cookies.length; i < max; i++) {

   10. let [key, value] = cookies[i].split('=')

   11. key = decodeURIComponent(key)

   12. value = decodeURIComponent(value)

   13. jar[key] = value

   14. if (key === name) {

   15. break

   16. }

   17. }

   18.

   19. return name ? jar[name] : jar

   20.}

   最後一個清除的方法就更加簡單了,只要將失效日期 (expires) 設定為過去的日期即可:

   1. function removeCookie (key) {

   2. setCookie(key, '', { expires: -1 })

   3. }

   介紹 Cookie 基本操作的封裝之後,還需要了解瀏覽器為了限制 Cookie 不會被惡意使用,規定了 Cookie 所佔磁碟空間的大小以及每個域名下 Cookie 的個數。

   四、服務端的 Cookie

   相比較瀏覽器端,服務端執行 Cookie 的寫操作時,是將拼接好的 Cookie 字串放入響應頭的 Set-Cookie 欄位中 ; 執行 Cookie 的讀操作時,則是解析 HTTP 請求頭欄位 Cookie 中的鍵值對。

   與瀏覽器最大的不同,在於服務端對於 Cookie 的安全性操碎了心

   signed

   當設定 signed=true 時,服務端會對該條 Cookie 字串生成兩個 Set-Cookie 響應頭欄位:

   1. Set-Cookie: lastTime=2019-03-05T14:31:05.543Z; path=/; httponly

   2. Set-Cookie: lastTime.sig=URXREOYTtMnGm0b7qCYFJ2Db400; path=/; httponly

   這裡透過再傳送一條以 .sig 為字尾的名稱以及對值進行加密的 Cookie ,來驗證該條 Cookie 是否在傳輸的過程中被篡改。

   httpOnly

   服務端 Set-Cookie 欄位中新增 httpOnly 屬性,當服務端在返回的 Cookie 資訊中含有 httpOnly 欄位時,開發者是不能透過 JavaScript 來操縱該條 Cookie 字串的。

   這樣做的好處主要在於面對 XSS(Cross-site scripting) 攻擊時,駭客無法拿到設定 httpOnly 欄位的 Cookie 資訊。

   此時,你會發現 localStorage 相比較 Cookie ,在 XSS 攻擊的防禦上就略遜一籌了。 sameSite

   在介紹這個新屬性之前,首先你需要明白:當使用者從 發起 的請求也會攜帶上 Cookie ,而從 攜帶過來的 Cookie 稱為第三方 Cookie

   雖然第三方 Cookie 有一些好處,但是給 CSRF(Cross-site request forgrey) 攻擊的機會。

   為了從根源上解決 CSRF 攻擊, sameSite 屬性便閃亮登場了,它的取值有以下幾種:

   · strict :瀏覽器在任何跨域請求中都不會攜帶 Cookie ,這樣可以有效的防禦 CSRF 攻擊,但是對於有多個子域名的網站採用主域名儲存使用者登入資訊的場景,每個子域名都需要使用者重新登入,造成使用者體驗非常的差。

   · lax :相比較 strict ,它允許從三方網站跳轉過來的時候使用 Cookie

   為了方便大家理解 sameSite 的實際效果,可以看這個例子:

   1. // a.com 服務端會在訪問頁面時返回如下 Cookie

   2. cookies.set('foo', 'aaaaa')

   3. cookies.set('bar', 'bbbbb')

   4. cookies.set('name', 'cccccc')

   5.

   6. // b.com 服務端會在訪問頁面時返回如下 Cookie

   7. cookies.set('foo', 'a', { sameSite: 'strict' })

   8. cookies.set('bar', 'b', { sameSite: 'lax' })

   9. cookies.set('baz', 'c')

   如何現在使用者在 a.com 中點選連結跳轉到 b.com ,它的請求頭是這樣的:

   1. Request Headers

   2.

   3. Cookie: bar=b; baz=c

   五、網站效能最佳化

   Cookie 在服務端和瀏覽器的通訊中,主要依靠 HTTP 的響應頭和請求頭傳輸的,所以 Cookie 會佔據一定的頻寬。

   前面提到瀏覽器會為每一次 HTPP 請求自動攜帶上 Cookie 資訊,但是對於同站內的靜態資源,伺服器並不需要處理其攜帶的 Cookie ,這無形中便浪費了頻寬。

   在最佳實踐中,一般都會將靜態資源部署到獨立的域名上,從而可以避免無效 Cookie 的影響。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2649444/,如需轉載,請註明出處,否則將追究法律責任。

相關文章