Amazon Cognito 用户池安全最佳实践 - Amazon Cognito

Amazon Cognito 用户池安全最佳实践

本页介绍了可以实施以防范常见威胁的安全最佳实践。您选择的配置将取决于每个应用程序的使用案例。建议您至少对管理操作应用最低权限,并采取措施保护应用程序和用户密钥。您可以采取的另一个高级但有效的步骤是配置 AWS WAF Web ACL 并将其应用于您的用户池。

在网络层面保护您的用户池

AWS WAF Web ACL 可以保护您使用 Amazon Cognito 构建的身份验证机制的性能和成本。借助 Web ACL,您可以在 API 请求和托管登录请求之前实施防护机制。Web ACL 会创建网络层和应用程序层过滤器,根据您设计的规则丢弃流量或要求完成 CAPTCHA 验证。只有在请求满足您的 Web ACL 规则中的条件后,才会传递到您的 Amazon Cognito 资源。有关更多信息,请参阅 AWS WAF Web ACL

防止短信滥用

如果您允许在用户池中进行公开注册,则可以使用 Amazon Cognito 以短信形式发送的代码来配置账户验证。短信可能与非预期活动相关联,并导致您的 AWS 账单增加。请配置您的基础设施,使其在遭遇欺诈时具备抵御能力,避免发送短信。有关更多信息,请参阅以下 AWS 博客文章。

了解公共身份验证

Amazon Cognito 用户池具有客户身份和访问管理(CIAM)功能,支持面向公众的使用案例,即用户可自行注册账户并访问您的应用程序。当用户池允许自助注册时,它将接受来自公共互联网的用户账户请求。自助请求来自 SignUpInitiateAuth 等 API 操作,以及用户与托管登录的互动。您可以配置用户池以减少可能来自公共请求的滥用行为,或者完全禁用公共身份验证操作。

以下设置是您可以在用户池和应用程序客户端中管理公共和内部身份验证请求的一些方法。

影响公共用户池访问的用户池设置示例
设置 可用选项 配置位置 对公共身份验证的影响 控制台设置 API 操作和参数
自助注册 允许用户以管理员身份注册账户或创建用户账户。 用户池 阻止公开注册 注册 - 自助注册

CreateUserPoolUpdateUserPool

AdminCreateUserConfigAllowAdminCreateUserOnly

管理员确认 向新用户发送确认码或要求管理员进行确认。 用户池 防止在没有管理员操作的情况下确认注册 注册 - Cognito 辅助验证和确认

CreateUserPoolUpdateUserPool

AccountRecoverySettingsadmin_only

用户披露 在登录和密码重置时发送“未找到用户”消息,或者防止披露。 应用程序客户端 防止猜测登录名、电子邮件地址或电话号码 应用程序客户端 - 防止用户已存在错误

CreateUserPoolClientUpdateUserPoolClient

PreventUserExistenceErrors

客户端密钥 注册、登录、重置密码时需要或不需要密钥哈希 应用程序客户端 防范来自未经授权来源的身份验证请求 应用程序客户端 - 客户端密钥

CreateUserPoolClient

GenerateSecret

Web ACL 针对身份验证请求启用或不启用网络防火墙 用户池 根据管理员定义的请求特征和 IP 地址规则限制或阻止访问 AWS WAFWAF 设置

AssociateWebACL

ResourceArn

外部 IdP 允许第三方 IdP、用户池目录或两者中的用户登录 应用程序客户端 排除本地用户联合用户进行注册和登录。 应用程序客户端 - 身份提供者

CreateUserPoolClientUpdateUserPoolClient

SupportedIdentityProviders

授权服务器 托管或不托管用于身份验证的公开网页 用户池 关闭公开网页,只允许基于 SDK 的身份验证

CreateUserPoolDomain

创建任何用户池域都会使公开网页变得可用。

威胁防护 启用或禁用对恶意活动迹象或不安全密码的监控 用户池或应用程序客户端 当用户显示泄露迹象时,可以自动阻止登录或要求进行 MFA 威胁防护 - 保护设置

SetRiskConfiguration

SetRiskConfiguration 的参数用于定义您的威胁防护设置。

使用客户端密钥保护机密客户端

客户端密钥是与应用程序客户端关联的可选字符串。向具有客户端密钥的应用程序客户端发出的所有身份验证请求,都必须包含由用户名、客户端 ID 和客户端密钥生成的密钥哈希。那些不知道客户端密钥的用户从一开始就被应用程序拒之门外。

但是,客户端密钥存在局限性。如果您在公共客户端软件中嵌入了客户端密钥,则您的客户端密钥将暴露于外部检查之下。这会使攻击者能够在您的应用程序客户端中创建用户、提交密码重置请求以及执行其他操作。只有当应用程序是唯一有权访问该密钥的实体时,才必须实施客户端密钥。通常,这种情况仅适用于服务器端的机密客户端应用程序。需要客户端密钥的 M2M 应用程序也是如此。请将客户端密钥存储在加密的本地存储或 AWS Secrets Manager 中。切勿让您的客户端密钥在公共互联网上暴露可见。

保护其他密钥

您基于 Amazon Cognito 用户池构建的身份验证系统可能会处理私有数据、密码和 AWS 凭证。以下是处理应用程序可能访问的密钥的一些最佳实践。

密码

用户在登录您的应用程序时可能会输入密码。Amazon Cognito 提供刷新令牌,您的应用程序可以使用这些令牌在没有新密码提示的情况下继续使用过期的用户会话。不要在本地存储中放置任何密码或密码哈希。设计您的应用程序时,应将密码视为不透明数据,仅将其传递至用户池。

最佳实践是使用 WebAuthn 通行密钥实现无密码身份验证。如果您必须使用密码,请使用安全远程密码(SRP)身份验证流程多重身份验证(MFA)

AWS 凭证

管理身份验证和用户池管理操作需要使用 AWS 凭证进行身份验证。要在应用程序中实现这些操作,请授予对临时 AWS 凭证的安全访问权限。仅向在您控制的服务器组件上运行的应用程序授予凭证访问权限。请勿将包含 AWS 凭证的应用程序放在公共版本控制系统(例如 GitHub)上。请勿在公开的客户端应用程序中硬编码 AWS 凭证。

PKCE 代码验证程序

代码交换证明密钥(PKCE)用于通过用户池授权服务器进行的 OpenID Connect(OIDC)授权码授予流程。当应用程序请求授权码时,它们会与您的用户池共享代码验证程序密钥。要将授权码交换为令牌,客户端必须重新确认其知晓该代码验证程序。这种做法可以防止颁发带有被拦截的授权码的令牌。

客户端必须针对每个授权请求生成一个新的随机代码验证程序。使用静态或可预测的代码验证程序意味着攻击者只需拦截硬编码的验证程序和授权码即可。设计您的应用程序时,应确保不向用户暴露代码验证程序的值。

用户池管理最低权限

IAM 策略可以定义主体对 Amazon Cognito 用户池管理和管理身份验证操作的访问级别。例如:

  • 对于 Web 服务器,授予使用管理 API 操作进行身份验证的权限。

  • 对于管理您的 AWS 账户中用户池的 AWS IAM Identity Center 用户,授予用户池维护和报告的权限。

在 IAM 策略中,Amazon Cognito 的资源粒度仅限于两种资源类型:用户池和身份池。请注意,您无法针对单个应用程序客户端设置管理权限。在配置用户池时需知晓,您授予的权限对于所有应用程序客户端均有效。如果您的组织拥有多个应用程序租户,并且您的安全模型要求在租户之间分离管理职责,则可以实施每个用户池一个租户的多租户架构

尽管您可以创建包含用户身份验证操作(如 InitiateAuth)权限的 IAM 策略,但这些权限实际上不会生效。公开的以及令牌授权的 API 操作不受 IAM 权限的约束。在可用的用户池身份验证操作中,您只能向管理类 服务器端操作(例如 AdminInitiateAuth)授予权限。

您可以使用最低权限 Action 列表来限制用户池的管理级别。以下示例策略适用于可以管理 IdP、资源服务器、应用程序客户端和用户池域,但无法管理用户或用户池的管理员。

JSON
{ "Version":"2012-10-17", "Statement": [ { "Sid": "UserPoolClientAdministrator", "Action": [ "cognito-idp:CreateIdentityProvider", "cognito-idp:CreateManagedLoginBranding", "cognito-idp:CreateResourceServer", "cognito-idp:CreateUserPoolDomain", "cognito-idp:DeleteIdentityProvider", "cognito-idp:DeleteResourceServer", "cognito-idp:DeleteUserPoolDomain", "cognito-idp:DescribeIdentityProvider", "cognito-idp:DescribeManagedLoginBranding", "cognito-idp:DescribeManagedLoginBrandingByClient", "cognito-idp:DescribeResourceServer", "cognito-idp:DescribeUserPool", "cognito-idp:DescribeUserPoolClient", "cognito-idp:DescribeUserPoolDomain", "cognito-idp:GetIdentityProviderByIdentifier", "cognito-idp:GetUICustomization", "cognito-idp:ListIdentityProviders", "cognito-idp:ListResourceServers", "cognito-idp:ListUserPoolClients", "cognito-idp:ListUserPools", "cognito-idp:SetUICustomization", "cognito-idp:UpdateIdentityProvider", "cognito-idp:UpdateManagedLoginBranding", "cognito-idp:UpdateResourceServer", "cognito-idp:UpdateUserPoolClient", "cognito-idp:UpdateUserPoolDomain" ], "Effect": "Allow", "Resource": "arn:aws:cognito-idp:us-west-2:123456789012:userpool/us-west-2_EXAMPLE" } ] }

以下示例策略为服务器端应用程序授予用户和组管理以及身份验证权限。

JSON
{ "Version":"2012-10-17", "Statement": [ { "Sid": "UserAdminAuthN", "Action": [ "cognito-idp:AdminAddUserToGroup", "cognito-idp:AdminConfirmSignUp", "cognito-idp:AdminCreateUser", "cognito-idp:AdminDeleteUser", "cognito-idp:AdminDeleteUserAttributes", "cognito-idp:AdminDisableProviderForUser", "cognito-idp:AdminDisableUser", "cognito-idp:AdminEnableUser", "cognito-idp:AdminForgetDevice", "cognito-idp:AdminGetDevice", "cognito-idp:AdminGetUser", "cognito-idp:AdminInitiateAuth", "cognito-idp:AdminLinkProviderForUser", "cognito-idp:AdminListDevices", "cognito-idp:AdminListGroupsForUser", "cognito-idp:AdminListUserAuthEvents", "cognito-idp:AdminRemoveUserFromGroup", "cognito-idp:AdminResetUserPassword", "cognito-idp:AdminRespondToAuthChallenge", "cognito-idp:AdminSetUserMFAPreference", "cognito-idp:AdminSetUserPassword", "cognito-idp:AdminSetUserSettings", "cognito-idp:AdminUpdateAuthEventFeedback", "cognito-idp:AdminUpdateDeviceStatus", "cognito-idp:AdminUpdateUserAttributes", "cognito-idp:AdminUserGlobalSignOut", "cognito-idp:AssociateSoftwareToken", "cognito-idp:ListGroups", "cognito-idp:ListUsers", "cognito-idp:ListUsersInGroup", "cognito-idp:RevokeToken", "cognito-idp:UpdateGroup", "cognito-idp:VerifySoftwareToken" ], "Effect": "Allow", "Resource": "arn:aws:cognito-idp:us-west-2:123456789012:userpool/us-west-2_EXAMPLE" } ] }

保护和验证令牌

令牌可以包含对组成员资格的内部引用,以及您可能不想向最终用户披露的用户属性。请勿将 ID 令牌和访问令牌存储在本地存储中。刷新令牌使用只有您的用户池才能访问的密钥进行加密,并且对用户和应用程序不透明。当用户注销或您出于安全原因认为不应该持久化用户会话时,请撤销刷新令牌

使用访问令牌,仅向独立验证令牌有效且未过期的系统授予访问权限。有关验证资源,请参阅验证 JSON Web 令牌

确定要信任的身份提供者

当您使用 SAMLOIDC 身份提供者(IdP)配置用户池时,您的 IdP 可以创建新用户、设置用户属性并访问您的应用程序资源。SAML 和 OIDC 提供商通常用于企业对企业(B2B)或企业级场景中,在这些场景中,您或您的直属客户控制提供商的成员资格和配置。

社交提供商向互联网上的任何人提供用户账户,且相比企业级提供商,您对其的控制力较弱。只有当您准备好允许公众客户登录和访问应用程序中的资源时,才能在应用程序客户端中激活社交 IdP。

了解作用域对用户配置文件访问的影响

您可以在向用户池授权服务器发起的身份验证请求中申请访问控制作用域。这些作用域可以授予您的用户访问外部资源的权限,也可以授予用户查看和修改自己的用户配置文件的权限。配置应用程序客户端,使其支持应用程序运行所需的最小范围。

aws.cognito.signin.user.admin 作用域存在于 SDK 身份验证通过诸如 InitiateAuth 的操作颁发的所有访问令牌中。它专为应用程序中的用户配置文件自助操作而设计。您也可以从授权服务器申请此作用域。此作用域是 UpdateUserAttributesGetUser 等令牌授权操作所必需的。这些操作的效果受应用程序客户端的读取和写入权限的限制。

openidprofileemailphone 作用域用于授权向用户池授权服务器上的 userInfo 端点发起的请求。它们定义了端点可返回的属性。当仅请求 openid 作用域(不包含其他作用域)时,会返回所有可用的属性;但当请求中包含其他作用域时,响应将被限制为仅包含这些额外作用域所对应的属性。openid 作用域还表示请求 ID 令牌;如果在向 对端点授权发起的请求中省略此作用域,Amazon Cognito 将仅颁发访问令牌,以及在适用时颁发刷新令牌。有关更多信息,请参阅应用程序客户端术语中的 OpenID Connect 作用域

清理用户属性的输入

可能用作分发方式和用户名的用户属性(例如 email)具有格式限制。其他属性则可使用字符串、布尔值或数字数据类型。字符串类型的属性值支持多种输入形式。请配置您的应用程序,防止恶意数据写入用户目录或 Amazon Cognito 向用户发送的消息。在将用户提交的字符串属性值提交至 Amazon Cognito 之前,请在应用程序中对其进行客户端验证。

用户池会根据您指定的属性映射,将 IdP 的属性映射到您的用户池中。请仅将安全且可预测的 IdP 属性映射到用户池的字符串类型属性。