# JWT 應用 ###### tags: `JWT` `API` `驗證` `授權` ## JWT 是? JSON Web Token(JWT) 是一種開放標準(RFC 7519),使用 JSON 作為點對點傳輸的格式,裡面有包含加密的規則,其中的訊息是透過數位簽章簽名的,因此可以被驗證及信任,可使用 HMAC、RSA、ECDSA 作為加密的演算法。 儘管可以對 JWT 進行加密,以確保雙方之間傳輸的資料保密性,重點在於簽章的token,這個 token 可以驗證資料的完整性,並透過加密的方式隱藏其中的資料,當 token 使用公鑰/私鑰加密時,只有其中一方擁有私鑰才可查看簽章內的資料。 ## 什麼情況適合使用 JWT * 授權(Authorization):這是很常見 JWT 的使用方式,例如使用者從 Client 端登入後,該使用者再次對 Server 端發送請求的時候,會夾帶著 JWT,允許使用者存取該 token 有權限的資源。單一登錄(Single Sign On)是當今廣泛使用 JWT 的功能之一,因為它的成本較小並且可以在不同的網域(domain)中輕鬆使用。 * 訊息交換(Information Exchange):JWT 可以透過公鑰/私鑰來做簽章,讓我們可以知道是誰發送這個 JWT,此外,由於簽章是使用 header 和 payload 計算的,因此還可以驗證內容是否遭到篡改。 * 用在多節點微服務架構上時,主機之間不需要同步權限資料表,就可以達到認證功能,省去等待同步的時間,以及同步的資料差問題 ## JSON Web Token 結構為何? JSON Web Token 是由三個部分組成,並以點 (.) 分隔,分別是: * Header * Payload * Signature 因此,JWT 通常會像下列所示 <font color="red">xxxxx.yyyyy.zzzzz</font> 我們來分解各個部分。 **Header** Header 通常是由兩個部分組成: * 簽名演算法 (alg),例如:HMAC、SHA256、RSA * 簽名類型 (typ),例如:jwt 範例: ``` { "alg": "HS256", "typ": "JWT" } ``` 然後,這個 JSON 檔案被 Base64Url 編碼形成 JWT 第一個部分。 **Payload** 第二部分是包含了參數的內容,參數是在描述這個個體與附加的資料,例如:使用者。這個部分可以分成被註冊、公開、私有的三類。 * **被註冊的參數**: 這部分是被註冊的參數,他不是必須的,但是它提供了一些很常被使用的參數,有些例如:iss(發行者)、exp(逾期時間)、sub(標題)、aud(audience)...之類的。 注意這些參數的名稱只有用三個字元的縮寫表示 * **公開的參數**: 這部分可以任意定義,但是為了避免衝突,建議在 [IANA JSON Web Token](https://www.iana.org/assignments/jwt/jwt.xhtml) 註冊,或是定義一個命名空間的連結。 * **私有的參數**: 這些是依賴方們自定義的參數,它們沒有被定義在被註冊或公開的參數內。 範例: ``` { "sub": "1234567890", "name": "John Doe", "admin": true } ``` 然後,這個 JSON 檔案被 Base64Url 編碼形成 JWT 第二個部分。 請注意,此令牌儘管可以防止篡改,但任何人都可以讀取。 因此勿將機密信息放入JWT的有效負載或標頭元素,除非已加密。 **Signature** 要創建數位簽章,你必須帶著你的已加密的header與payload、金鑰,並透過header指定的演算法,進行簽名。 使用HMAC SHA256進行簽名,可以參考一下範例: ``` HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) ``` 這個數位簽章是用來表示訊息未被竄改,而且如果這個簽章是透過私鑰進行簽名的,它也可以知道這個簽章是的由誰進行簽名的。 **把他們放在一起** 輸出文字的組成是由3個Base64-URL的字串透過句點符號.分隔,因此他可以透過HTML與HTTP的環境傳送,與基於XML的標準(例如SAML)相比,它的檔案更小。 下圖顯示一個JWT範例,他包含著已經編碼過的header、payload以及乙個經由金鑰簽名的數位簽章。  如果你想要嘗試一下使用JWT與他的概念,你可以透過[jwt.io Debugger ](https://jwt.io/#debugger-io)去解碼、驗證與產生JWT。  ## 情境探討: ### 什麼是 HMAC ? 以及RSA or ECDSA? > HMAC屬於[雜湊](https://zh.wikipedia.org/wiki/密碼雜湊函數 "雜湊") > RSA與ECDSA屬於 [非對稱式加密](https://zh.wikipedia.org/wiki/公开密钥加密 "非對稱式加密"),我們使用非對稱加密的[簽章](https://zh.wikipedia.org/wiki/數位簽章 "簽章") 特性來做演算 > ⚠️請注意『雜湊』與『加密』與『簽章』這三個是不同行為,常常會被口誤或混淆 > HMAC,RSA簽章,ECDSA簽章都屬單向函式 單向函式是指資料被運算後,無法被解反解回原始資料,如果嘗試反解會找到多個解 HMAC是屬單純的單向雜湊,參數為一組密鑰以及原始訊息,但使用上通常會先加亂數資料在原始訊息上防止被暴力破解,這個亂數資料稱之為[鹽](https://zh.wikipedia.org/wiki/盐_(密码学) "鹽") RSA是使用因式分解的演算法,私鑰是公鑰的因數,因此可以驗證出私鑰加密的資料 ECDSA是橢圓曲線演算法,應該原理跟因式分解類似,但他與因式分解的演算法相比 在相同的安全性下,ECDSA使用的金鑰與私鑰可以較短,因此產生出來的數位簽章也較短 > 一般JWT應用上會配合SHA雜湊函數SHA256/SHA384...等等的雜湊長度來使用,防止對過長的內文做整體簽章減慢速度,以SHA-256 (雜湊完結果為256 Bit)來舉例的話分別為 1. HMAC-SHA256(下文提到的HS256) 2. RSA-SHA256(下文提到的HS256) 3. ECDSA-SHA256(下文提到的ES256) ### 何時用 HMAC?何時用 RSA or ECDSA? 如果自己用或不敏感的資料可以使用HMAC (此演算法效率高,但為對稱式加密,不適合加密資料) 適用於 Client <=> Server 的情境 要跟別人串接才使用 RSA或ECDSA 如果考量頻寬可以使用ECDSA ECDSA產生簽章速度較快,且簽章長度小 但RSA驗證簽章速度較快,且簽章長度大 使用JWT發出去的token是會被破解的,只是時間的早晚,但是不知道所謂的破解是否指公私鑰被查出來 <感謝**善導寺謝先生**提供實驗資料參考,在Performance考量下可以選擇的部份> JWT算法對比測試(HMAC/RSA/ECDSA) https://www.cnblogs.com/langshiquan/p/10701198.html JWT 簽章算法 HS256、RS256 及 ES256 及密碼生成 https://www.cnblogs.com/kirito-c/p/12402066.html ### JWT運作原理為何? header 寫明用什麼演算法方式 payload 放data主要資料(權限表或使用者參數)以及有效時間 signature 為檢查碼,避免資料被串改 JWT的形狀: header(base64) +"."+ payload(base64) + "." + signature(base64) signature為payload使用header裡面指定的演算法方式做運算 ### JWT如何預防資料外洩與串改? 對前面的資料再做一次簽章,驗證是否與後面的簽章一致 JWT中包含的資料都應視為明碼,設計上不應該放置敏感資料 ### JWT有什麼缺點? 除了等原有token失效之外,沒有方法可以停用那組發出去的token 例如管理員切斷權限或是使用者改密碼防止盜用 #### JWT如何實作把 user 踢出去的功能? **來自善導寺的謝先生**說把要踢出去的使用者token加入靜態陣列,如果token在這個靜態陣列內,就直接block他 #### 如何預防別人竊取到 token 來做壞事? 發一組高權限token時讓token的權限範圍更窄,時效性更短 或是高危險性操作時使用傳統查DB的方式登入 ### 什麼是Stateless & Stateful Service? Stateless service是指無狀態 Stateful service 是只有狀態 因為無狀態的服務比較單純,但每次參數都要帶一堆,因此要盡量把伺服器寫成有狀態的,讓被傳遞的參數減少 ## 附件 官方網站:[連結](https://jwt.io/)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up