JWT token的組成
JWT token由三個部分組成,頭部(header)、有效載荷(payload)、簽名(signature),
官網: https://jwt.io/
head
header部分由 typ 和 alg 組成,typ的全稱是(type,類型)、alg全稱(algorithm,算法),類型可以自己定義,沒有限制。而alg: HS256,表示當前的token是使用HS256算法來進行加密的。HS256實際上是一種簽名算法。
首先我們要了解幾個名詞:
- 數字簽名,數字簽名和我們平常在文件中簽上自己的名字是一樣的,數字簽名是為了防止偽造。
- 數字摘要/數據指紋: 一般來說指的就是數據的hash值,比如SHA1/SHA256/SHA512/MD5等,這些都是常見的摘要算法,最簡單的例子是我們在網上下載一個軟件時,軟件會有一個md5的編碼,一般為了安全起見,
都會讓我們去驗證下載下來的軟件的md5和官方的md5是否匹配,如果匹配就表示沒有被串改過 - 加密算法,這個就比較容易理解了,就是直接對數據進行加密,加密算法和摘要算法最大的區別就是,加密是可逆的。常見的加密算法有對稱加密和非對稱加密等。
數字簽名一般的實現是,先對一個原始數據進行一次HASH摘要,然后再使用非對稱加密算法(RSA、ECC等)對這個摘要進行加密,這樣得到的結果就是原始數據的一個簽名。
那么用戶在驗證數據的時候,只需要使用公鑰對簽名進行解密,然后得到一組hash的摘要,用這個摘要和要比較的目標數據的摘要再進行比較,如果這兩個摘要相等,說明驗證成功,否則則驗證失敗。
而在JWT中,提供了好幾種簽名算法的支持,分別是: - HS256, 這種簽名算法是表示采用同一個[secret-key]進行簽名與驗證,這種就是屬於對稱加密的驗證方式,一旦[secret_key]泄露,就無法保證安全性。
- RS256,RS256采用的是RSA非對稱加密算法來進行加密,使用公鑰進行驗證,通過私鑰進行加密,公鑰即使泄露也不會有影響,只需要確保私鑰的安全即可。
- ES256,ES256和RS256是一樣的,都是使用私鑰簽名、公鑰驗證,算法速度上的差距也不大,但是ES算法的長度相對來說要短一些。
對於單體應用來說,HS256和RS256的安全性相差不大,如果是在微服務架構中,需要多方驗證的場景,使用RS256/ES256的安全性會更高。
Header部分的數據,是通過base64位進行編碼
** { “typ”: “JWT”, “alg”: “HS256” }** | base64編碼 http://tool.oschina.net/encrypt?type= 3 | ** eyAKInR5cCI6ICJKV1QiLCAKImFsZyI6ICJIUzI1NiIKfSAK** |
payLoad
Payload 里面是 Token 的具體內容,也是一個json字符串,這些內容里面有一些是標准字段,你也可以添加其它需要的內容;payload的json結構並不像header那么簡單,payload用來承載要傳遞的數據,
它的json結構實際上是對JWT要傳遞的數據的一組聲明,這些聲明被JWT標准稱為claims , JWT默認提供了一些標准的Claim,具體內容如下。
- iss(Issuser):代表這個JWT的簽發主體;
- sub(Subject):代表這個JWT的主體,即它的所有人;
- aud(Audience):代表這個JWT的接收對象;
- exp(Expiration time):是一個時間戳,代表這個JWT的過期時間;
- nbf(Not Before):是一個時間戳,代表這個JWT生效的開始時間,意味着在這個時間之前驗證JWT是會失敗的;
- iat(Issued at):是一個時間戳,代表這個JWT的簽發時間;
- jti(JWT ID):是JWT的唯一標識。
按照JWT標准的說明:標准的claims都是可選的,在生成playload不強制用上面的那些claim,你可以完全按照自己的想法來定義payload的結構,不過這樣做根本沒必要:
- 第一是,如果把JWT用於認證, 那么JWT標准內規定的幾個claim就足夠用了,甚至只需要其中一兩個就可以了,假如想往JWT里多存一些用戶業務信息,比如角色和用戶名等,這倒是用自定義的claim來添加;
- 第二是,JWT標准里面針對它自己規定的claim都提供了有詳細的驗證規則描述,每個實現庫都會參照這個描述來提供JWT的驗證實現,所以如果是自定義的claim名稱,那么你用到的實現庫就不會主動去驗證這些claim。
同樣,payLoad中的數據,也是拼接好之后,通過base64進行編碼,得到一個目標字符串。
signature
signature表示簽名,它的組成是。
signature=HS256(base64(header)+"."+base64(payload),secret_key)
簽名的組成是,把header、payload分別通過base64進行編碼,然后拼接在一起,使用 . 作為分隔符。
再通過header中聲明的簽名方法進行整體簽名,其中HS256是一種對稱加密方法,需要指定一個secret_key。最終得到的signature就成為了jwt中的第三個部分。
最后將這3個部分組成一個完整的字符串構成了JWT:base64(header)+”.”+base64(payload)+”.”+sinature 。 這就是JWT的核心。
secret_key
是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它在任何場景都不應該流露出去。一旦客戶端得知這個secret_key, 那就意味着客戶端是可以自我簽發jwt了