如何才能解码和验证 Amazon Cognito JSON Web 令牌的签名?

2 分钟阅读
0

我想将 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-verifyOpenID FoundationOpenID Foundation 建议的库)来验证令牌的签名并提取值(如到期信息和用户名)。

除了签名之外,验证以下内容也是最佳做法:

  • 令牌没有过期。
  • 负载中指定的受众(“aud”)与在 Amazon Cognito 用户群体中创建的应用程序客户端 ID 匹配。

aws-jwt-verify 库代表您包含这些检查。更多有关如何使用 Lambda 解码并验证 Amazon Cognito JWT 的代码示例,请参阅解码并验证 Amazon Cognito JWT 令牌


相关信息

验证 JSON 网络令牌

将令牌与用户池结合使用

AWS 官方
AWS 官方已更新 2 年前