本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
验证 JSON Web 令牌
JSON Web 令牌(JWT)可以轻松解码、读取和修改。修改过的访问令牌会带来权限提升的风险。修改过的 ID 令牌会带来冒充身份的风险。您的应用程序信任您的用户池作为令牌颁发者,但如果用户拦截了传输中的令牌,该怎么办? 您必须确保应用程序收到的令牌与 Amazon Cognito 颁发的令牌一致。
Amazon Cognito 颁发令牌,这些令牌使用 OpenID Connect(OIDC)规范的某些完整性和保密性特征。用户池令牌通过到期时间、颁发者和数字签名等对象来指示令牌的有效性。签名(. 分隔的 JWT 的第三个也是最后一个分段)是令牌验证的关键组件。恶意用户会修改令牌,但如果您的应用程序检索公钥并比较签名,则该令牌将不匹配。处理来自 OIDC 身份验证的 JWT 的任何应用程序都必须在每次登录时执行此验证操作。
在此页上,我们为 JWT 的验证提出了一些一般性和具体的建议。在应用程序开发过程中,开发人员需要使用各种编程语言和平台。由于 Amazon Cognito 实施的 OIDC 足够接近公共规范,因此选择开发人员环境中任何声誉良好的 JWT 库都可以满足您的验证要求。
这些步骤描述了验证用户池 JSON Web 令牌(JWT)的过程。
先决条件
您的库、开发工具包或软件框架可能已处理本部分中的任务。AWS软件开发工具包为应用程序中的 Amazon Cognito 用户池令牌处理和管理提供了工具。 AWS Amplify包括检索和刷新 Amazon Cognito 令牌的功能。
有关更多信息,请参阅以下页面。
-
Amplify Dev Center(Amplify 开发中心)中的 Advanced workflows
(高级工作流)
许多库可用于解码和验证 JSON Web 令牌 (JWT)。如果您要手动处理用于服务器端 API 处理的令牌,或者您使用的是其他编程语言,则这些库可以为您提供帮助。请参阅用于处理 JWT 令牌库的 OpenID Foundation 列表
使用 aws-jwt-verify 验证令牌
在 Node.js 应用程序中,AWS建议使用该aws-jwt-verify库aws-jwt-verify,您可以使用要为一个或多个用户池验证的声明值填充 CognitoJwtVerifier。它可以检查的一些值包括以下内容。
-
该访问令牌或 ID 令牌的格式不正确或已过期,但具有有效的签名。
-
这些访问令牌来自正确的用户池和应用程序客户端
。 -
该访问令牌声明包含正确的 OAuth 2.0 作用域
。 -
对访问令牌和 ID 令牌进行签名的密钥与用户池的 JWKS URI 中的签名密钥
kid匹配。 JWKS URI 包含有关对用户令牌进行签名的私有密钥的公有信息。您可以在以下位置找到用户池的 JWKS URI:
https://cognito-idp.。<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json
有关可在 Node.js 应用程序或AWS Lambda授权方中使用的更多信息和示例代码,请参阅aws-jwt-verify
了解和检查令牌
在将令牌检查与应用程序集成之前,请考虑 Amazon Cognito 如何组装 JWT。从用户池中检索示例令牌。解码并详细检查它们,以了解它们的特征,并确定要验证的内容和时间。例如,您可能希望检查一个场景中的组成员资格,而在另一个场景中,您可能想要检查作用域。
以下部分描述在准备应用程序时手动检查 Amazon Cognito JWT 的过程。
确认 JWT 的结构
JSON Web 令牌 (JWT) 包括三个部分,各部分之间有一个 .(圆点)分隔符。
- 标题
-
Amazon Cognito 用来对令牌进行签名的密钥 ID
kid和 RSA 算法alg。Amazon Cognito 使用alg(RS256) 对令牌进行签名。kid是对您的用户池持有的 2048 位 RSA 私有签名密钥的截断引用。 - 有效载荷
-
令牌声明。在 ID 令牌中,声明包括用户属性和有关用户池
iss和应用程序客户端aud的信息。在访问令牌中,有效载荷包括作用域、组成员资格、用户池身份 (iss) 和应用程序客户端 (client_id)。 - 签名
-
签名不是像标头和有效载荷那样的可解码 base64url。它是一个 RSA256 标识符,派生自签名密钥和参数(您可以在 JWKS URI 上观察到)。
标头和有效载荷是以 base64url 编码的 JSON。您可以通过解码为起始字符 eyJ 的开头字符 { 来识别它们。如果用户向您的应用程序提供了以 base64url 编码的 JWT,但其格式不是 [JSON Header].[JSON Payload].[Signature],则它不是有效的 Amazon Cognito 令牌,您可以将其丢弃。
以下示例应用程序使用 aws-jwt-verify 验证用户池令牌。
// cognito-verify.js // Usage example: node cognito-verify.js eyJra789ghiEXAMPLE const { CognitoJwtVerifier } = require('aws-jwt-verify'); // Replace with your Amazon Cognito user pool ID const userPoolId = 'us-west-2_EXAMPLE'; async function verifyJWT(token) { try { const verifier = CognitoJwtVerifier.create({ userPoolId, tokenUse: 'access', // or 'id' for ID tokens clientId: '1example23456789', // you must verify the token audience }); const payload = await verifier.verify(token); console.log('Decoded JWT:', payload); } catch (err) { console.error('Error verifying JWT:', err); } } // Example usage if (process.argv.length < 3) { console.error('Please provide a JWT token as an argument.'); process.exit(1); } const MyToken = process.argv[2]; verifyJWT(MyToken);
验证 JWT
JWT 签名是标头和负载的哈希组合。Amazon Cognito 为每个用户池生成两对 RSA 加密密钥。一个私有密钥对访问令牌进行签名,另一个私有密钥对 ID 令牌进行签名。
验证 JWT 令牌的签名
-
解码 ID 令牌。
OpenID Foundation 还维护用于处理 JWT 令牌的库列表
。 您还可以使用AWS Lambda解码用户池 JWT。有关更多信息,请参阅使用解码和验证 Amazon Cognito J
WT 令牌。AWS Lambda -
将本地密钥 ID (
kid) 与公有kid进行比较。-
下载并存储适用于用户池的对应的公有 JSON Web Key(JWK)。它可作为 JSON Web Key Set (JWKS) 的一部分提供。您可以通过为您的环境构建以下
jwks_uriURL 来找到它:https://cognito-idp.<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json有关更多 JWK 和 JWK 集的更多信息,请参阅 JSON Web Key (JWK)
。 注意
Amazon Cognito 可能会轮换用户池中的签名密钥。最佳做法是使用
kid作为缓存密钥在应用程序中缓存公有密钥,并定期刷新缓存。将您的应用程序收到的令牌中的kid与缓存进行比较。如果您收到的令牌的颁发者是正确的,但
kid不同,则 Amazon Cognito 可能已经轮换了签名密钥。从您的用户池jwks_uri端点刷新缓存。这是个
jwks.json文件示例:{ "keys": [{ "kid": "1234example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "1234567890", "use": "sig" }, { "kid": "5678example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "987654321", "use": "sig" }] }- 密钥 ID(
kid) -
kid是一个提示,指示哪个密钥用于保护令牌的 JSON Web 签名(JWS)。 - 算法(
alg) -
alg标头参数表示用于保护 ID 令牌的加密算法。用户池使用 RS256 加密算法,该算法是 RSA 签名。 SHA-256有关 RSA 的更多信息,请参阅 RSA 加密。 - 密钥类型(
kty) -
kty参数标识与密钥结合使用的加密算法系列,例如,在本示例中为“RSA”。 - RSA 指数(
e) -
e参数包含 RSA 公有密钥的指数值。它表示为一个 Base64urlUInt-encoded 值。 - RSA 模数(
n) -
n参数包含 RSA 公有密钥的模数值。它表示为一个 Base64urlUInt-encoded 值。 - 使用(
use) -
use参数描述了公有密钥的预期用途。在本示例中,use值sig表示签名。
- 密钥 ID(
-
搜索与您 JWT 的
kid相匹配的kid的公有 JSON Web 密钥。
-
验证声明
验证 JWT 声明
-
通过以下方法之一,验证令牌是否未过期。
-
对令牌解码并将
exp声明与当前时间进行比较。 -
如果您的访问令牌包含
aws.cognito.signin.user.admin索赔,请向类似的 API 发送请求GetUser。如果令牌已过期,您使用访问令牌进行授权的 API 请求会返回错误。 -
在针对userInfo 端点的请求中提供您的访问令牌。如果您的令牌已过期,则请求会返回错误。
-
-
ID 令牌中的
aud声明和访问令牌中的client_id声明必须与在 Amazon Cognito 用户池中创建的应用程序客户端 ID 相匹配。 -
颁发者 (
iss) 索赔必须与您的用户池相匹配。例如,在us-east-1区域中创建的用户池将有下列iss值:https://cognito-idp.us-east-1.amazonaws.com/.<userpoolID> -
检查
token_use声明。-
如果您在 Web API 操作中只接受访问令牌,则其值必须为
access。 -
如果您只使用 ID 令牌,则其值必须为
id。 -
如果您同时使用 ID 令牌和访问令牌,则
token_use声明必须为id或access。
-
您现在可以信任该令牌内的声明。