摘要
HTTP cookie(數位存根) ,後續簡稱 cookie , 專門為網頁瀏覽器所建立,用於追蹤、個人化和保存關於使用者的資訊、行為。
session(會話) 後續簡稱 session,網站瀏覽期間在伺服端留存的身份識別資訊。
cookie 記錄使用者資訊並存在 Client(客戶端) (瀏覽器),session 記錄使用者資訊並存在 Server(伺服端) (網頁主機)。
兩者相結合即 session-cookie(認證機制) ,可以用來驗證使用者的身份。
使用這個認證機制,容易有安全漏洞,需要謹慎規劃。
Session 是什麼?
web(網頁)剛出現時,只是一篇篇放在網路上的文字檔,提供紀錄、瀏覽的基本功能,隨着技術的進步,網頁互動的需求,有了登錄、電子商務、網頁遊戲...等需求,於是產生了需要識別目前瀏覽者身分的需求。- 因為HTTP是無狀態的,所以想出來的辦法就是給每個使用者發一個
session_id(會話標籤)給Client,發起請求時,瀏覽器會帶這個識別證給Server,讓Server比對,這樣就可以識別使用者身份。
Session 的實踐原理:
session 是在 Server 裡的一個儲存空間,每一位瀏覽者都會有自己的一份 session,每次請求都會透過 Client 端帶過來的 session_id 來存取對應的 session ,一般來說 session_id 儲存在 Client 端的 cookie 裡面。只要 Client 端不允許使用 cookie 一般來說 session 就會無法追蹤使用者的狀態及身份資訊。
Session 底層實踐方式:
- 當一個
session生成時,Servlet容器會創建一個HttpSession對象,那麼在HttpSession對象中,可以存放使用者狀態的資訊。 Servlet容器為HttpSession對象分配一個session_id(唯一標籤),Servlet容器把session_id塞進cookie保存在Client中。- 使用者每次發出
Http請求時,Servlet容器會從HttpServletRequest對象中取出session_id,然後根據這個session_id找到相應的HttpSession對象,從而獲取使用者狀態的資訊。
Session 結束生命週期的兩種辦法
- 一個是
Session.invalidate()方法,不過這個方法在實際的開發中,並不推薦,可能在強制註銷使用者的時候會使用; - 一個是當前使用者和
Server的交互時間超過生命週期後,session會失效。
💡 錦囊 [Tips]:
其實當瀏覽器關閉的時候,瀏覽器並沒有向
Server發送關閉session的請求,那為什麼重新打開時session訪問不到了呢? 因為瀏覽器關閉後,cookie銷毀了,重新打開瀏覽器時,之前的cookie不在了,所以Server會再發一個新的, 而本來的session會等到生命週期到了後自然銷燬。使用者瀏覽這個網站的不同頁面時,始終處於一個
session中。
Cookie 是什麼?
上面一直提到 cookie ,那麼 cookie 到底是什麼口味的? cookie 是 Server 發送後,儲存在 Client 的小型文件(最多只有4Kb),內容是一包規範的Key、value、特殊屬性。 由W3C組織提出的標準,目前所有主流瀏覽器都支援 cookie。 cookie 的作用是與 Server 進行通訊,作為http規範的一部分而存在的。
💡 錦囊 [Tips]:
Google 在2020年發出消滅 cookie 的宣言,Google預計在2022年前廢除 cookie。 但是,cookie 太深入目前的網頁生態,觸動太多人的蛋糕了,與廣告業產生強烈的分歧,計劃推遲到 2024 然後推遲到 2025 , 目前 Google 宣布結束將 Chrome 瀏覽器中 cookie 淘汰的計畫,表示將讓使用者擁有能夠選擇更多隱私的選項,而非汰除 cookie。
如果瀏覽器不支援 cookie 或者禁用了,cookie 功能就失效了。
如 ios app、Android app等,不支援 cookie 因為他們用的是原生的系統,而不是瀏覽器。
一般情況下跨域請求,瀏覽器是不會發送憑證資訊,有這個需求時,需要在 XMLHttpRequest 裡設定 withCredentials=true, 才會附帶上該ajax請求所在域的 cookie ,使 cookie 可以隨着請求跨域發送。
並且 Server 應該在 response header 中回傳 Access-Control-Allow-Credentials:true ,
否則瀏覽器將不會把 response 的結果傳遞給發出請求的程式,以確保資訊安全。 給一個帶有 withCredentials 的請求發送響應的時候, Server 端必須指定允許請求的域名,不能使用 '*' 否則會失敗。
axios和jQuery在同域ajax請求時會帶上cookie, 跨域請求不會, 跨域請求需要設定withCredentials和Server的response headerServer如果設定了httpOnly: true,那麼帶有該屬性的cookie,Client將無法讀取(可以預防XSS攻擊)。
Cookie 可用的參數:
name
as string:cookie的名稱。cookie一旦生成,名稱便不可更改。value
as object: 該cookie的值。如果值為Unicode,需要設定編碼格式。如果值為二進制,則使用base64編碼詳細資料 [Details]:
- 中文:屬於
Unicode,在記憶體中佔4個字元,cookie中使用Unicode時需要對Unicode進行編碼,否則會呈現亂碼。
一般使用UTF-8編碼。不推薦使用Big5、GBK等中文編碼,因為瀏覽器和JavaScript不一定支援。 - 英文:屬於
ASCII,記憶體中只佔2個字節。 - 二進制:例如在
cookie中使用數字證書,提供安全度。使用二進制值時需要使用base64編碼。
- 中文:屬於
MaxAge
as int:cookie失效的時間,單位秒。預設為-1。
通過getMaxAge()與setMaxAge(MaxAge as int)方法來讀寫MaxAge屬性。詳細資料 [Details]:
- 正:則表示該
cookie會在MaxAge秒之後自動失效。
瀏覽器會將MaxAge為正數的cookie持久化,寫到對應的cookie文件(存放在硬碟)中。
無論客户關閉了瀏覽器還是電腦,只要還在MaxAge秒之前,登錄網站時該cookie仍然有效。 - 負:則表示該
cookie僅在瀏覽器以及該網站打開的網頁內有效,關閉網站後cookie失效。Maxage為負數的cookie,為臨時性(存在瀏覽器記憶體中)cookie。 關閉瀏覽器cookie就消失了。 - 0:則表示刪除該
cookie。cookie機制沒有提供刪除cookie的方法,通過設定cookie即時失效來達到刪除cookie的效果。cookie會被瀏覽器從 硬碟或者記憶體中刪除‧ - 沒設定:這個
cookie的生命期為瀏覽器會話期間(稱為session cookie),關閉瀏覽器時cookie就會消失。session cookie一般不存儲在硬碟而是保存在記憶體‧
💡 錦囊 [Tips]:
HTTP1.0 中使用的是
expires。HTTP1.1 中被MaxAge取代了,
(ie6、ie7 和 ie8) 不支持MaxAge,所有的瀏覽器都支持expires。(但是現在沒人在管IE了啦)- 正:則表示該
Secure
as boolean: 該cookie是否僅能在https (被TLS(SSL)安全協議加密過的http通訊)的情況下使被取得。預設為falseHttpOnly
as boolean:啟用時瀏覽器會限制cookie只能經由 HTTP(S) 協定來存取。⚡ 注意 [Warning]:
當網站有
Cross-Site Scripting(XSS)[^1] 弱點時,若cookie有啟用HttpOnly攻擊者無法直接經由 JavaScript 存取使用者的cookie,因此HttpOnly可有效降低XSS的影響並提升攻擊難度。SameSite
as (Strict | Lax | None):瀏覽器會檢查request(請求)發起點和cookie本身是否同源,不同源則不攜帶該cookie,預設'Lax'。⚡ 注意 [Warning]:
Strict:會完全禁止第三方的
request攜帶,基本上只有在請求網域 和 URL中的網域相同,才會傳遞cookie。Lax:限制大多數的第三方請求,但 Lax 會允許 Get 的請求攜帶。
None:不限制
request攜帶cookie,需啟用secure才能生效,否則等同 'Lax'2014年10月發佈第一個規格草案。
設定
SameSite除了控制cookie的送出,也會影響cookie的寫入,開發時需要注意。同源限制,有效防護
Cross-Site Request Forgery(CSRF)[^2] 攻擊。建議除了設定SameSite以外,再加上CSRF Token會更有效的防範CSRF的攻擊。
domain
as string: 可以訪問該cookie的域名。詳細資料 [Details]:
如果設定為 ".google.com" ,則所有以 "google.com" 結尾的域名都可以訪問該
cookie。注意第一個字元必須為 "." 。cookie是有域的,根據cookie的規範(隱私安全機制),瀏覽器只會操作當前域名的cookie,也就是説 google 不能操作 github 的cookie。- 需要注意的是,雖然網站
images.google.com與網站www.google.com同屬於 Google,但是子網域不一樣,二者同樣不能互相操作彼此的cookie。
如果需要所有頂級域下的二級域名都使用同一個cookie,需要設定cookie的domain為頂級域,但會提高安全風險。
💡 錦囊 [Tips]:
因為高安全性設定的
cookie存在不能跨域問題,所以如果需要跨域認證的話,使用Token[^3]類的認證機制[^4]是比較好的做法。path
as string: 可以訪問該cookie的路徑。詳細資料 [Details]:
頁面只能獲取它屬於的 Path 的
cookie。
例如/article/a.html不能獲取到路徑為/product/abc/的cookie。path(路徑)與domain(域)一起構成cookie的使用範圍。- 設定為
/時允許所有路徑使用cookie。 path屬性需要使用符號/結尾。
comment
as string: 該cookie的用處説明。瀏覽器顯示cookie資訊的時候顯示該説明。version
as int:該cookie使用的版本號。
0:表示遵循 Netscape 的cookie規範
1:表示遵循 W3C 的 RFC 2109 規範
⚡ 注意 [Warning]:
修改、刪除
cookie時,新的cookie除value、MaxAge之外的所有屬性(ex:name、path、domain),都要與原來的cookie完全一樣,
否則瀏覽器會視為兩個不同的cookie不予覆蓋。導致修改、刪除失敗。domian、path、expires、secure都是Server給瀏覽器的指示,
指定何時應該發送cookie。這些參數不會夾帶進給Server的請求中,只有name=value會被夾帶‧從
Client讀取cookie時,包括Max-Age在內的其他屬性都是不可讀的,也不會被提交。
瀏覽器提交cookie時只會提交name與value屬性。Max-Age屬性只被瀏覽器用來判斷cookie是否過期。
Session vs Cookie
| Session | Cookie | |
|---|---|---|
| 存放位置 | 資料存在Server | 資料存在Client (硬碟或記憶體) |
| 存放格式 | 物件 | 字串 |
| 安全性 | 較安全 | 不安全,有XSS、CSRF等攻擊 |
| 尺寸限制 | 沒有限制 | 大小不能超過4k |
| 生命週期 | 生命週期到了銷毀 | 可以設定生命週期,或永久保存在本地的文件 |
| 性能需求 | 存在 Server ,體量大的時候有負載壓力 | 無 |
| 隱私 | 無 | 常用於追蹤用戶行為 |
| 路徑 | 不區分路徑 | 可以設定路徑 |
Session-Cookie (認證機制)
cookie 和 session 組合在一起可以作為使用者認證機制之一: session-cookie(認證機制)
1. Session-Cookie 的實踐原理:
Server 通過在 response header 裡設定 Set-cookie 來讓瀏覽器保存 cookie,瀏覽器在請求中攜帶 cookie 來告訴 Server 之前的狀態。 cookie 中包含若干個鍵值對,每個鍵值對可以單獨設定過期時間。
[此處應有圖]
2. Server 端設定 Cookie 方式(php 為例)
$cookie_name = "time";
$cookie_value = "20240828";
$cookie_expire = time() + (10 * 365 * 24 * 60 * 60);
$cookie_domain = ".opshell.com";
$cookie_path = "/";
$cookie_secure = true;
$cookie_httponly = true;
setcookie($cookie_name, $cookie_value, [
'expires' => $cookie_expire,
'paht' => $cookie_path,
'domain' => $cookie_domain,
'secure' => $cookie_secure,
'httponly' => $cookie_httponly,
'samesite' => 'Strict'
]);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
小結:
session 和 cookie 是常用的會話跟蹤技術。session 和 cookie 結合就可以實現 session-cookie(認證機制) ,用來認證使用者資訊。
預設 cookie 不能跨域,容易被盜取,有 XSS、CSRF 攻擊的風險,設計上要小心。
[^1]: Cross-Site Scripting(XSS) 攻擊 [^2]: Cross-Site Request Forgery(CSRF) 攻擊 [^3]: Token 類的認證機制: JWT [^4]: Token 類的認證機制: OAuth

