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

2 分钟阅读
0

我想使用 Amazon Cognito 用户池作为我的应用程序的身份验证方法。我想要一种安全的方法来验证客户发送到我的应用程序的 ID 令牌和访问令牌。

简短描述

当客户端使用用户池对您的应用程序进行身份验证时,Cognito 会发送 JSON Web 令牌 (JWT) 供您解码、读取和修改。要从 JWT 获取 Cognito 用户详细信息,请解码令牌并验证签名。

**重要事项:**在授予资源访问权限之前,必须验证签名。

解决方法

验证 Cognito 是否发布了 JWT

在 JavaScript 中使用以下代码:

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!");
}

**注意:**将 user_pool_id 替换为您的用户池 ID,将 client_id 替换为您的应用程序客户端 ID。对于 ID 令牌,将 tokenUse 字段更新为 "id"。有关可用参数的列表,请参阅 GitHub 网站上的 aws-jwt-verify

如果您使用其他编程语言,请查看 JWT 网站上的 jwt.io 库或 OpenID 网站上的 OpenID Connect 库。有关代码示例,请参阅 GitHub 网站上的解码和验证 Amazon Cognito JWT 令牌

Cognito 最多返回三个令牌:ID 令牌访问令牌刷新令牌。如果您使用 REST API、AWS Amplify 或 AWS SDK 对用户进行身份验证,则您将获得所有三个令牌。

对于 Cognito 托管式用户界面,您获得的令牌取决于您使用的授权授予类型。如果您使用隐式授予,则只能获得访问令牌和 ID 令牌。授权码授予会返回访问令牌、ID 令牌和刷新令牌。客户端凭证授予仅返回访问令牌。

访问令牌和 ID 令牌包括标头、有效载荷和签名。客户端无法解码或验证刷新令牌。

以下是 ID 令牌标头的示例。标头包含密钥 ID ("kid")和用于签署令牌的算法 ("alg")。RS256 算法是使用 SHA-256 的 RSA 签名:

{
  "kid": "key_id_example=",
  "alg": "RS256"
}

以下是包含用户信息以及令牌创建和到期时间戳的有效载荷示例:

{
  "sub": "aaaaaaaa-bbbb-cccc-dddd-example",
  "aud": "audience_example",
  "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"
}

签名是标头和有效载荷的哈希和加密组合。

Cognito 为每个用户池生成两个 RSA 密钥对。每对的私钥用于对 ID 令牌或访问令牌进行加密签名。您可以在以下位置找到公钥:

https://cognito-idp.region.amazonaws.com/userPoolId/.well-known/jwks.json

**注意:**将 region 替换为您的用户池所在的 AWS 区域,将 userPoolId 替换为您的用户池 ID。

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"
    }]
}

要验证 Cognito JWT 的签名,请使用与令牌标头匹配的密钥 ID 搜索公钥。使用不同的库来验证令牌的签名并提取值,例如到期日和用户名。

最佳实践是验证令牌未过期。此外,请确保有效载荷中的受众 ("aud") 与您在 Amazon Cognito 用户池中创建的应用程序客户端 ID 相匹配。aws-jwt-verify 库会为您检查这些值。有关更多信息,请参阅 GitHub 网站上的 aws-jwt-verify

缓存公钥

由于 JWKS 端点中的公钥很少轮换,因此您无需在每次验证令牌时都从端点下载它们。取而代之的是,下载公钥并将其缓存到使用 JWT 令牌验证逻辑的本地计算机上。

"kid" 是公钥的唯一标识符。要验证 JWT 令牌,请检查您的本地缓存以确定令牌标头中的 "kid" 是否在缓存中。如果没有缓存,则从 JWKS 端点下载公钥并更新您的缓存。

使用不同的方法检查令牌的到期或撤销状态

您可以撤消刷新令牌并使访问令牌失效,但不能撤销 ID 令牌。JWT 验证器库会验证令牌的到期时间,但这些库不会检查令牌的撤销状态。撤销状态的检查需要通过服务器端进行检查。

相关信息

了解用户池 JSON Web 令牌 (JWT)

如何使用 AWS CLI 撤销 Amazon Cognito 中的 JWT 令牌?

AWS 官方
AWS 官方已更新 4 个月前