为什么使用 Cognito 的 RevokeToken 后仍然可以向 API Gateway 授权请求?

Qia*_* Li 4 amazon-web-services jwt amazon-cognito aws-sdk aws-lambda

我正在使用 AWS Lambda 函数 (Node.js 14.x) 调用 CognitorevokeToken函数来撤销刷新令牌。

根据官方文档,“revokeToken”将:

撤销由指定刷新令牌生成的所有访问令牌。令牌被撤销后,您将无法使用撤销的令牌访问 Cognito 认证的 API。

虽然我可以成功撤销刷新令牌和关联的访问令牌,但仍然可以使用之前创建的访问令牌来访问 API 网关资源(启用了 Cognito 用户池身份验证)。

RevokeToken为什么使用Cognito的方法撤销访问令牌后仍然可以授权对API网关的请求?

Erm*_*ary 8

您的刷新令牌和使用该刷新令牌创建的访问令牌将被撤销,但是 API Gateway 不会接受此操作并仍然允许访问。

原因是API Gateway 使用身份令牌来授权 API 调用,而不是访问令牌

该文件(我必须承认非常不清楚)提到:

令牌被撤销后,您将无法使用撤销的令牌访问Cognito 认证的 API

在这种情况下,上述含义是撤销实际上属于Cognito 的API 操作的令牌,而不是使用Cognito 进行身份验证的服务。

这就是为什么您仍然可以使用 API Gateway 进行身份验证,因为它将在内部使用未撤销的 ID 令牌。


为了演示这一点,典型的 Cognito 身份验证结果将如下所示:

{
   "AuthenticationResult":{
      "AccessToken":"eyJraWQiOiJvZ2JFM2xXN0FWeEpPZjJWRU50MW9RNnRrY3ZOdVRJUUNTZkJpczlBWDFBPSIsImFsZyI6IlJTMjU2In0.eyJvcmlnaW5fanRpIjoiOThjM2QyNTgtYWU1NC00MzBiLWEwNjktYjg4OGZhNWQ5YzkwIiwic3ViIjoiZWE5MGQ2MjktMWI3NS00Y2ZiLThkOWQtZGRmZWJhZGZlZGYzIiwiZXZlbnRfaWQiOiJlODMxZWI1MS1mMjM3LTRhNDctYTM3YS1jNTk5MzBkNzFkZDgiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiYXV0aF90aW1lIjoxNjM0NDcxOTA1jsda56dsf8sd7f7sdf9sdf6hdf8gfdf8dg89dfg8dfgIiwiZXhwIjoxNjM0NTU4MzA1LCJpYXQiOjE2MzQ0NzE5MDUsImp0aSI6IjNlMWQ1ZmJjLTUwNjMtNGZmNS1iZDIxLWFlZTk1ZjAyZTVjZCIsImNsaWVudF9pZCI6IjNiZHBsZzNxYmwyNWJhczM1aWRuOWU4YWdqIiwidXNlcm5hbWUiOiJxbDAzIn0.FU8fv7bXDFLhUku_A11bLiw2kCdLCIepZ0l4E5t8okC_KgABGE4G_VFZ5E34VYAokuy-npWQaP84PKksnPR-S17phEQ-CWyoL5OM7t5sqkJseikqrgxzMoAgnSn34RUY4FJDhmuM9F5ejNhaKp-uDhDnvYaWe8Qcuz1TfBlgLUwARE1eBMaxqusmPOyJpZOvKcaeiOfqduv_rnN36UjIRaOeeDkht54n0066H9vBYnE1kwkVLlLagCI7kF2agHV6Kkl-cTVZTZjqCYzhOuAba_ZhdedsLn9xrQcY14-qgxfYiBxc-m1CVSZ-ZUTlmRShFrG6aHZDYSlWP38bRgQD8g",
      "ExpiresIn":86400,
      "TokenType":"Bearer",
      "RefreshToken":"eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.ODcmlgBQ4TWaUudE5edD5Y0Fx4LQQ6LnmNjfBBcfS14s4Q9MmiD9YQZZSyKTu9UoeR3SpQkGEVvkI6t7rhtyheMqwtJiCxmitCcKVm8RhLrjgEIq2wbBTegINEOKFQKpf3IHsolssm2UuebYpaXxxB68swMwDdBC-By51aTdAaZpJWGiviqZiCNnuzvuKNfhnrZVk482ctrBdu0AgGj-YxKsnVEQozXvCHiojnQE7YfJW048ctYUBgti0wpKvNI2_PbavT11W8cD0x093uQhARZtSBazv4mkqtbPpdv6GSzIE6PHETfKIxJIMaDzLJKAnbOHCEquHfYD1KouZO93Cw.IopkTsaLXan0zWOW.jWxoHQPORSNVHQKfypBQ23BWtq3hzwkDDasd65asd7a8sfg8sd8gsd78gs9gdf8asdc9asdfdsfFXw-hfLA1uhCIeZebRNcTzmVcR_Kd0g75tCzH8FJw4TXMPvQ9Qg9NcJI1JsA_DLC1B9m0hwPXtUib0Pz7k5Z2l7fwCUUfFfT4VNiPrhsuz35XlbNJc1fq1kfN88f5sGZ0UocYwl_CtPf-0FwMeGJkhyyKIWAguV0z5FsfaVWojDPcGkw5JqILUwYxKZUW3mSORI5tXrgVloLoF48xaFoXpK5T2xPHfSaUZMJBsFMK24MdDRgLIfy6XS-21upJsi30O6yyc96A1vYYpk-eD871WC9156AlB3BskCsmgPKRSjPaDQ6Dfuc_xDR4ZLYb5XSaFtEC8q5eGeq-N2DjS0eDQbsUyMFY8ddY7BVNWIv0X1_HRKz6Nilrveimmc4OfaQ3aTHj32VDkxJb5BZgylEgLtaO_HRnqjnPD1Ic-XlxH0oXLgVm2aN3SSdXuEr3BdtCoRtnGfAkLAlK686L-3Ryo2Xg1oR61gNJXBljeFQVeTeUSNuYBKyc_swv4pwBUW_Ff_iOiR_ddhMuzqattTEtGxyXDKIVls3tDoyerJsD5e-_igpKkw5cks9Il6XI1I0Mq2jnso7xFeZEBztt3qcXJ5w8OdV1Qsc79SnAIA8yF9K_8zwZvMfFU5ODJSkvY56lReBiHDImQfDiImkgShDSKu-4y8IP10Ba3jr55b7rebgk3fO9yV9JcZOx9C2JtAHKFaTVCYz2YRA3fChUXlRHcqJfc2cYYAx5wD9fJLR4FiVkgkapaNadYT0pc4LPnylyijtUXgxL7tpDG4i9yJiQ1hT3kHV4o9NZeXyPV-VDN2XWeCOEYhpXASnj7nyRpzH4wPmD9xa6N-4mDzqDVXel7c527eecN7ZfU3MPXJ2fHnTGTzDjPCCPG1Ur0LE-9CJMWMMxbFDV9RR6paKMU8fno-cgczR-HZsWIgGzXudYEyb03OVDmRgdKxW_oWL8yWx0KEMtibHH.5jIZnrXB7RFLn3LS1bJqGA",
      "IdToken":"eyJraWQiOiJlZFRQVFU0cXNOdFQyOEd2TWlXakg1aUExZjZFOVwvekw3OEZLYzdWU1VoWT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJlYTkwZDYyOS0xYjc1LTRjZmItOGQ5ZC1kZGZlYmFkZmVkZjMiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImlzcyI6Imh0dHBzOlwvXC9jb2dadfgsdf6asdf87sd6fsd8f89fjpITrZUOH58mhfm-ToGQznHcWxd5I48W-uHckz1F9dLP9YLZpI0e3BGPPPeEOf2lAIa0dSfzKhl-SZgSLRBd5qX066jx1_6SvnTMpDgRE9JZmFM_n3cI2_jGoShxUwr7NpGaUCo2r2LPXx9Rs-KqmU33mqTFD8F-CezracE9xuAuDiTNCwlBA9_LB1FPQhvzkkgSR5vouIyUYzg"
   },
   "..."
}
Run Code Online (Sandbox Code Playgroud)

这包含3部分:

  1. AccessToken- 用于检查对Cognito 验证的 API 的访问
  2. RefreshToken- 用于刷新访问令牌
  3. IdToken- 通常由 CUP(Congito 用户池)之外的服务使用的不记名 JWT 令牌

AccessToken&RefreshToken正在被撤销,但 JWT ID 令牌(API GW 使用的)未被撤销。

AWS 员工在此 GitHub问题中证实了这一点:

由于 IdToken 表示为 JSON Web 密钥令牌,因此它是使用秘密或私钥/公钥对进行签名的,这意味着即使您撤销 IdToken,也无法撤销分发的公钥。

其他人也指出了这个问题,例如这里这里这里。

这并不是亚马逊的错,因为 JWT 代币的本质意味着它们是无状态的。授权服务器不需要存储任何状态来验证 JWT 令牌 - 令牌本身就是验证令牌持有者授权所需的全部。

这可能在文档的另一部分中更清楚地突出显示:

如果使用任何验证令牌签名和过期的 JWT 库进行验证,则已撤销的令牌仍然有效。


从本质上讲,坏消息是您遇到了 Amazon Cognito 限制。

稍微好一点的消息是,如果您的解决方案允许,您可以将Cognito ID 令牌的 ID 令牌有效期设置为至少 1 小时。虽然Cognito 配额页面提到 ID 令牌至少需要 5 分钟,但控制台实际上会抛出Cannot be greater than refresh token expiration.5 分钟的错误。您必须将其设置为最小刷新令牌过期持续时间,当前为 60 分钟。

更好的说法是文档的措辞[AdminUserGlobalSignOut][9]

以管理员身份从所有设备注销用户。它还会使颁发给用户的所有刷新令牌失效。用户当前的访问权限和 Id 令牌在过期之前保持有效。访问令牌和 Id 令牌将在颁发后一小时过期。

好消息是,AWS Amplify 贡献者在 2 月份提供了更新,表示他们正在研究该问题(同样的“修复”有望适用于 API Gateway,作为 Congito 的外部服务)。

“最好的”消息是,您可以自己实施“真正的”令牌撤销,以防止 ID 令牌继续被使用。您将需要一个自定义API Gateway Lambda 授权者(本指南也可能有用)来使用 Cognito 验证令牌,然后还检查令牌以查看它是否已通过检查blocklistDynamoDB 表等方式撤销。我的回答中阅读有关该方法的更多信息。

除非亚马逊也允许您“撤销”ID 令牌,即管理将与撤销的刷新令牌关联的 ID 令牌添加到其一侧的阻止列表(其他服务可以使用该列表进行验证),否则您必须自己实现此操作。