在这篇文章中,我将分享一些关于JWT令牌的知识。具体来说,我将讨论JWT的结构,以及如何通过验证签名来信任令牌中的信息是真实的。
JWT令牌的结构。
Json Web Token(JWT)包含某些声明或事实,例如颁发者,用户,访问类型和其他特定于应用程序的属性。假设令牌有效,应用程序根据令牌中的事实或声明授予或拒绝访问权限。
签名的JWT令牌由三部分组成:头部,有效负载和签名。各个部分用点分开。下面是我从jwt.io获取的令牌的示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWT令牌的每个部分都是base64编码的。例如,如果您获取标头:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
,并将其提供给base64解码器功能,则会得到以下内容:{"alg":"HS256","typ":"JWT"}
表示令牌是JWT令牌,并使用HMAC-SHA256算法对其进行签名。
JWT标题
标题基本上告诉您JWT是否已签名。如果令牌未签名,则“alg”的值将为“none”。如果它已签名,则该值将指示用于对令牌进行签名的算法类型,如上例所示。验证令牌时,应确保令牌具有有效签名,否则请勿接受。
JWT有效载荷
根据令牌的类型,有效负载可能包含不同类型的信息,我们称之为声明。例如,如果JWT是id令牌,则声明可能包含有关用户的信息,包括用户名,id,电子邮件,姓名等...如果JWT是访问令牌,则声明还可以包括范围,角色,受众,等等...... JWT还可能包含特定于发行者或应用程序的自定义声明。例如,Azure AD允许您通过修改应用程序清单来定义自定义声明。所有索赔都是可选的。但其中一定数量已成为标准。有关标准声明的列表,请查看此Wiki文档或JWT手册的 3.2.1注册声明部分。
下面我展示了Microsoft Azure Active Directory发布的示例访问令牌。
{
"aud": "api://bafd76b5-ccb0-4e81-****-************",
"iss": "https://sts.windows.net/91db64d0-e9d0-43a4-a34b-************/",
"iat": 1560128459,
"nbf": 1560128459,
"exp": 1560132359,
"acr": "1",
"aio": "ATQAy/8LAAAAna3Zp9so64X3zDBfw1omazGdFgA+7aU/pqZ4C1K6Dg282U8h0rrv7AQ2NpW11QGu",
"amr": [
"pwd"
],
"appid": "546e1552-cd97-48d1-****-************",
"appidacr": "0",
"family_name": "John",
"given_name": "Doe",
"hasgroups": "true",
"ipaddr": "216.65.***.***",
"name": "John Doe",
"oid": "29c94cd3-f78c-4470-****-************",
"onprem_sid": "S-1-5-21-1543824733-581343488-**********-*****",
"roles": [
"Admin"
],
"scp": "",
"sub": "FV-j2XdynjmjHq3VU5OwlmcqzXgGw**********_***",
"tid": "91db64d0-e9d0-43a4-a34b-************",
"unique_name": "johndoe@email.com",
"upn": "johndoe@email.com",
"uti": "zmDgejHyj0apCH********",
"ver": "1.0"
}
让我们看看上面例子中的一些声明。
- aud - audience:这表示目标web api可以验证此访问令牌并授予用户 - John Doe访问api。
- iss - issuer:这表示发布访问令牌的颁发者。在这种情况下,Azure Active Directory是颁发令牌的服务。
- iat - issue at:这表示AAD发出令牌的时间。在这种情况下,令牌发布于:格林威治标准时间2019年6月9日星期日8:03:50。
- nbf - 不在之前:这表示令牌有效的最早时间。如果时间早于nbf中的值,则令牌无效。在示例中,nbf = iat,这意味着令牌在发布时立即生效。但是,nbf可能大于iat。例如,您可以提前发出访问令牌,但直到稍后才激活它。有关详细信息,请参阅此帖子。
- exp - expire:表示令牌过期的时间。上述令牌将于2019年6月9日星期日格林尼治标准时间9:08:50到期。因此,令牌在发布时间后的一小时五分钟内有效。过期后,不应再接受令牌。
- amr - 身份验证方法参考:客户端如何进行身份验证?在这种情况下,客户端使用用户名和密码进行身份验证。根据openid连接规范,“使用此声明的各方需要就所使用的值的含义达成一致,这可能是特定于上下文的。amr值是一个区分大小写的字符串数组“。
- sub - Subject:令牌断言信息的主体。根据Microsoft的文档,此值特定于特定的应用程序ID。例如,“如果单个用户使用两个不同的客户端ID登录两个不同的应用程序,那么这些应用程序将收到两个不同的主题声明值”。
- scp - 作用域:这是一组值,用于定义具有访问令牌的应用程序可以代表用户访问的资源和权限的种类。在OAuth2协议之后,当客户端代表用户请求访问令牌时,授权服务器应向用户显示一个同意屏幕,其中列出了应用程序请求的范围。用户需要给出同意,表明可以授予应用程序对范围所指示的资源的访问权限。
示例中的某些其他声明特定于Azure Active Directory。有关它们的详细信息,请查看文档。
id令牌的有效负载类似于访问令牌的有效负载。id令牌具有更多关于用户的声明,而不是授权。下面显示了Microsoft Azure Active Directory发出的id令牌的示例。
{
"aud": "546e1552-cd97-48d1-a9f4-************",
"iss": "https://login.microsoftonline.com/91db64d0-e9d0-****-****-************/v2.0",
"iat": 1560128457,
"nbf": 1560128457,
"exp": 1560132357,
"aio": "ATQAy/8LAAAA7U6jE1sIGgx/SMN5yYGYEJJvEx+u4GoMMLP5OTDfs4j1wcCPa/*************",
"name": "John Doe",
"nonce": "19e9904a-46b4-4dfe-a7a7-f068a637d1a2",
"oid": "29c94cd3-f78c-4470-89df-************",
"preferred_username": "johndoe@email.com",
"sub": "8V2XFRo4ea8GYl7are8FanR7vFNn6HnhO_*********",
"tid": "91db64d0-e9d0-43a4-a34b-************",
"uti": "39Un3zlE-*************",
"ver": "2.0"
}
请注意'oid'的值,它与访问令牌中的值相同。根据Microsoft的文档,“此ID可以跨应用程序唯一标识用户 - 在同一用户中签名的两个不同应用程序将在oid
声明中获得相同的值”。
JWT签名
JWT的最后一部分是签名。安全的JWT必须始终包含签名。针对JWT的一些攻击包括剥离签名并使JWT成为未签名的JWT。所以你应该总是确保JWT有一个有效的签名。
存在用于签署包括HS256,RS256和ES256的JWT的若干算法。根据JSON Web算法(JWA)规范,实现必须支持HS256。该规范还推荐了另外两种算法:RS256和ES256。其他算法是可选的。
签署JWT主要有两种不同的方式。第一种方法是使用密钥散列消息认证码(HMAC)。HMAC实质上意味着使用共享密钥来签名和验证签名。基本上,一旦使用密钥对JWT进行签名/加密,您需要知道能够解密令牌的密钥。这意味着,如果您的应用程序拥有密钥,并且您能够使用密钥解密令牌,则您知道该令牌已由预期的颁发者签名,并且未被篡改。但是,对于HMAC,泄露秘密的机会随着您需要支持的客户数量而增加。HS256(HMAC + SHA-256)是一种使用HMAC的算法。
签署JWT的第二种方式是使用公钥/私钥对。RS256(RSASSA + SHA256)是一种使用公钥/私钥对的算法。例如,在RSA算法的变体中,发行者拥有私钥,并且每个消费者获得公钥。使用公钥,消费者可以验证签名,从而验证JWT的真实性。但是,使用者无法使用公钥创建消息。因此,在共享密钥上使用公钥/私钥对的优点在于公钥/私钥中泄露秘密密钥的风险较小,因为您不需要与消费者共享密钥。在RSA算法的另一个变体中,公钥可以用于加密令牌,并且只有私钥可以用于解密它。
您可以在JWT手册中找到有关这些算法的详细讨论。
Azure AD使用公钥/私钥对进行签名和验证JWT。
Azure AD使用由公钥和私钥对组成的签名密钥。当用户登录使用Azure AD进行身份验证的应用程序时,Azure AD会创建一个安全令牌,其中包含有关该用户的信息。在将Azure发送回应用程序之前,此标记由Azure AD使用其私钥签名。要验证令牌是否有效并且源自Azure AD,应用程序必须使用Azure AD公开的公钥来验证令牌的签名,该公钥包含在租户的OpenID Connect发现文档或SAML / WS-Fed 联合元数据文档中。
你怎么能相信JWT是真实的?
如果您可以验证其签名,您可以信任JWT是真实的。例如,Azure AD使用公钥/私钥对进行签名和验证访问令牌。当您的API从AAD收到ID或访问令牌时,令牌的标头包含获取公钥的信息。
{"typ":"JWT","alg":"RS256","kid":"CtfQC8Le-8NsC7oC2zQkZpcrfOc"}
在上面的json中,“kid”是公钥的id,可用于验证令牌。您可以通过访问此公共端点来验证公钥是否存在并获取实际密钥:https://login.microsoftonline.com/common/discovery/keys
此外,如果您已有权访问公钥,则无需联系授权服务器即可验证令牌。也许,您的应用程序可以调用以检索公钥并将其缓存以供后续使用。请记住,AAD等服务会出于安全目的而转动密钥。如果您使用AAD,请查看文档。
携带签名的访问令牌(例如签名的JWT)可以由资源服务器自己验证。为此,无需联系授权服务器。
转:https://medium.com/@taithienbo/how-can-you-trust-a-jwt-to-be-authentic-2bd5124b243a