摘要
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 header
Server
如果設定了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通訊)
的情況下使被取得。預設為false
HttpOnly
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