Session, Cookie, JWT相關概念

概念整理。

Session

  • 原理: Client端連上Server時,Server會創建Session出來,Server向Client端瀏覽器傳送一個名為JSESSIONID的Cookie會以Cookie的形式傳回Client端,Session依據該Cookie來識別是否為同一使用者。
    • 該Cookie為伺服器自動生成的,它的maxAge屬性一般為–1,表示僅當前瀏覽器內有效,關閉瀏覽器就會失效。
    • Cookie被禁止時會以URL重寫的方式來處理,表現形式為http://…../xxx?jsessionid=xxxxx。
    • 常有的錯誤想法:
      • 只要關閉瀏覽器,Session就消失了。沒有主動Call Server做登出的動作其實不會消除Session,Server會一直保留,因為Server這邊不會知道已經關閉瀏覽器了。會有這種錯覺,是大部分Session機制都使用Cookie來儲存Session id(瀏覽器上會看到jsessionid儲存這部分的資訊), 而關閉瀏覽器後這個Session id就消失了,再次連線Server也就無法找到原來的Session。
      • 如果Server產生的Cookie被儲存或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的Session id傳送給Server,則再次開啟瀏覽器仍然能夠找到原來的Session。
      • 關閉瀏覽器不會導致Session被刪除,Server會為seesion設定了一個失效時間,當距離客戶端上一次使用Session的時間超過這個失效時間時,Server就可以認為Client端已經停止了活動,才會把Session刪除以節省儲存空間。
  • 不可跨域,會綁單一域名。
  • Cookie的maxAge決定著Cookie的有效期,單位為秒(Second)。
  • 如果maxAge為負數,則表示該Cookie僅在本瀏覽器視窗以及本視窗開啟的子視窗內有效,關閉視窗後該Cookie即失效。maxAge為負數的Cookie,為臨時性Cookie,不會被持久化,不會被寫到Cookie檔案中。Cookie資訊儲存在瀏覽器記憶體中,因此關閉瀏覽器該Cookie就消失了。Cookie預設的maxAge值為–1。
  • 如果maxAge為0,則表示刪除該Cookie。Cookie機制沒有提供刪除Cookie的方法,因此通過設定該Cookie即時失效實現刪除Cookie的效果。失效的Cookie會被瀏覽器從Cookie檔案或者記憶體中刪除。
  • 不希望Cookie在HTTP等非安全協議中傳輸,可以設定Cookie的secure屬性為true。瀏覽器只會在HTTPS和SSL等安全協議中傳輸此類Cookie。
    • secure屬性並不能對Cookie內容執行加密,因而不能保證絕對的安全性。若需要高安全性,需要在程式中對Cookie內容加密、解密,以防洩密。

Session和Cookie的主要區別

  • 安全性: Session比 Cookie安全
    • Session是儲存Server端。
    • Cookie是儲存Client端,因此敏感資料不可放在這。
  • 存取類型:
    • Cookie只支持存文字類型,想存其他類型的需做轉換(例: 用base64)。
    • Session可以儲存任意數據類型。
  • 儲存大小:
    • Cookie: 至多4k。
    • Session: 遠高於Cookie,但過多的資料會佔用過多Server的資源。
  • 效期:
    • Cookie: 關閉瀏覽器即失效、30天內有效與永久有效。通過設定Cookie的age屬性來實現。
    • Session: 至多上限24小時,實務上預設是30分鐘。

JWT(JSON Web Token)

  • 使用時機 :
    • 跨域下的請求。
    • 一次性、時效短的請求。
    • 身份驗證單點登入(SSO)。
    • Call Web API(eg. RESTful API)。
  • JWT 主要分為三段,個別為 Header、Payload 與 Signature,以.做區隔,每一段都是透過 Base64去編碼,中間的 payload中有敏感資料會加密。
    Header.Payload.Signature
    1
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • 資料結構:
    • Header
    • 一個JSON對象, alg屬性表示簽名的算法(algorithm),默認為HMAC SHA256(寫成HS256); typ屬性表示該令牌(token)的類型(type),JWT令牌統一寫為JWT。
1
2
3
4
{
"alg": "HS256", # 加密的方法: HMAC、SHA256、RSA等
"typ": "JWT"
}
  • Payload
    • 一個JSON對象,用於存放實際需要傳遞的資料。JWT規定了7個官方參數供選擇(建議但不強制使用)。
    • 實際上這裡是明文,不適合儲存敏感資料(例如:使用者帳號密碼)。
1
2
3
4
5
6
7
iss (issuer):發行人
exp (expiration time):過期時間
sub (subject):主题
aud (audience):接收jwt的一方
nbf (Not Before):定義在什麼時間之前,該jwt都是不可用的,生效時間
iat (Issued At):簽發時間
jti (JWT ID):編號, jwt的唯一身份標識,主要用來作為一次性token,從而迴避replay attack
  • Signature
    • 針對Header與Payload產生,目的是防止資料竄改。
    • 指定一個secret,只有Server知道secret才知道,不可洩漏給用戶,然後使用 Header裡面指定的簽名演算法。
1
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),  secret)

Header、Payload 與 Signature之後用.串起來就是JWT,一般JWT放在HTTP的Authorization標頭中跟請求一起帶出去。

1
Authorization: Bearer <token>
  • 安全的使用JWT:

    • header: 確保指定唯一的decode algorithm。
    • payload: 不放入密鑰或敏感數據、設置置過期時間(exp)不要太長、驗證部分聲明(iss、aud等關鍵參數)。
    • signature: 密鑰的安全性(長度、密碼複雜度)、指定decode函數的簽名驗證等。
    • 開啟 Http only 防止Token被擷取,是常見的來 XSS防護方法之一。
    • 使用 Https 確保在授權的時候不會被竊取。
    • 用來加密的 Secret要保存在 Server不應外流 。
    • replay attacks的問題可以多宣告 jti, exp處理。
    • 黑名單機制(針對使用不當或不明原因進行手動防禦機制)、刷新機制。
    • Server端保有JWT權限的控制權(例如: 把JWT儲存Cache server中,移除及消除該JWT權限)。
    • 權限的授權與token分離(該token只是帳密認證過,擁有什麼權限依然掌握在Server這邊的設定)。
  • JWT vs Session 一些個人結論,認為都有可取之處:

    • 安全機制: JWT安全機制的細節較Session處理而言較為繁雜。
    • 擴展: JWT較為方便,不過Session這邊也有不少解決方案(硬體: F5, 軟體: nginx, AWS: ELB等方案,關鍵字: sticky session)。

Single sign-on (SSO)

  • 降低存取第三方網站的風險。
  • 減少相同身份重新輸入密碼所花費的時間。
  • 不同的使用者名稱和密碼組合衍生的問題(例如:忘記某一組帳號密碼)。
  • 跨域認證: 一般橫跨不同伺服器的架構上身份驗證Server是獨立出來,Single sign-on(SSO)的方式來處理。
    • Java類似的方案有:
    • Java Spring + Redis(利用Cache server的特性, 使用Redis存入Session或JWT的方式,讓Redis管理其時效,不同AP可以從中取得相關訊息)。

More info: JSON Web Token(JWT)
More info: Base64 編碼
More info: Single sign-on(SSO)
More info: Replay attack