# Cookie & Session - 筆記
###### tags: `HTTP` `cookie` `session` `authentication` `web security`
:::warning
:bulb: 本站筆記已同步更新到我的[個人網站](https://simplydevs.netlify.app/)囉! 歡迎參觀與閱讀,體驗不同的視覺感受!
:::
[TOC]
## :memo: HTTP 的無狀態 (Stateless) 特性
HTTP通訊協定(HTTP Protocol)具無狀態(Stateless)的特性,這表示每個伺服器所接收的HTTP request是獨立的,並且與先前接收到的request不相關。伺服器不會保存client的狀態,因此伺服器給予的response是根據當下的狀態。
**無狀態協定具有特性如下:**
* 簡化了伺服器的設計
* 因為系統不需要追蹤多個連結通訊與session的細節,因此無狀態協定所需資源較少。
* 在無狀態協定中,各個封包(packet)各自運輸,與其他封包無涉
* 伺服器與客戶端之間的依賴程度低
因此,如果我們希望伺服器能認出 request 的狀態 (例如之前已經登入),我們可以讓 request 本身攜帶充足的資訊,來幫助伺服器判斷這個 request 是否為會員系統裡的某位使用者,再進一步判斷這位使用者的狀態。而所謂「讓 request 本身攜帶充足的資訊」,類似會員卡的概念,我們會**讓 request 攜帶一串憑證,伺服器可以用這串憑證進一步查找資料庫裡的使用者資訊,cookie就是達成這種目的的一種憑證**。
## :memo: 憑證
### 用戶端如何保存憑證
保存憑證的方法有很多種,瀏覽器本身提供了 cookie 和 web storage 等機制,如果有特殊目的,也可以拉出去儲成獨立的外部檔案。

<p style="text-align:center">兩種不同的web session管理機制</p>
<h6 style="text-align:center;">(Source: Alpha Camp material)</h6>
### 伺服器如何比對 request 攜帶的憑證?
真正的使用者資料存在資料庫裡,所以在應用程式伺服器上也需要建立一個儲存機制,才能把用戶端、應用程式伺服器、資料庫三個地方的資訊匹配起來。
在應用程式伺服器上,用來存放使用者狀態的機制,稱為 session。
### **Session**

<p style="text-align:center">session與cookie儲存使用者資訊的方式</p>
<h6 style="text-align:center">(Source: Alpha Camp material)</h6>
Session 翻譯成「會話」,這是抽象的概念,代表 **「用戶端與伺服器之間一系列的交流」**,你可以把一個「登入-登出」的週期視為一次「會話」。
* 通常「伺服器的 session」和「用戶端的 cookie」是相對存在的解決方案。
* session 也是一個 key-value pair 的結構,可以先想像成一個龐大的物件,裡面的資訊都和使用者登入記錄有關
* session通常儲存在:
* 記憶體(預設)
* 資料庫,如MySQL、MongoDB
* cache,如Redis、Memcached
* 常見的session攻擊如[session hijacking](https://owasp.org/www-community/attacks/Session_hijacking_attack),攻擊者竊取session ID並送至伺服器,若伺服器未檢查session ID的使用者身分,即可成功獲取該ID使用者的相關資訊。
* 常見預防session攻擊的措施包含:
- 增強session ID的長度、隨機性,使攻擊者難以猜測
- 設置session的有效期限(time-out)
- 增強cookie的安全性
- 設置HTTPS-Only
### **Cookie**
Cookie是使用者瀏覽網站時,由伺服器建立,傳送給瀏覽器,並透過加密的方式儲存在用戶端(Client Side)上的小片段文檔(text)。
* Cookies是key-value pair 的結構,儲存session ID,不儲存session data(session data存在資料庫裡,[如圖所示](###Session)),由HTTP response header設置,有效期為直到瀏覽器關閉或cookie過期:
`Set-Cookie: Key=Value`
實際上看起來像是`Set-Cookie: sessionID=91laR31m`
* Cookies可能會儲存敏感的個人資訊,例如個人偏好或瀏覽紀錄,所以應該確保cookie的安全性,例如透過
**1. 增加cookie到期時間:**
`Set-Cookie: Key=Value; expires=Monday, 13-March-2023 09:20:10 GMT`
**2. 增加HttpOnly的特性:**
透過增加[HttpOnly](https://owasp.org/www-community/HttpOnly)的特性,確保cookie的資料不會因XSS攻擊(Cross-Site Scripting)經由JavaScript直接存取session cookie。
`Set-Cookie: Key=Value; expires=Monday, 13-March-2023 09:20:10 GMT; HTTPOnly`
**3. 增加其他特性:**
[SameSite](https://owasp.org/www-community/SameSite):避免CSRF(Cross-Site Request Forgery)攻擊
[Secure](https://owasp.org/www-community/controls/SecureCookieAttribute):確保只有https的網站可以獲得cookie的資料
更多詳情可參考[MDN文件](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)關於Set-Cookie的解釋
* 通常儲存Cookie的地方包含:**記憶體或硬體**內,記憶體是由瀏覽器來維護的,通常會在瀏覽器關閉後清除,不同瀏覽器間的Cookie無法相互使用;硬體的Cookie則有保存期限,除非過期或是手動刪除,否則儲存時間會較瀏覽器來的久。
### **Session-Cookie運作模式**
1. 使用者進入網站,伺服器產生session和session ID
2. 伺服器的response header中可以Set-Cookie,寫入session id及其他屬性,瀏覽器收到response,儲存一個存有session ID的cookie(但不應包含任何私人資訊)
3. 存放有session ID的cookie自動連結在之後的HTTP request,傳送給伺服器
4. 伺服器接收到含有session ID的cookie的request時,解析session ID並回傳該ID相關連的session資料
5. 只要session 處於active狀態,此過程重複且持續進行
6. 當使用者關掉瀏覽器/登出/超過預先設定的session時限(如:30分鐘),session和對應的cookie即過期。
### **利用Cookie與Session進行使用者認證**
<h6 style="text-align:center">(Source: Alpha Camp material)</h6>
* 第一次登入:伺服器建立一個 session :arrow_right: 把 session id 交給用戶端:arrow_right:用戶端把 session id 保存到瀏覽器的 cookie 裡。
* 下一次登入:同一個瀏覽器發送請求:arrow_right:附上同一組 session id:arrow_right:伺服器會判斷「這個 request 來自一個登入過的使用者」:arrow_right:這個瀏覽器可以使用授權的服務內容。
* 登出:把這個 session id 消滅掉:arrow_right:結束這一回合的會話 (session)。下次再進入網站時,又需要重新登入、建立新的 session。
### 使用者認證的安全性
cookie 保存在用戶端,而用戶端可以隨意修改自己的本地資訊。如果認證機制如此單純,使用者就可以修改自己的session id假冒他人登入,因此伺服器當然不可以允許這種事發生,不但資訊本身要加密,session 裡還需要有其他的驗證機制,防止用戶端偷改資訊以及避免資訊外洩。
---
## 參考資料
* Alpha Camp教案
* [Day25 來人上菜! 給我來點Cookie and Session](https://ithelp.ithome.com.tw/articles/10278733)
* [[不是工程師] Cookie 是文檔還是餅乾?簡述HTTP網頁紀錄會員資訊的一大功臣。](https://progressbar.tw/posts/91)
* [深入理解無狀態協議、HTTP 與 web 會話](https://blog.csdn.net/antony1776/article/details/83474496)
* [白話 Session 與 Cookie:從經營雜貨店開始](https://hulitw.medium.com/session-and-cookie-15e47ed838bc)
* [Difference between Stateless and Stateful Protocol](https://www.geeksforgeeks.org/difference-between-stateless-and-stateful-protocol/)
::: success
:crescent_moon: 本站內容僅為個人學習記錄,如有錯誤歡迎留言告知、交流討論!
:::