1. 什麼是JWT
JWT是由三段信息構成的,將這三段信息文本用.鏈接一起就構成了Jwt字元串。就像這樣:
jwt的頭部承載兩部分信息:
聲明類型,這里是jwt
聲明加密的演算法 通常直接使用 HMAC SHA256
完整的頭部就像下面這樣的JSON:
然後將頭部進行base64加密(該加密是可以對稱解密的),構成了第一部分.
載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分
標准中注冊的聲明
公共的聲明
私有的聲明
標准中注冊的聲明 (建議但不強制使用) :
公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。
定義一個payload:
然後將其進行base64加密,得到Jwt的第二部分。
jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:
這個部分需要base64加密後的header和base64加密後的payload使用.連接組成的字元串,然後通過header中聲明的加密方式進行加鹽secret組合加密,然後就構成了jwt的第三部分。
將這三部分用.連接成一個完整的字元串,構成了最終的jwt:
一般是在請求頭里加入Authorization,並加上Bearer標註:
2. ID Token - JWT
我們來繼續前兩章( OAuth2 總結 , 對OpenID Connect的理解 )的討論,進入對JWT的理解。先來簡單回顧一下OAuth2和OpenID:
OpenID建立在OAuth之上,完成了認證和授權。而認證和授權的結果就體現在這個ID token之上,而這個ID token通常會是JWT。那麼為什麼會是JWT呢?我們通過以下幾點來逐一解釋。
JWT RFC 7519 給出了官方定義的一些欄位:
當然也不限於此,可以根據自己的需要,添加其他欄位。到此,我們可以看出JWT提供了ID token所需要的能力。一個完整的JTW是由三部分組成:Header,Payload,Signature。三者之間由 . 隔開,剛才提到的認證授權的欄位就存在於Payload中。
Header中存放的是JTW的元數據,包含簽名的演算法以及token的類型,如下所示:
Signature部分是對前兩部分的簽名, 防止數據篡改 。首先,需要指定一個密鑰(secret)。這個密鑰只有伺服器才知道,不能泄露給用戶。然後,使用 Header 裡面指定的簽名演算法(默認是 HMAC SHA256),按照下面的公式產生簽名。
算出簽名以後,把 Header、Payload、Signature三個部分經過base64序列化為三個字元串,再講三個字元串由 . 為間隔拼接成一個字元串返回給客戶端。
ID Token需要有足夠的安全性,JWT是如何做到的呢?
剛看到了簽名部分,簽名的作用只是為了防止數據篡改,而JWT默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。比如認證伺服器中使用私鑰進行加密,把公鑰分發給其他應用伺服器,應用服務拿到加密後的token後用公鑰解密,獲取到JWT,再用簽名的秘鑰來驗證數據是否經過的篡改。
我們來看看還有神馬其他備選么?Simple Web Tokens (SWT)和Security Assertion Markup Language Tokens (SAML)。
JWT vs SAML:JWT基於json,而SAML基於XML,在大小上就有足夠的優勢,更適用於HTML和HTTP。
JWT vs SWT:在安全性上,SWT只支持對稱加密,而JWT和SAML支持公私鑰的加密方式。
作為一個mobile developer,也想在這里對比一下原先的簡單token模式和SSO中的JWT:
在沒有該機制前,我們通常會使用一個隨機產生的字元串作為token,認證成功後返回給前端,之後前端的每個請求帶上這個token。若後台服務的是個單體應用沒有什麼問題,請求來了,驗證一下token是否有效即可,但當認證服務和其他的應用服務是分離的,怎麼做呢?應用服務受到請求,再向認證服務發起一個請求來驗證驗證token是否合法,是否有許可權訪問該應用服務。這樣做到沒有什麼問題,只是當服務變多時,比如微服務下,勢必會造成認證伺服器的壓力過大。
在使用該機制後,客戶端通過認證服務登錄,獲得這個JWT,之後其他應用服務自身便可以驗證這個token的是否有效,是否有權訪問。
看似完美,但也有它自身的問題,我們來看一個場景:許可權變更。某用戶原先是一個超級管理員,可以訪問所有服務,並可進行任意的刪除,更改操作,他在這個狀態下拿到了JWT。隨後,由於許可權更改為普通管理員,便不應該具有所有許可權,但此時他開始時的JWT被緩存在客戶端仍然可用,其他應用服務也並無法知道這個用戶的許可權已經被更改,後果可想而知了。解決的方式無非是將這個token的有效時間設置的短一些。
3. JWT的定義及其組成
JWT 的定義及其組成
JWT(JSON Web Token) 是一個非常輕巧的規范。這個規范允許我們使用JWT在用戶和伺服器之間傳遞安全可靠的信息。
一個JWT實際上就是一個字元串,它由三部分組成,頭部、載荷與簽名。
我們先將用戶認證的操作描述成一個JSON對象。其中添加了一些其他的信息,幫助今後收到這個JWT的伺服器理解這個JWT。
這裡面的前6個欄位都是由JWT的標准所定義的。
這些定義都可以在標准中找到。
將上面的JSON對象進行base64編碼可以得到下面的字元串:
這個字元串我們將它稱作JWT的Payload(載荷)。
如果你使用Node.js,可以用Node.js的包base64url來得到這個字元串:
註:Base64是一種編碼,也就是說,它是可以被翻譯回原來的樣子來的。它並不是一種加密過程。
頭部(Header)
JWT還需要一個頭部,頭部用於描述關於該JWT的最基本的信息,例如其類型以及簽名所用的演算法等。這也可以被表示成一個JSON對象:
在這里,我們說明了這是一個JWT,並且我們所用的簽名演算法(後面會提到)是HS256演算法。
對它也要進行Base64編碼,之後的字元串就成了JWT的Header(頭部):
將上面的兩個編碼後的字元串都用句號.連接在一起(頭部在前),就形成了:
最後,我們將上面拼接完的字元串用HS256演算法進行加密。在加密的時候,我們還需要提供一個密鑰(secret):
這樣就可以得到我們加密後的內容:
這一部分又叫做簽名。
最後將這一部分簽名也拼接在被簽名的字元串後面,我們就得到了完整的JWT:
4. jwt有什麼用
JWT是JSON WEB TOKEN的縮寫,它是基於 RFC 7519 標準定義的一種可以安全傳輸的的JSON對象,由於使用了數字簽名,所以是可信任和安全的。
JWT token的格式:header.payload.signature
header中用於存放簽名的生成演算法
{"alg": "HS512"}Copy to clipboardErrorCopiedpayload中用於存放用戶名、token的生成時間和過期時間
{"sub":"admin","created":1489079981393,"exp":1489684781}Copy to clipboardErrorCopiedsignature為以header和payload生成的簽名,一旦header和payload被篡改,驗證將失敗
//secret為加密演算法的密鑰 String signature = HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)