基本信息
用户池是 Amazon Cognito 中的用户目录。通过用户池,您的用户可以通过 Amazon Cognito 登录到您的网页或移动应用 ,或通过 第三方 身份提供者 (IdP) 联合 。无论您的用户是直接登录还是通过第三方,用户池的所有成员都有一个可以通过 SDK 访问的目录配置文件。
用户池提供:
通过 Facebook、Google、Amazon 登录和 Apple 登录的社交登录,以及通过用户池中的 SAML 和 OIDC 身份提供者。
安全功能,如多因素身份验证 (MFA)、对被泄露凭证的检查、账户接管保护,以及电话和电子邮件验证。
通过 AWS Lambda 触发器自定义工作流和用户迁移。
应用程序的 源代码 通常还会包含 用户池 ID 和 客户端应用程序 ID (有时还有 应用程序密钥 ?),这些都是 用户登录 Cognito 用户池所需的。
潜在攻击
注册 :默认情况下,用户可以自我注册,因此他可以为自己创建一个用户。
用户枚举 :注册功能可用于查找已存在的用户名。这些信息对于暴力攻击可能很有用。
登录暴力攻击 :在 身份验证 部分,您可以找到用户 登录 的所有 方法 ,您可以尝试暴力破解它们以 找到有效凭证 。
渗透测试工具
Pacu ,现在包括 cognito__enum
和 cognito__attack
模块,这些模块自动枚举帐户中的所有 Cognito 资产并标记弱配置、用于访问控制的用户属性等,并且还自动创建用户(包括 MFA 支持)和基于可修改自定义属性、可用身份池凭证、可假设角色的 ID 令牌等的权限提升。
有关模块功能的描述,请参见 博客文章 的第 2 部分。有关安装说明,请参见主 Pacu 页面。
Copy # Run cognito__enum usage to gather all user pools, user pool clients, identity pools, users, etc. visible in the current AWS account
Pacu (new:test) > run cognito__enum
# cognito__attack usage to attempt user creation and all privesc vectors against a given identity pool and user pool client:
Pacu (new:test) > run cognito__attack --username randomuser --email XX+sdfs2@gmail.com --identity_pools
us-east-2:a06XXXXX-c9XX-4aXX-9a33-9ceXXXXXXXXX --user_pool_clients
59f6tuhfXXXXXXXXXXXXXXXXXX@us-east-2_0aXXXXXXX
Copy # Install
pip install cognito-scanner
# Run
cognito-scanner --help
Copy python cognito-attribute-enu.py -client_id 16f1g98bfuj9i0g3f8be36kkrl
注册
User Pools 默认允许 注册新用户 。
Copy aws cognito-idp sign-up --client-id < client-i d > \
--username < usernam e > --password < passwor d > \
--region < regio n > --no-sign-request
如果任何人都可以注册
您可能会发现一个错误,指示您需要提供更多关于用户的详细信息 :
Copy An error occurred (InvalidParameterException) when calling the SignUp operation: Attributes did not conform to the schema: address: The attribute is required
您可以提供所需的详细信息,格式为 JSON,例如:
Copy --user-attributes '[{ "Name" : "email" , "Value" : "carlospolop@gmail.com" } , { "Name" : "gender" , "Value" : "M" } , { "Name" : "address" , "Value" : "street" } , { "Name" : "custom:custom_name" , "Value" : "supername&\"*$" }]'
您还可以使用此功能来枚举现有用户。 当已存在该名称的用户时,错误消息为:
Copy An error occurred (UsernameExistsException) when calling the SignUp operation: User already exists
注意在之前的命令中,自定义属性以 "custom:" 开头 。
还要知道,在注册时,您无法为用户创建新的自定义属性 。您只能为默认属性 (即使它们不是必需的)和指定的自定义属性 赋值。
或者只是测试客户端 ID 是否存在。如果客户端 ID 不存在,则会出现此错误:
Copy An error occurred (ResourceNotFoundException) when calling the SignUp operation: User pool client 3ig612gjm56p1ljls1prq2miut does not exist.
如果只有管理员可以注册用户
您将会发现此错误,您将无法注册或枚举用户:
Copy An error occurred (NotAuthorizedException) when calling the SignUp operation: SignUp is not permitted for this user pool
验证注册
Cognito 允许通过验证用户的 电子邮件或电话号码 来 验证新用户 。因此,在创建用户时,通常至少需要用户名和密码,以及 电子邮件和/或电话号码 。只需设置一个 您控制的 ,这样您就会收到代码来 验证您的 新创建的用户 帐户 ,如下所示:
Copy aws cognito-idp confirm-sign-up --client-id < cliet_i d > \
--username aasdasd2 --confirmation-code < conf_cod e > \
--no-sign-request --region us-east-1
即使看起来你可以使用相同的电子邮件 和电话号码,当你需要验证创建的用户时,Cognito会抱怨使用相同的信息,并且不会让你验证账户 。
权限提升 / 更新属性
默认情况下,用户可以修改其属性的值 ,例如:
Copy aws cognito-idp update-user-attributes \
--region us-east-1 --no-sign-request \
--user-attributes Name=address,Value=street \
--access-token < access toke n >
自定义属性权限提升
您可能会发现使用了自定义属性 (例如isAdmin
),因为默认情况下您可以更改自己属性的值 ,您可能能够通过自己更改值来提升权限 !
邮箱/用户名修改权限提升
您可以使用此功能修改用户的电子邮件和电话号码 ,但是,即使帐户仍然被验证,这些属性也会被设置为未验证状态 (您需要再次验证它们)。
您无法使用电子邮件或电话号码登录 ,直到您验证它们,但您将能够使用用户名登录 。
请注意,即使电子邮件已被修改且未验证,它仍会出现在ID令牌的**email
** 字段 中,并且字段**email_verified
将为 false**,但如果应用程序没有检查,您可能会冒充其他用户 。
此外,请注意,您可以在**name
字段中放入任何内容,只需修改 name属性**。如果应用程序出于某种原因检查 该字段而不是 email
(或任何其他属性),您可能能够冒充其他用户 。
无论如何,如果出于某种原因您将电子邮件更改为您可以访问的新电子邮件,您可以使用您在该电子邮件地址收到的代码确认电子邮件 :
Copy aws cognito-idp verify-user-attribute \
--access-token < access_toke n > \
--attribute-name email --code < cod e > \
--region < regio n > --no-sign-request
使用 phone_number
而不是 email
来更改/验证 新电话号码 。
管理员还可以启用 使用用户首选用户名登录 的选项。请注意,您将无法将此值更改为 任何已被使用的用户名或首选用户名 以冒充其他用户。
恢复/更改密码
只需 知道用户名 (或接受电子邮件或电话)并能够访问它,因为代码将发送到那里,便可以恢复密码:
Copy aws cognito-idp forgot-password \
--client-id < client_i d > \
--username < username/email/phon e > --region < regio n >
服务器的响应总是会是积极的,就像用户名存在一样。您无法使用此方法来枚举用户
使用代码可以更改密码:
Copy aws cognito-idp confirm-forgot-password \
--client-id < client_i d > \
--username < usernam e > \
--confirmation-code < conf_cod e > \
--password < pw d > --region < regio n >
要更改密码,您需要知道之前的密码 :
Copy aws cognito-idp change-password \
--previous-password < valu e > \
--proposed-password < valu e > \
--access-token < valu e >
认证
用户池支持不同的认证方式 。如果您有用户名和密码 ,也支持不同的方法 进行登录。
此外,当用户在池中被认证时,会提供3种类型的令牌 :ID令牌 、访问令牌 和刷新令牌 。
ID令牌 :它包含关于已认证用户身份 的声明,例如name
、email
和phone_number
。ID令牌也可以用于对您的资源服务器或服务器应用程序进行用户认证 。如果您在外部应用程序中使用ID令牌,您必须验证 ID令牌的签名 ,才能信任ID令牌中的任何声明。
ID令牌是包含用户属性值 的令牌,甚至包括自定义属性。
访问令牌 :它包含关于已认证用户的声明、用户组的列表 和作用域的列表 。访问令牌的目的是在用户池中授权API操作 。例如,您可以使用访问令牌授予用户访问 添加、修改或删除用户属性的权限。
刷新令牌 :使用刷新令牌,您可以为用户获取新的ID令牌和访问令牌 ,直到刷新令牌失效 。默认情况下,刷新令牌在您的应用程序用户登录到用户池后30天过期 。当您为用户池创建应用程序时,可以将应用程序的刷新令牌过期时间设置为60分钟到10年之间的任何值 。
ADMIN_NO_SRP_AUTH & ADMIN_USER_PASSWORD_AUTH
这是服务器端认证流程:
服务器端应用程序调用**AdminInitiateAuth
API操作**(而不是InitiateAuth
)。此操作需要具有包括**cognito-idp:AdminInitiateAuth
和 cognito-idp:AdminRespondToAuthChallenge
**权限的AWS凭证。该操作返回所需的认证参数。
在服务器端应用程序获得认证参数 后,它调用**AdminRespondToAuthChallenge
API操作**。只有在提供AWS凭证时,AdminRespondToAuthChallenge
API操作才会成功。
此方法默认情况下未启用 。
要登录 ,您需要 知道:
为了能够使用此方法登录 ,该应用程序必须允许使用ALLOW_ADMIN_USER_PASSWORD_AUTH
进行登录。
此外,要执行此操作,您需要具有**cognito-idp:AdminInitiateAuth
和 cognito-idp:AdminRespondToAuthChallenge
**权限的凭证。
Copy aws cognito - idp admin - initiate - auth \
--client - id < client - id > \
--auth - flow ADMIN_USER_PASSWORD_AUTH \
--region < region > \
--auth - parameters 'USERNAME=<username>,PASSWORD=<password>,SECRET_HASH=<hash_if_needed>'
--user - pool - id "<pool-id>"
# Check the python code to learn how to generate the hsecret_hash
登录代码```python import boto3 import botocore import hmac import hashlib import base64
client_id = "" user_pool_id = "" client_secret = "" username = "" password = ""
boto_client = boto3.client('cognito-idp', region_name='us-east-1')
def get_secret_hash(username, client_id, client_secret): key = bytes(client_secret, 'utf-8') message = bytes(f'{username}{client_id}', 'utf-8') return base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
If the Client App isn't configured to use a secret
just delete the line setting the SECRET_HASH
def login_user(username_or_alias, password, client_id, client_secret, user_pool_id): try: return boto_client.admin_initiate_auth( UserPoolId=user_pool_id, ClientId=client_id, AuthFlow='ADMIN_USER_PASSWORD_AUTH', AuthParameters={ 'USERNAME': username_or_alias, 'PASSWORD': password, 'SECRET_HASH': get_secret_hash(username_or_alias, client_id, client_secret) } ) except botocore.exceptions.ClientError as e: return e.response
print(login_user(username, password, client_id, client_secret, user_pool_id))
Copy </details>
### USER\_PASSWORD\_AUTH
此方法是另一种简单且**传统的用户和密码认证**流程。建议将**传统的**认证方法**迁移到Cognito**,并**建议**随后**禁用**它,改为使用**ALLOW\_USER\_SRP\_AUTH**方法(因为该方法从不通过网络发送密码)。\
此**方法默认情况下未启用**。
与代码中的**前一种认证方法**的主要**区别**在于您**不需要知道用户池ID**,并且您**不需要额外的权限**在Cognito用户池中。
要**登录**,您**需要**知道:
* 客户端ID
* 用户名
* 密码
* 客户端密钥(仅在应用程序配置为使用密钥时)
<div data-gb-custom-block data-tag="hint" data-style='info'>
为了**能够使用此方法登录**,该应用程序必须允许使用ALLOW\_USER\_PASSWORD\_AUTH登录。
</div>
```python
aws cognito-idp initiate-auth --client-id <client-id> \
--auth-flow USER_PASSWORD_AUTH --region <region> \
--auth-parameters 'USERNAME=<username>,PASSWORD=<password>,SECRET_HASH=<hash_if_needed>'
# Check the python code to learn how to generate the secret_hash
REFRESH_TOKEN_AUTH & REFRESH_TOKEN
此方法始终有效 (无法禁用),但您需要拥有有效的刷新令牌。
Copy aws cognito-idp initiate-auth \
--client-id 3ig6h5gjm56p1ljls1prq2miut \
--auth-flow REFRESH_TOKEN_AUTH \
--region us-east-1 \
--auth-parameters 'REFRESH_TOKEN=<token>'