當我們需要設計會員登入機制的時候,很常會面臨到該如何選擇最適合的技術在網站上?這裡將會整理出設計驗證機制的重點。

前情提要

驗證 Authentication

簡單來說就是驗證使用者的身份。

授權 Authorization

使別人有權限做事情,例如給予第三方應用程式可以用哪些服務。

憑證 Credentials

要實行驗證和授權之前,需要有東西可以證明這些事情,而這個東西就叫憑證,可以想像是你的身分證。
例如你要在凌晨的時候進去網咖或是酒吧,必須要有東西證明你是成年的。

認證機制種類

最常見的認證機制為以下三種:

  1. Cookie
  2. Session
  3. JSON Web Token

以key-value的方式儲存在瀏覽器內。

無狀態的協議

無狀態表示對處理過的事件並沒有記憶性,每個請求都是獨立的,因此也無法辨識這次的請求和上次的請求是否為同一個人。為了要確認是否是同一個瀏覽器執行請求,因此需要額外處理這些判斷,可以透過Session來判別。

儲存在Client

Server會發送一些資料到Client儲存,下次Client發送請求的時候會送給Server。
因為儲存在Client,資料可能會被用戶任意竄改,因此在使用前可以先進行檢查。

不可跨域

Cookie會綁定同一個網域,無法在別的網域獲取使用。

Session

紀錄Server與Cient狀態的一種機制,Session基於Cookie產生出Session與SessionId,Session儲存在Server,SessionId則儲存在Client。

流程

  1. Server根據用戶提供的資料創建Session
  2. 請求回到Client收到回傳的SessionId
  3. 將返回的SessionId紀錄在Cookie與Domain
  4. 當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

特點

  1. Server不需儲存狀態,因此擴展性較高
  2. 較高的安全性
  3. 可跨域使用

流程

  1. Client要求登入
  2. Server收到請求驗證帳號密碼
  3. 驗證成功會發送Token到Client
  4. Client收到請求會儲存在Cookie或localstorage
  5. Client每次請求都會帶Token
  6. Server每次收到請求都會驗證Token

重點

  1. 每次攜帶Token都會放到Http的header
  2. 由於是Server無狀態的驗證方式,因次Server不需儲存Token,改以解析Token的時間換取儲存空間來減少Server的負擔,不需再頻繁的查詢資料庫。
  3. Token不受限於同源問題

Refresh token

改善Token時效過長可能被竊取的問題(降低風險)
是一種可以刷新Access token的token,有沒有它其實都可以刷新Access token,只是每次要刷新都要使用者登入一次帳號密碼,所以他改善使用者需要額外做的一些繁瑣動作確認是否為本人。

重點

  1. 如果過期了,那使用者還是要登入。
  2. Refresh token的過期時間儲存在Server資料庫上,只有在申請新的Access token的時候才要驗證。

Token和Session的差別

以身份驗證來說,Token的安全性比Session來得好。
如果你的產品需要支援第三方服務,用Token。
如果只需要在自己的網站上開發,都行。

JSON Web Token

JWT是目前最流行的跨網域解決方案,一般被用來傳遞使用者的資訊。
可以使用HMAC演算法或RSA公私鑰進行簽名。
首先來了解JWT解決了什麼問題,因為他是存在Client,所以他的出現不是為了解決資料安全的問題,而是為了確保資料是被本人所創建的!(無法竄改)
為什麼無法解決安全性的問題?因為header, payload是以base64的方式編碼,base64主要是為了方便傳遞資料而被使用的
Token由於會攜帶資料,所以會比cookie還大。

驗證流程

  1. Client登入,Server認證成功之後送一組JWT到Client。
  2. Client儲存JWT在local,通常是放在localstorage。
  3. 當使用者想要訪問受到保護的route或是資源的時候,需要在header的Authorization加入Bearer模式
header
1
Authorization: Bearer <token>
  1. Server的Router將會檢查Authorization
  2. JWT可夾帶使用者訊息,因此減少了訪問資料庫的動作
  3. JWT不會使用到Cookie,因此可以使用任意網域的服務
  4. 使用者的狀態不再儲存到Server,所以是一種無狀態驗證機制

JWT使用方式

  1. 放入header
    當然使用者可以放到Cookie,但是這樣就無法進行跨域,因此可以放到header的Authorization。

    1
    2
    3
    GET /calendar/v1/events
    Host: api.example.com
    Authorization: Bearer <token>
  2. 使用URL傳輸
    這是一種方式,不過不建議這麼做,因為把Token暴露給大家看到了

    1
    http://www.example.com/user?token=xxx

Token和JWT

共通點

  1. 都是一種Token
  2. 都可以記錄使用者訊息
  3. 讓Server無狀態化
  4. 驗證成功後,才能訪問資源

差異

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