

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

# Amazon Cognito 用户池安全最佳实践
<a name="user-pool-security-best-practices"></a>

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

## 在网络层面保护您的用户池
<a name="user-pool-security-best-practices-network"></a>

Amazon WAF web ACLs 可以保护您使用 Amazon Cognito 构建的身份验证机制的性能和成本。借助 Web ACLs，您可以在 API 和托管登录请求之前实施防护措施。Web ACLs 创建网络层和应用层过滤器，这些过滤器可以根据您设计的规则丢弃流量或要求使用验证码。只有在请求满足您的 Web ACL 规则中的条件后，才会传递到您的 Amazon Cognito 资源。有关更多信息，请参阅 [Amazon WAF web ACLs](user-pool-waf.md)。

## 防止短信滥用
<a name="user-pool-security-best-practices-sms"></a>

如果您允许在用户池中进行公开注册，则可以使用 Amazon Cognito 以短信形式发送的代码来配置账户验证。SMS 消息可能与不想要的活动相关联，从而增加您的 Amazon 账单。请配置您的基础设施，使其在遭遇欺诈时具备抵御能力，避免发送短信。有关更多信息，请查看 Amazon 博客中的以下帖子。
+ [Reduce risks of user sign-up fraud and SMS pumping with Amazon Cognito user pools](https://www.amazonaws.cn/blogs/security/reduce-risks-of-user-sign-up-fraud-and-sms-pumping-with-amazon-cognito-user-pools/)
+ [防范短信抽水：新 Amazon 功能可帮助抵御人为膨胀的流量](https://www.amazonaws.cn/blogs/messaging-and-targeting/defending-against-sms-pumping-new-aws-features-to-help-combat-artificially-inflated-traffic/)

## 了解公共身份验证
<a name="user-pool-security-best-practices-public-operations"></a>

Amazon Cognito 用户池具有客户身份和访问管理（CIAM）功能，支持面向公众的使用案例，即用户可自行注册账户并访问您的应用程序。当用户池允许自助注册时，它将接受来自公共互联网的用户账户请求。自助服务请求来自和之类的 API 操作 [InitiateAuth](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)，[SignUp](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_SignUp.html)以及用户与托管登录的交互。您可以配置用户池以减少可能来自公共请求的滥用行为，或者完全禁用公共身份验证操作。

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


**影响公共用户池访问的用户池设置示例**  

| 设置 | 可用选项 | 配置位置 | 对公共身份验证的影响 | 控制台设置 | API 操作和参数 | 
| --- | --- | --- | --- | --- | --- | 
| [自助注册](user-pool-settings-admin-create-user-policy.md) | 允许用户以管理员身份注册账户或创建用户账户。 | 用户池 | 阻止公开注册 | 注册 - 自助注册 |  [CreateUserPool](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html#CognitoUserPools-CreateUserPool-request-AdminCreateUserConfig), [UpdateUserPool](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html#CognitoUserPools-UpdateUserPool-request-AdminCreateUserConfig) `AdminCreateUserConfig` – `AllowAdminCreateUserOnly`  | 
| [管理员确认](signing-up-users-in-your-app.md#signing-up-users-in-your-app-and-confirming-them-as-admin) | 向新用户发送确认码或要求管理员进行确认。 | 用户池 | 防止在没有管理员操作的情况下确认注册 | 注册 - Cognito 辅助验证和确认 |  [CreateUserPool](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPool.html#CognitoUserPools-CreateUserPool-request-AccountRecoverySetting), [UpdateUserPool](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPool.html#CognitoUserPools-UpdateUserPool-request-AccountRecoverySetting) `AccountRecoverySettings` – `admin_only`  | 
| [用户披露](cognito-user-pool-managing-errors.md) | 在登录和密码重置时发送“未找到用户”消息，或者防止披露。 | 应用程序客户端 | 防止猜测登录名、电子邮件地址或电话号码 | 应用程序客户端 - 防止用户已存在错误 |  [CreateUserPoolClient](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html#CognitoUserPools-CreateUserPoolClient-request-PreventUserExistenceErrors), [UpdateUserPoolClient](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html#CognitoUserPools-UpdateUserPoolClient-request-PreventUserExistenceErrors) `PreventUserExistenceErrors`  | 
| [客户端密钥](user-pool-settings-client-apps.md#user-pool-settings-client-app-client-types) | 注册、登录、重置密码时需要或不需要密钥哈希 | 应用程序客户端 | 防范来自未经授权来源的身份验证请求 | 应用程序客户端 - 客户端密钥 |  [CreateUserPoolClient](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html#CognitoUserPools-CreateUserPoolClient-request-GenerateSecret) `GenerateSecret`  | 
| [Web ACLs](user-pool-waf.md) | 针对身份验证请求启用或不启用网络防火墙 | 用户池 | 根据管理员定义的请求特征和 IP 地址规则限制或阻止访问 | Amazon WAF – WAF 设置 |  [AssociateWebACL](https://docs.amazonaws.cn/waf/latest/APIReference/API_AssociateWebACL.html#WAF-AssociateWebACL-request-ResourceArn) `ResourceArn`  | 
| [外部 IdP](cognito-user-pools-identity-provider.md) | 允许用户在第三方 IdPs、用户池目录或两者中登录 | 应用程序客户端 | 排除[本地用户](cognito-terms.md#terms-localuser)或[联合用户](cognito-terms.md#terms-federateduser)进行注册和登录。 | 应用程序客户端 - 身份提供者 |  [CreateUserPoolClient](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolClient.html#CognitoUserPools-CreateUserPoolClient-request-SupportedIdentityProviders), [UpdateUserPoolClient](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html#CognitoUserPools-UpdateUserPoolClient-request-SupportedIdentityProviders) `SupportedIdentityProviders`  | 
| [授权服务器](cognito-user-pools-assign-domain.md) | 托管或不托管用于身份验证的公开网页 | 用户池 | 关闭公开网页，只允许基于 SDK 的身份验证 | 域： |  [CreateUserPoolDomain](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_CreateUserPoolDomain.html) 创建任何用户池域都会使公开网页变得可用。  | 
| [威胁防护](cognito-user-pool-settings-threat-protection.md) | 启用或禁用对恶意活动迹象或不安全密码的监控 | 用户池或应用程序客户端 | 当用户显示泄露迹象时，可以自动阻止登录或要求进行 MFA | 威胁防护 - 保护设置 |  [SetRiskConfiguration](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_SetRiskConfiguration.html) `SetRiskConfiguration` 的参数用于定义您的威胁防护设置。  | 

## 使用客户端密钥保护机密客户端
<a name="user-pool-security-best-practices-client-secret"></a>

客户端密钥是与[应用程序客户端](user-pool-settings-client-apps.md)关联的可选字符串。向具有客户端密钥的应用程序客户端发出的所有身份验证请求，都必须包含由用户名、客户端 ID 和客户端密钥生成的[密钥哈希](signing-up-users-in-your-app.md#cognito-user-pools-computing-secret-hash)。那些不知道客户端密钥的用户从一开始就被应用程序拒之门外。

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

## 保护其他密钥
<a name="user-pool-security-best-practices-manage-secrets"></a>

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

**密码**  
用户在登录您的应用程序时可能会输入密码。Amazon Cognito 提供刷新令牌，您的应用程序可以使用这些令牌在没有新密码提示的情况下继续使用过期的用户会话。不要在本地存储中放置任何密码或密码哈希。设计您的应用程序时，应将密码视为不透明数据，仅将其传递至用户池。  
[最佳做法是使用密钥实现无密码身份验证。WebAuthn](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-passkey)如果您必须使用密码，请使用[安全远程密码（SRP）身份验证流程](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-srp)和[多重身份验证（MFA）](amazon-cognito-user-pools-authentication-flow-methods.md#amazon-cognito-user-pools-authentication-flow-methods-mfa)。

**Amazon 证书**  
管理身份验证和用户池管理操作需要使用 Amazon 凭据进行身份验证。要在应用程序中实现这些操作，请授予对[临时 Amazon 证书](https://docs.amazonaws.cn/IAM/latest/UserGuide/id_credentials_temp.html)的安全访问权限。仅向在您控制的服务器组件上运行的应用程序授予凭证访问权限。不要将包含 Amazon 凭据的应用程序放在公共版本控制系统上，例如。 GitHub不要在公共客户端应用程序中对 Amazon 凭据进行编码。

**PKCE 代码验证程序**  
[代码交换证明密钥（PKCE）](using-pkce-in-authorization-code.md)用于通过用户池授权服务器进行的 OpenID Connect（OIDC）授权码授予流程。当应用程序请求授权码时，它们会与您的用户池共享代码验证程序密钥。要将授权码交换为令牌，客户端必须重新确认其知晓该代码验证程序。这种做法可以防止颁发带有被拦截的授权码的令牌。  
客户端必须针对每个授权请求生成一个新的随机代码验证程序。使用静态或可预测的代码验证程序意味着攻击者只需拦截硬编码的验证程序和授权码即可。设计您的应用程序时，应确保不向用户暴露代码验证程序的值。

## 用户池管理最低权限
<a name="user-pool-security-best-practices-least-privilege"></a>

IAM 策略可以定义主体对 Amazon Cognito 用户池管理和管理身份验证操作的访问级别。例如：
+ 对于 Web 服务器，授予使用管理 API 操作进行身份验证的权限。
+ 对于管理您的 Amazon IAM Identity Center 用户池的用户 Amazon Web Services 账户，请授予用户池维护和报告的权限。

在 IAM 策略中，Amazon Cognito 的资源粒度仅限于[两种资源类型](https://docs.amazonaws.cn/service-authorization/latest/reference/list_amazoncognitoidentity.html#amazoncognitoidentity-resources-for-iam-policies)：用户池和身份池。请注意，您无法针对单个应用程序客户端设置管理权限。在配置用户池时需知晓，您授予的权限对于所有应用程序客户端均有效。如果您的组织拥有多个应用程序租户，并且您的安全模型要求在租户之间分离管理职责，则可以实施[每个用户池一个租户的多租户架构](bp_user-pool-based-multi-tenancy.md)。

尽管您可以创建包含用户身份验证操作（如 `InitiateAuth`）权限的 IAM 策略，但这些权限实际上不会生效。[公开的以及令牌授权的 API 操作](authentication-flows-public-server-side.md)不受 IAM 权限的约束。在可用的用户池身份验证操作中，您只能向*管理类* 服务器端操作（例如 `AdminInitiateAuth`）授予权限。

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

------
#### [ 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"
    }
  ]
}
```

------

## 保护和验证令牌
<a name="user-pool-security-best-practices-secure-tokens"></a>

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

使用访问令牌，仅向独立验证令牌有效且未过期的系统授予访问权限。有关验证资源，请参阅[验证 JSON Web 令牌](amazon-cognito-user-pools-using-tokens-verifying-a-jwt.md)。

## 确定要信任的身份提供者
<a name="user-pool-security-best-practices-trusted-idps"></a>

使用 [SAML](cognito-user-pools-saml-idp.md) 或 [OIDC](cognito-user-pools-oidc-idp.md) 身份提供商 (IdPs) 配置用户池时， IdPs 您可以创建新用户、设置用户属性和访问您的应用程序资源。SAML 和 OIDC 提供商通常用于 business-to-business (B2B) 或企业场景，在这种场景中，您或您的直接客户控制提供商的成员资格和配置。

[社交提供商](cognito-user-pools-social-idp.md)向互联网上的任何人提供用户账户，且相比企业级提供商，您对其的控制力较弱。只有当你准备好允许公众客户登录和访问应用程序 IdPs 中的资源时，才能在应用程序客户端中激活 social。

## 了解作用域对用户配置文件访问的影响
<a name="user-pool-security-best-practices-scopes"></a>

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

该`aws.cognito.signin.user.admin`作用域存在于 SDK 身份验证通过以下操作颁发的所有访问令牌中[InitiateAuth](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html)。它专为应用程序中的用户配置文件自助操作而设计。您也可以从授权服务器申请此作用域。此作用域是令牌授权的操作（如和）所必需的。[UpdateUserAttributes[GetUser](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_GetUser.html)](https://docs.amazonaws.cn/cognito-user-identity-pools/latest/APIReference/API_UpdateUserAttributes.html)这些操作的效果受应用程序客户端的读取和写入权限的限制。

`openid`、`profile`、`email` 和 `phone` 作用域用于授权向用户池授权服务器上的 [userInfo 端点](userinfo-endpoint.md)发起的请求。它们定义了端点可返回的属性。当仅请求 `openid` 作用域（不包含其他作用域）时，会返回所有可用的属性；但当请求中包含其他作用域时，响应将被限制为仅包含这些额外作用域所对应的属性。`openid` 作用域还表示请求 ID 令牌；如果在向 [对端点授权](authorization-endpoint.md)发起的请求中省略此作用域，Amazon Cognito 将仅颁发访问令牌，以及在适用时颁发刷新令牌。有关更多信息，请参阅[应用程序客户端术语](user-pool-settings-client-apps.md#cognito-user-pools-app-idp-settings-about)中的 **OpenID Connect 作用域**。

## 清理用户属性的输入
<a name="user-pool-security-best-practices-sanitize-inputs"></a>

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

用户池根据您指定的属性映射将[属性从映射 IdPs ](cognito-user-pools-specifying-attribute-mapping.md)到您的用户池。请仅将安全且可预测的 IdP 属性映射到用户池的字符串类型属性。