我想将 Amazon Cognito 用户群体作为我应用程序的身份验证方法。验证客户端发送到我的应用程序的 ID 和访问令牌的安全方法是什么?
简短描述
当客户端使用某个用户池来对您的应用程序进行身份验证时,Amazon Cognito 会发送 ID 令牌。对于与下面类似的情况,您可以手动验证 ID 令牌:
- 您创建了 Web 应用程序,并希望使用 Amazon Cognito 用户池进行身份验证。
- 您可以使用 Amazon Cognito 用户池进行身份验证,并使用 Amazon Cognito 身份池来检索 AWS Security Token Service(AWS STS)临时证书。使用这些证书调用 AWS Lambda,但 Lambda 没有关于最初通过用户池进行身份验证的用户的信息。
要获取 Amazon Cognito JSON Web 令牌(JWT)中包含的 Amazon Cognito 用户详细信息,您可以对它进行解码,然后验证签名。
解决方法
AWS 发布了以下可用于验证 JWT 的库:https://github.com/awslabs/aws-jwt-verify
import { CognitoJwtVerifier } from "aws-jwt-verify";
// Verifier that expects valid access tokens:
const verifier = CognitoJwtVerifier.create({
userPoolId: "<user_pool_id>",
tokenUse: "access",
clientId: "<client_id>",
});
try {
const payload = await verifier.verify(
"eyJraWQeyJhdF9oYXNoIjoidk..." // the JWT as string
);
console.log("Token is valid. Payload:", payload);
} catch {
console.log("Token not valid!");
}
用户登录后,Amazon Cognito 用户群体将返回 JWT。JWT 是一个 base64url 编码的 JSON 字符串,其中包含有关用户的信息。Amazon Cognito 返回三个令牌:ID 令牌、访问令牌和刷新令牌。ID 令牌包含在 Amazon Cognito 用户池中定义的用户字段。
令牌包括三个部分:标头、有效负载和签名。
以下是示例 ID 令牌的标头。标头包含密钥 ID(“kid”)以及用于签名令牌的算法(“alg”)。在此示例中,该算法是“RS256”,它是带有 SHA-256 的 RSA 签名。
{
"kid": "abcdefghijklmnopqrsexample=",
"alg": "RS256"
}
以下是有效负载的示例,其中包含有关用户的信息以及令牌创建和到期的时间戳:
{
"sub": "aaaaaaaa-bbbb-cccc-dddd-example",
"aud": "xxxxxxxxxxxxexample",
"email_verified": true,
"token_use": "id",
"auth_time": 1500009400,
"iss": "https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-2_example",
"cognito:username": "anaya",
"exp": 1500013000,
"given_name": "Anaya",
"iat": 1500009400,
"email": "anaya@example.com"
}
最后一部分是签名,它是标头和有效负载的哈希加密组合。
Amazon Cognito 为每个用户池生成两个 RSA 密钥对。每对的私钥用于签名相应的 ID 令牌或访问令牌。公钥在以下格式的地址提供:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
JSON 文件 (jwks.json) 采用如下格式的结构:
{
"keys": [{
"alg": "RS256",
"e": "AQAB",
"kid": "abcdefghijklmnopqrsexample=",
"kty": "RSA",
"n": "lsjhglskjhgslkjgh43lj5h34lkjh34lkjht3example",
"use": "sig"
}, {
"alg":
"RS256",
"e": "AQAB",
"kid": "fgjhlkhjlkhexample=",
"kty": "RSA",
"n": "sgjhlk6jp98ugp98up34hpexample",
"use": "sig"
}]
}
要验证 Amazon Cognito JWT 的签名,请首先搜索具有与令牌标头中的密钥 ID 匹配的密钥 ID 的公钥。然后,您可以使用库(如 aws-jwt-verify 或 OpenID Foundation 或 OpenID Foundation 建议的库)来验证令牌的签名并提取值(如到期信息和用户名)。
除了签名之外,验证以下内容也是最佳做法:
- 令牌没有过期。
- 负载中指定的受众(“aud”)与在 Amazon Cognito 用户群体中创建的应用程序客户端 ID 匹配。
aws-jwt-verify 库代表您包含这些检查。更多有关如何使用 Lambda 解码并验证 Amazon Cognito JWT 的代码示例,请参阅解码并验证 Amazon Cognito JWT 令牌。
相关信息
验证 JSON 网络令牌
将令牌与用户池结合使用