验证JSON网络令牌 - Amazon Cognito

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

验证JSON网络令牌

JSONWeb 令牌 (JWTs) 可以轻松解码、读取和修改。修改后的访问令牌会带来权限升级的风险。修改后的 ID 令牌会带来被冒充的风险。您的应用程序信任您的用户池作为令牌发行者,但是如果用户拦截了传输中的令牌怎么办? 您必须确保您的应用程序收到的令牌与 Amazon Cognito 发放的令牌相同。

Amazon Cognito 发行的令牌使用 OpenID Connect () 规范的某些完整性和保密性功能。OIDC用户池令牌使用过期时间、颁发者和数字签名等对象表示有效性。签名是 .-分隔符的第三部分,也是最后一段JWT,是令牌验证的关键组成部分。恶意用户可以修改令牌,但是如果您的应用程序检索到公钥并比较签名,则该令牌将不匹配。任何通过OIDC身份验证进行处理JWTs的应用程序都必须在每次登录时执行此验证操作。

在本页上,我们提出了一些一般和具体的验证建议JWTs。应用程序开发跨越各种编程语言和平台。由于 Amazon Cognito 的实现与公共规范非常接近,OIDC因此您选择的开发者环境中的任何信誉良好的JWT库都可以满足您的验证要求。

以下步骤描述了验证用户池 JSON Web Token (JWT)。

先决条件

您的库或软件框架可能已经处理了本节中的任务。SDK AWS SDKs为应用程序中的 Amazon Cognito 用户池令牌处理和管理提供工具。 AWS Amplify 包括检索和刷新 Amazon Cognito 令牌的功能。

有关更多信息,请参阅以下页面。

许多库都可用于解码和验证 JSON Web Token (JWT)。如果您想手动处理令牌以进行服务器端API处理,或者您正在使用其他编程语言,这些库可以提供帮助。有关使用令牌的信息,请参阅 OpenID 基础库列表。JWT

使用验证令牌 aws-jwt-verify

在 Node.js 应用程序中, AWS 建议 aws-jwt-verify 库,用于验证用户传递给您的应用程序的令牌中的参数。使用 aws-jwt-verify,您可以使用要为一个或多个用户群体验证的声明值填充 CognitoJwtVerifier。它可以检查的一些值包括以下内容。

有关您可以在 Node.js 应用程序或 AWS Lambda 授权方中使用的更多信息和示例代码,请参阅 aws-jwt-verify上 GitHub。

了解和检查令牌

在将令牌检查与应用程序集成之前,请考虑一下 Amazon Cognito 是如何组装的。JWTs从用户群体中检索示例令牌。解码并详细检查它们,以了解它们的特征,并确定要验证的内容和时间。例如,您可能希望检查一个场景中的组成员资格,而在另一个场景中,您可能想要检查范围。

以下各节描述了在准备应用程序时手动检查 Amazon Cognito JWTs 的过程。

确认的结构 JWT

JSONWeb Token (JWT) 包括三个部分,它们之间有一个.(点)分隔符。

标题

Amazon Cognito 用于签署令牌的密钥 ID 和RSA算法。kid algAmazon Cognito 使用 alg (RS256) 对令牌进行签名。kid是对您的用户池持有的 2048 位RSA私有签名密钥的截断引用。

有效负载

令牌声明。在 ID 令牌中,声明包括用户属性和有关用户群体 iss 和应用程序客户端 aud 的信息。在访问令牌中,有效负载包括范围、组成员资格、用户群体身份 (iss) 和应用程序客户端 (client_id)。

签名

签名不是像标头和有效负载那样的可解码 base64。它是从签名密钥和参数派生的RSA256标识符,您可以在自己的位置观察到JWKSURI。

标头和有效负载均采用 base64 编码JSON。您可以通过解码为起始字符 eyJ 的开头字符 { 来识别它们。如果您的用户JWT向您的应用程序提供了 base64 编码但其格式不正确[JSON Header].[JSON Payload].[Signature],则它不是有效的 Amazon Cognito 令牌,您可以将其丢弃。

验证 JWT

JWT签名是标头和有效载荷的哈希组合。Amazon Cognito 为每个用户池生成两对RSA加密密钥。一个私有密钥对访问令牌进行签名,另一个私有密钥对 ID 令牌进行签名。

验证令牌的签JWT名
  1. 解码 ID 令牌。

    OpenID 基金会还维护着一份用于处理令牌的库清单。JWT

    您也可以使用 AWS Lambda 解码用户池JWTs。有关更多信息,请参阅使用解码和验证 Amazon JWT Cognito 令牌。 AWS Lambda

  2. 将本地密钥 ID (kid) 与公有 kid 进行比较。

    1. 为您的用户池下载并存储相应的公共 JSON Web 密钥 (JWK)。它作为 JSON Web 密钥集 (JWKS) 的一部分提供。你可以通过jwks_uriURI为你的环境构造以下内容来找到它:

      https://cognito-idp.<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json

      有关JWK和JWK集的更多信息,请参阅 JSONWeb 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加密算法,即带有 SHA -256 的RSA签名。有关的更多信息RSA,请参阅RSA密码学

      密钥类型(kty

      kty参数标识与密钥一起使用的加密算法系列,例如本示例中的 RSA “”。

      RSA指数 () e

      e参数包含RSA公钥的指数值。它以 Base64 urlUInt 编码的值表示。

      RSA模量 () n

      n参数包含RSA公钥的模数值。它以 Base64 urlUInt 编码的值表示。

      使用(use

      use 参数描述了公有密钥的预期用途。在本示例中,usesig 表示签名。

    2. 在公共 JSON Web 密钥中搜索与您的密钥kid相匹配的JWT。kid

  3. 使用JWT库将颁发者的签名与令牌中的签名进行比较。颁发者签名源自 jwks.json kid 中与令牌匹配的公钥(RSA模数"n")。kid您可能需要先将 to PEM 格式JWK转换为格式。以下示例采用JWT和JWK并使用 Node.js 库 jsonwebtoken 来验证签名:JWT

    Node.js
    var jwt = require('jsonwebtoken'); var jwkToPem = require('jwk-to-pem'); var pem = jwkToPem(jwk); jwt.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) { });

验证声明

验证JWT索赔
  1. 通过以下方法之一,验证令牌是否未过期。

    1. 对令牌解码并将 exp 声明与当前时间进行比较。

    2. 如果您的访问令牌包含aws.cognito.signin.user.admin索赔,请向点赞发送请求GetUser。APIAPI如果您的令牌已过期,则使用访问令牌授权的请求会返回错误。

    3. 在针对userInfo 端点的请求中提供您的访问令牌。如果您的令牌已过期,则请求会返回错误。

  2. ID 令牌中的 aud 声明和访问令牌中的 client_id 声明应与在 Amazon Cognito 用户池中创建的应用程序客户端 ID 匹配。

  3. 发布者 (iss) 声明应与您的用户池匹配。例如,在 us-east-1 区域中创建的用户池将有下列 iss 值:

    https://cognito-idp.us-east-1.amazonaws.com/<userpoolID>.

  4. 检查 token_use 声明。

    • 如果您只在网络API操作中接受访问令牌,则其值必须为access

    • 如果您只使用 ID 令牌,则其值必须为 id

    • 如果您同时使用 ID 令牌和访问令牌,则 token_use 声明必须为 idaccess

您现在可以信任该令牌内的声明。