認識Cookie、Session、Token與JWT
當我們需要設計會員登入機制的時候,很常會面臨到該如何選擇最適合的技術在網站上?這裡將會整理出設計驗證機制的重點。
前情提要
驗證 Authentication
簡單來說就是驗證使用者的身份。
授權 Authorization
使別人有權限做事情,例如給予第三方應用程式可以用哪些服務。
憑證 Credentials
要實行驗證和授權之前,需要有東西可以證明這些事情,而這個東西就叫憑證,可以想像是你的身分證。
例如你要在凌晨的時候進去網咖或是酒吧,必須要有東西證明你是成年的。
認證機制種類
最常見的認證機制為以下三種:
- Cookie
- Session
- JSON Web Token
Cookie
以key-value的方式儲存在瀏覽器內。
無狀態的協議
無狀態表示對處理過的事件並沒有記憶性,每個請求都是獨立的,因此也無法辨識這次的請求和上次的請求是否為同一個人。為了要確認是否是同一個瀏覽器執行請求,因此需要額外處理這些判斷,可以透過Session來判別。
儲存在Client
Server會發送一些資料到Client儲存,下次Client發送請求的時候會送給Server。
因為儲存在Client,資料可能會被用戶任意竄改,因此在使用前可以先進行檢查。
不可跨域
Cookie會綁定同一個網域,無法在別的網域獲取使用。
Session
紀錄Server與Cient狀態的一種機制,Session基於Cookie產生出Session與SessionId,Session儲存在Server,SessionId則儲存在Client。
流程
- Server根據用戶提供的資料創建Session
- 請求回到Client收到回傳的SessionId
- 將返回的SessionId紀錄在Cookie與Domain
- 當Client第二次訪問Server的時候,會將Cookie傳送到Server拿取SessionId,在查找到對應的Session驗證使用者已經登入了。
Cookie和Session比較
安全性
Session將資訊儲存在Server,相較儲存在Client的Cookie安全。
儲存資訊
Session可以儲存任意的資料類型,Cookie只能儲存字串。
時效
Session時效較短,Client關閉或是過期都會失效。
Cookie可以保持長時間的登入狀態,例如常見的默認登入。
儲存大小
Session可儲存的空間較大,但是客戶過多會佔用大量的資源。
Cookie限制儲存最大不超過4KB。
Token
Acesss Token
一種訪問時所需要的憑證。
組成
唯一Id + 時間戳記 + 簽名
UId + Time stamp + signature
特點
- Server不需儲存狀態,因此擴展性較高
- 較高的安全性
- 可跨域使用
流程
- Client要求登入
- Server收到請求驗證帳號密碼
- 驗證成功會發送Token到Client
- Client收到請求會儲存在Cookie或localstorage
- Client每次請求都會帶Token
- Server每次收到請求都會驗證Token
重點
- 每次攜帶Token都會放到Http的header
- 由於是Server無狀態的驗證方式,因次Server不需儲存Token,改以解析Token的時間換取儲存空間來減少Server的負擔,不需再頻繁的查詢資料庫。
- Token不受限於同源問題
Refresh token
改善Token時效過長可能被竊取的問題(降低風險)
是一種可以刷新Access token的token,有沒有它其實都可以刷新Access token,只是每次要刷新都要使用者登入一次帳號密碼,所以他改善使用者需要額外做的一些繁瑣動作確認是否為本人。
重點
- 如果過期了,那使用者還是要登入。
- Refresh token的過期時間儲存在Server資料庫上,只有在申請新的Access token的時候才要驗證。
Token和Session的差別
以身份驗證來說,Token的安全性比Session來得好。
如果你的產品需要支援第三方服務,用Token。
如果只需要在自己的網站上開發,都行。
JSON Web Token
JWT是目前最流行的跨網域解決方案,一般被用來傳遞使用者的資訊。
可以使用HMAC演算法或RSA公私鑰進行簽名。
首先來了解JWT解決了什麼問題,因為他是存在Client,所以他的出現不是為了解決資料安全的問題,而是為了確保資料是被本人所創建的!(無法竄改)
為什麼無法解決安全性的問題?因為header, payload是以base64的方式編碼,base64主要是為了方便傳遞資料而被使用的
Token由於會攜帶資料,所以會比cookie還大。
驗證流程
- Client登入,Server認證成功之後送一組JWT到Client。
- Client儲存JWT在local,通常是放在localstorage。
- 當使用者想要訪問受到保護的route或是資源的時候,需要在header的Authorization加入Bearer模式
1 | Authorization: Bearer <token> |
- Server的Router將會檢查Authorization
- JWT可夾帶使用者訊息,因此減少了訪問資料庫的動作
- JWT不會使用到Cookie,因此可以使用任意網域的服務
- 使用者的狀態不再儲存到Server,所以是一種無狀態驗證機制
JWT使用方式
放入header
當然使用者可以放到Cookie,但是這樣就無法進行跨域,因此可以放到header的Authorization。1
2
3GET /calendar/v1/events
Host: api.example.com
Authorization: Bearer <token>使用URL傳輸
這是一種方式,不過不建議這麼做,因為把Token暴露給大家看到了1
http://www.example.com/user?token=xxx
Token和JWT
共通點
- 都是一種Token
- 都可以記錄使用者訊息
- 讓Server無狀態化
- 驗證成功後,才能訪問資源
差異
Token
驗證Client送過來的Token時,還需要使用資料庫查詢資料,再驗證Token是否有效
JWT
將Token和payload加密後儲存在Client,Server只需要使用key進行解密,不需要額外再使用資料庫,因為JWT已經包含使用者資訊和加密訊息。
參考資料
Cookie、Session、Token、JWT
JWT suck
https://learnku.com/articles/22616
https://ithelp.ithome.com.tw/articles/10199102