Decentralized Web Token(DeWT)
Decentralized Web Token(DeWT) 是我們專為 TideBit-DeFi 設計的去中心化認證機制,其原理參考 JWT 的認證機制,兩者主要的不同在於 JWT 是由網站所核發(是 一種中心式的認證機制)而 DWT 則是由用戶所核發,並且兩者簽署的內容也不同。
常見的身份驗證和授權技術
當我們談論前後端的鑑權方式時,我們主要討論的是怎麼確定一個用戶或應用程式的身份以及他們是否有權限去訪 問某些資源。以下是幾種常見的鑑權方式的詳細說明:
Session - Cookie:
- 主要特點:透過伺服器生成的 Session ID 和客戶端的 Cookie 進行身份驗證和狀態管理。
- Session:當使用者成功登入後,伺服器會為該使用者建立一個獨特的 Session ID,並將此 ID 儲存於 伺服器的 session 儲存區(例如,伺服器記憶體、資料庫、Redis 等)。
- Cookie:伺服器將 Session ID 寫入使用者瀏覽器的 Cookie 中。當使用者再次訪問該網站時,瀏覽器 會自動將 Cookie 中的 Session ID 發送到伺服器,伺服器接收到後,查找對應的 Session 資料,以此確認 使用者身份。
- 優點:
- 較容易實現,尤其適用於傳統的網頁應用程式。
- 使用者登入狀態持久化,伺服器具有完全控制,可以隨時終止 session。
- 缺點:
- 伺服器需保存大量 session 資料,對於大型或高流量的應用程式可能會造成伺服器壓力。
- 當使用分散式系統或集群時,可能需要進行 session 同步,增加複雜性。
- Cookies 可能受到 XSS 和 CSRF 攻擊。
Token 驗證 (包括 JWT、SSO):
- Token:與 Session 類似,但不會儲存使用者資訊於伺服器。當使用者登入成功後,伺服器會發放一個 Token 給使用者,每次請求時帶上這個 Token,伺服器驗證 Token 的有效性即可。
- JWT (JSON Web Token):是一種編碼後的 JSON 格式的資料,可以儲存資訊(例如使用者 ID)。JWT 有 三部分:header, payload, signature。它能確保資料沒有被篡改,JWT 是一種常用的 Token 格式。
- SSO (Single Sign-On):允許使用者登入一個應用程式或平台後,可以不用重新登入便可訪問所有已授 權的其他相關聯的系統或服務。
- 主要特點:使用 Token 代替 Session ID 進行身份驗證,無需伺服器保存使用者狀態。
- 優點:
- 無狀態性,伺服器不需要保存使用者狀態,適合分散式系統。
- JWT 可以跨語言和平台使用,具有很高的擴展性。
- SSO 提供了優良的使用者體驗,允許在多個應用程式間共享身份驗證狀態。
- 缺點:
- 若 Token 遺失或被竊取,它可能被濫用,直到過期。
- JWT 的內容可以被解碼查看,因此不能用來儲存敏感資料。
SSO 實施需要考慮多種安全問題,可能增加複雜性。
OAuth 2.0 (開放授權):
- OAuth 2.0 是一個讓第三方應用程式在未取得使用者明確帳戶和密碼的情況下,取得其資源的協定。例如, 當您使用 Google 帳戶登入其他網站或應用時。
- 這個流程涉及多個步驟,包括取得授權、交換 token 以及使用 token 訪問受保護的資源。
- OAuth 2.0 定義了四種授權方式:授權碼、隱藏式、用戶密碼、客戶端憑證。
- 主要特點:允許第三方應用在不知道使用者憑證的情況下訪問使用者的資源。
- 優點:
- 可以讓第三方應用訪問特定資源,而不需要知道使用者的帳戶密碼。
- 靈活的授權方式,可以根據不同的需求和場景選擇不同的授權流程。
- 被廣泛應用和接受,有豐富的開源庫和工具支持。
- 缺點:
- 實施和管理可能複雜,需要維護授權伺服器。
- 若不正確或不安全地實施,可能會被攻擊者利用。
- 某些 OAuth 2.0 流程(例如隱藏式)可能不夠安全,需要特別注意。
核心差異:
- Session - Cookie:伺服器中心化,是一種基於伺服器的身份驗證方法,需要伺服器持久化保存每個使用者 的 Session 資料,使用者的瀏覽器需要支持並接受 Cookies,使用伺服器儲存的 Session 資料和客戶端的 Cookie 進行驗證。
- Token 驗證:與 Session 相反,是無狀態的身份驗證方法,不需要伺服器保存 Session 資料。使用 Token 進行驗證,其中 JWT 是一種常用的 Token 格式,具有自包含性,它可以在 token 本身儲存資訊。
- SSO:是一個廣義的概念,描述的是一種身份驗證策略,是一種允許在多個應用間共享身份驗證狀態的技術 。而 token(不論其格式如何)只是實現 SSO 的多種工具之一。
- OAuth 2.0:授權而非身份驗證:OAuth 2.0 重點是允許應用程式訪問特定資源,而不是驗證使用者身。它 允許第三方應用在使用者的同意下訪問其資源,涉及授權、交換 token 以及使用 token 訪問資源的多個步驟, 根據不同的需求和場景,OAuth 2.0 定義了不同的授權流程。
結語:鑑於上述技術,我們可以見到各有所長、所短。Session-Cookie 是伺服器中心,適合傳統網頁應用 。Token 驗證如 JWT 則更適合現代分散式系統。SSO 專為多應用共享驗證而設,而 OAuth 2.0 更偏重於資源授權 ,選擇哪種身份驗證和授權技術取決於應用程式的需求、結構和目標。例如,對於單一的 web 應用程式,使用 Session-Cookie 可能更簡單和直接;對於移動應用程式或單頁應用程式,使用 Token 或 OAuth 可能更為適合。
簡述 JWT
JWT 是 Auth0 提出的通過对 JSON 进行加密签名來實現授權驗證的方案;
就是登錄成功後將相關用戶信息組成 JSON 對象,然後對這個對象進行某種方式的加密,返回給客戶端;客戶端在 下次請求時帶上這個 Token;服務端再收到請求時校验 token 合法性,其實也就是在校驗請求的合法性。
產生 JWT
JWT 為 JSON Web Token 是一種開放標準(RFC 7519),它定義了一種簡單穩定的方式來表示身份驗證和授權數據 。流程為
- 是由用戶提交登入的帳號密碼後。
- 前端將加密過的用戶資料傳送給後端伺服器。
- 收到資料後,後端伺服器根據用戶的資料產生對應的 JSON ,其 JSON 含有三個部份 header、payload、signature(在第三步產生)。
- 由伺服器對用 Base64 編碼的 header、payload 簽名得到 signature, 得到的 signature 也用Base64 編碼。
- 得到 Token, Token 是 header、payload、signature 分 別Base64 編碼後得到的結果用點(.)將三者串聯起來。
const JWT =
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e25hbWU6Ikpob24gRG9lIixleHBpcmVkOjE2ODA3NjE1MDAzMDEsYWRtaW46dHJ1ZX0.PT7k3siYn67lJBMYzQkj/yLsLt1SYGztgTTiR5or1Ss=';
- header: 是實作 JWT 共用的格式,註明類別(typ)為(JWT),加密演算法(alg)為(HS256),以
{"typ":"JWT","alg":"HS256"}
為例 Base64 編碼的結果為eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
。 - payload: 裡面則是包含有前後端需要共享的資訊,以
{name:"Jhon Doe",expired:1680761500301,admin:true}
為例 Base64 編碼的結果為e25hbWU6Ikpob24gRG9lIixleHBpcmVkOjE2ODA3NjE1MDAzMDEsYWRtaW46dHJ1ZX0
。 - signature: 由後端持有的 private key 對 header 及 payload Base64Encoded 的結果使用 HMACSHA256 演算 法簽名,將簽名的結果也進行 Base64 編碼。
名詞定義
- 無狀態 JWT(Stateless JWT):包含 Session 數據的 JWT Token。Session 數據將被直接編碼進 Token 內。
- 有狀態 JWT(Stateful JWT):包含 Session 引用或其 ID 的 JWT Token。Session 數據存儲在服務端。 Session token(又稱 Session cookie):標準的、可被簽名的 Session ID,例如各類 Web 框架(譯者註:包 括 Laravel)內已經使用了很久的 Session 機制。Session 數據同樣存儲在服務端。
驗證流程
- 後端伺服器收到 JWT 後使用 base64 解碼。
- 先比對 header 內容,確認 typ 為 JWT 且 alg 為 HS256。
- (optional) 若 payload 中有 iat(issue at, 簽名時間)或是 expired 等資訊則需要判斷此 JWT 是否是未過 期的狀態。
- JWT 簽名的伺服器與驗證的伺服器會共用私鑰,所以可以將收到的 JWT 的 header,payload 的簽名,對比是 否有得到一樣的結果。
上述條件均滿足即為合法的 JWT。
JWT 的優點
- 不需要在服務端保存會話信息(RESTful API 的原則之一就是無狀態),所以易於應用的擴展,即信息不保存在 服務端,不會存在 Session 擴展不方便的情況;
- JWT 中的 Payload 負載可以存儲常用信息,用於信息交換,有效地使用 JWT,可以降低服務端查詢數據庫的次 數
JWT 的缺點
- 加密問題: JWT 默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。
- 到期問題: 由於服務器不保存 Session 狀態,因此無法在使用過程中廢止某個 Token,或者更改 Token 的權限 。在無狀態 Tokens 內存儲的數據最終會「過時」,不再反映數據庫內最新的數據。這意味著,Tokens 內保留 的可能是過期的信息。也就是說,一旦 JWT 簽發了,在到期之前就會始終有效,除非服務器部署額外的邏輯。
- 費空間: JWT Tokens 實際上並不「小」。尤其是使用無狀態 JWT 時,所有的數據將會被直接編碼進 Tokens 內 ,很快將會超過 Cookies 或 URL 的長度限制。你可能在想將它們存儲到 Local Storage。然而,Local Storage 並沒有提供任何類似 Cookies 的安全措施。LocalStorage 與 Cookies 不同,並不會在每次請求時發 送存儲的數據。
- 其實並不安全: 成上所述,將 JWT Tokens 存儲到 Cookies 內,那麼安全性與其他 Session 機制無異。但如果 你將 JWT 存儲至其它地方,會導致一個新的漏洞。簡單來說,使用 Cookies 並不是可選的,無論你是否採用 JWT。
- 無法單獨銷毀: 不像 Sessions 無論何時都可以單獨地在服務端銷毀。無狀態 JWT Tokens 無法被單獨的銷毀。 根據 JWT 的設計,無論怎樣 Tokens 在過期前將會一直保持有效。舉個例子,這意味著在檢測到攻擊時,你卻 不能銷毀攻擊者的 Session。同樣,在用戶修改密碼後,也無法銷毀舊的 Sessions。對此,我們幾乎無能為力 ,除非重新構建複雜且有狀態(Stateful)的基礎設施來明確地檢測或拒絕特定 Session,否則將無法結束會話 。但這完全違背了使用無狀態 JWT Tokens 的最初目的。
補充
Cookies 是一種存儲機制,然而 JWT Tokens 是被加密並簽名後產生的憑證。它們並不對立, 相反他們可以獨立 或結合使用。正確的對比應當是:Session 對比 JWT,以及 Cookies 對比 Local Storage。
結論
無狀態 JWT Tokens 無法被單獨地銷毀或更新,取決於你如何存儲,可能還會導致長度問題、安全隱患。有狀態 JWT Tokens 在功能方面與 Session cookies 無異,但缺乏生產環境的驗證、經過大量 Review 的實現,以及良好 的客戶端支持。
簡述 DeWT
產生 DeWT
- 用戶訪問 TideBit-DeFi 使用 metamask 與 TideBit-DeFi 連結後
- 為使用 TideBit-DeFi 的服務需使用自己的錢包簽 TideBit-DeFi 提供的相關的同意條款如 Term of services, private policy。
- 用戶簽名的內容我們使用 eip712 寫在智能合約裡,將用戶簽名的結果加上簽名的內容即為 DeWT。
存取 DeWT
在用戶產生 DeWT 後使用 api 發送給後端伺服器,並將 DeWT 將存放在用戶瀏覽器的 cookie 之中。
- 前端: 在每次發送 api 時要帶上 DeWT,並且需要定期到 cookie 檢查 DeWT 是否已過期。
- 後端: 在收到 DeWT,要先驗證此 DeWT(驗證方法稍後說明)是否合法,如合法需要到 DB 檢查此用戶是否存在, 如存在就紀錄此登入行為,若不存在則需要建立新用戶並紀錄此登入行為。
DeWT 資料格式
DeWT 為簽名的內容加上用戶簽名的結果進行 rlp 編碼。
簽名內容:
- domain: Tidebit-DeFi 的 domain
- version: Tidebit-DeFi 現在使用的版本
- agree: 服務條款的網址(Term of services),隱私條款的網址(private policy)
- 其中服務條款的網址、隱私條款的網址後面都有一個 hash 用來確定服務條款、隱私條款的版本
- signer: 用戶簽名錢包的地址
- expired: DeWT 的到期時間,簽名後的 1 小時到期。
- iat: issue at,DeWT 的簽名時間
const payload = {
domain: "https://www.tidebit-defi.com",
version: "",
agree: ["https://www.tidebit-defi.com/term_of_service/{hash}", "https://www.tidebit-defi.com/private_policy/{hash}"],
signer: "0xfc657dAf7D901982a75ee4eCD4bDCF93bd767CA4",
expired: "{timestamp}",
iat: "{timestamp}"
}
簽名結果:
const signature = {
r,
s,
v
}
驗證機制
後端在收到 DeWT 後,先將 DeWT 由 rlp 編碼轉回明文,
- 檢查 DeWT 的 domain 是否正確
- 檢查 DeWT 的 version 是否正確
- 檢查用戶同意的條款是否為最新版
- 檢查 DeWT 是否未過期,可透過 iat(issue at, 簽名時間)或是 expired 等資訊=判斷。
- 檢查用戶的簽名,由用戶的簽名結果加上明文內容反推出用戶的 publickey,再由 publickey 推出用戶的地址 ,與先前回推出的明文中提供的 signer 比對是否一致,若一致才合法。
Reference
- What is a JWT? Understanding JSON Web Tokens
- How to Sign and Validate JSON Web Tokens – JWT Tutorial
- 別再使用 JWT 作為 Session 系統!問題重重且很危險
- 一文整理前后端鉴权方案!
- session、token、jwt、oauth2
- 白话让你理解什么是 oAuth2 协议
- 前后端接口鉴权全解:cookie、session、token 区别解析
- 还分不清 Cookie、Session、Token、JWT?
- 扒一扒 Cookie、Session、Token、JWT、OAuth2、OIDC、SSO、Ids4 一家的关系网