只知道JWT,那JWE、JWS、JWK、JWA呢?
移動端興起和OAuth2的流行導(dǎo)致JWT這幾年火得一塌糊涂。今天要介紹另一個規(guī)范集JOSE[1],全稱Javascript Object Signing and Encryption,它和JWT有莫大的關(guān)系。
JOSE簡介
JOSE是一個Javascript對象簽名和加密協(xié)議,目的是提供一種在各個通訊方之間安全傳輸聲明( claims,例如授權(quán)信息 )的方法,它特意構(gòu)建在JSON和BASE64之上,以便在 Web應(yīng)用程序中輕松使用。目前該規(guī)范還在不斷地發(fā)展,我們常用的包含以下幾個由RFC文檔定義的概念:
JOSE規(guī)范集
JWT就可以用JWS或JWE表示,稍后我會詳細(xì)介紹這一方面的知識。
JWS
JSON Web簽名,基于JSON數(shù)據(jù)結(jié)構(gòu)、使用數(shù)字簽名技術(shù)或者消息認(rèn)證碼技術(shù)保護(hù)的內(nèi)容(MAC)都可以稱為JWS。該規(guī)范使用的密碼算法和標(biāo)識符在另一個規(guī)范JWA中定義。規(guī)則是比較多的參見RFC7515[2],這里我們通過序列化來感受一下即可。
JWS 序列化
JWS的序列化分為JWS Compact Serialization和JWS JSON Serialization兩種。
JWS Compact Serialization
該序列化表示為一種URL安全的、緊湊的字符串。格式為:
BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)
例如:
eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q
JWT通常就是這種格式。
JWS JSON Serialization
該序列化表示為一個JSON對象,有兩種格式。一般格式為:
{
"payload":"<payload contents>",
"signatures":[
{"protected":"<integrity-protected header 1 contents>",
"header":"<non-integrity-protected header 1 contents>“,
"signature":"<signature 1 contents>"},
{"protected":"<integrity-protected header N contents>",
"header":"<non-integrity-protected header N contents>",
"signature":"<signature N contents>"}]
}
平鋪格式為:
{
"payload":"<payload contents>",
"protected":"<integrity-protected header contents>",
"header":"<non-integrity-protected header contents>",
"signature":"<signature contents>"
}
舉個一般格式的例子:
{
"payload":
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"signatures":[
{"protected":"eyJhbGciOiJSUzI1NiJ9",
"header":
{"kid":"2010-12-29"},
"signature":
"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ
mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb
KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl
b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES
c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX
LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"},
{"protected":"eyJhbGciOiJFUzI1NiJ9",
"header":
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
"signature":
"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
lSApmWQxfKTUJqPP3-Kg6NU1Q"}]
}
JWE
JWS 僅僅是對聲明(claims)作了簽名,保證了其不被篡改,但是其 payload(中段負(fù)載) 信息是暴露的。也就是 JWS 僅僅能保證數(shù)據(jù)的完整性而不能保證數(shù)據(jù)不被泄露。它不適合傳遞敏感數(shù)據(jù)。JWE 的出現(xiàn)就是為了解決這個問題的。具體的可以看下圖:
JWE示意圖
從上面可以看出 JWE 的生成非常繁瑣,作為 Token 可能比較消耗資源和耗時。用作安全的數(shù)據(jù)傳輸途徑應(yīng)該不錯。舉個例子:
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.
OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe
ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb
Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV
mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8
1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi
6UklfCpIMfIjf7iGdXKHzg.
48V1_ALb6US04U3b.
5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji
SdiwkIr3ajwQzaBtQD_A.
XFBoMYUZodetZdvTiFvSkQ
一共有五個部分,被四個英文句號隔開。
其實JWE也有對應(yīng)的JSON格式,同樣具有JWS的兩種序列化方式,參見RFC7516[3]。
JWT和JWS、JWE的關(guān)系
以下是RFC7519[4]對JWT的說明:
JWT的定義
從上面可以得出一些結(jié)論:
- JWT有特定的 claims,這些claims以JSON的形式組成Payload。
- JWT的結(jié)構(gòu)可以是JWS或者JWE。
- JWT的序列化方式只能使用Compact Serialization,不能是JSON Serialization。
簡而言之,JWT是包含了特定claims的JWS或者JWE字符串。我們常見的大部分都屬于JWS。
另外,我們通常讀作J、W、T,實際建議讀作jot(角特),關(guān)于JWT的定義和規(guī)范請參閱RFC7519[5]。
JWK
JWK是本文最重要的知識點,這對我們后面學(xué)習(xí)資源服務(wù)器(Resource Server)非常重要。
場景描述
我相信簽名公私鑰這個大家都不陌生。JWT本身也要做使用私鑰進(jìn)行簽名防止信息被篡改,公鑰用來發(fā)給下游消費方來驗證JWT的可靠性。通常情況下,公鑰的配置方式為靜態(tài)文件集成,這有一個弊端,當(dāng)上游公私鑰進(jìn)行了改動,下游就無法動態(tài)進(jìn)行公鑰適配。這就是JWK要解決的問題,它對密碼算法和標(biāo)識符進(jìn)行了規(guī)范設(shè)計,它緊湊的JSON數(shù)據(jù)結(jié)構(gòu)非常方便在上下游之間傳輸。
JWK 格式
JWK是表示加密密鑰的JSON對象。該對象包含的key名稱必須是唯一的,在此基礎(chǔ)上JWK可以包含一些自定義字段。下面是一個P-256 EC(橢圓曲線離散密碼)密鑰的JWK表示:
{"kty":"EC",
"crv":"P-256",
"x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"kid":"Public key used in JWS spec Appendix A.3 example"
}
按照RFC7517[6]的定義,JWK JSON對象可能包含以下屬性:
JWK的定義屬性
根據(jù)不同的算法JWK還可能包含其它的屬性。
JWK Set
JWK Set 表示一組具有不同kid的JWK,這非常容易理解。它也是一個JSON對象,唯一的key就是keys。舉個例子:
{"keys":
[
{"kty":"EC",
"crv":"P-256",
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use":"enc",
"kid":"1"},
{"kty":"RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx
4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs
tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2
QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI
SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb
w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"2011-04-29"}
]
}
OAuth2配置中的JWK Set URL就是輸出JWK Set的端點。
JWA
JWA規(guī)范規(guī)定了哪些算法可以作為JWS和JWE的密碼算法。還規(guī)定了這些算法對應(yīng)的JWK中的alg屬性,以及特定算法在JWK包含的屬性例如前面EC算法中的crv、x、y,這些屬性并不是一成不變的,它們會根據(jù)算法的迭代進(jìn)行調(diào)整。如果你對JWA的細(xì)節(jié)感興趣,請參閱RFC7518[7]。
你可以通過JWK生成器[8]自行使用一些算法生成JWK觀察不同算法之間的區(qū)別。
小結(jié)
今天對JOSE規(guī)范進(jìn)行簡單的介紹了解,對你學(xué)習(xí)OAuth2和OIDC相關(guān)的知識非常有幫助。不要求深入但是一定要了解相關(guān)的知識。
參考資料:
[1]JOSE: https://datatracker.ietf.org/wg/jose/documents/
[2]RFC7515: https://datatracker.ietf.org/doc/rfc7515/
[3]RFC7516: https://datatracker.ietf.org/doc/rfc7516/
[4]RFC7519: https://datatracker.ietf.org/doc/rfc7519/
[5]RFC7519: https://datatracker.ietf.org/doc/rfc7519/
[6]RFC7517: https://datatracker.ietf.org/doc/rfc7517/
[7]RFC7518: https://datatracker.ietf.org/doc/rfc7518/
[8]JWK生成器: https://mkjwk.org/