基本情報
ユーザープールは、Amazon Cognitoのユーザーディレクトリです。ユーザープールを使用すると、ユーザーはAmazon Cognitoを通じてウェブまたはモバイルアプリにサインイン したり、サードパーティ のアイデンティティプロバイダー(IdP)を通じてフェデレーション したりできます。ユーザーが直接サインインするか、サードパーティを通じてサインインするかにかかわらず、ユーザープールのすべてのメンバーには、SDKを通じてアクセスできるディレクトリプロファイルがあります。
ユーザープールは以下を提供します:
ユーザーをサインインさせるための組み込みのカスタマイズ可能なウェブUI。
Facebook、Google、Amazonでのログイン、Appleでのサインイン、SAMLおよびOIDCアイデンティティプロバイダーを通じたソーシャルサインイン。
ユーザーディレクトリ管理およびユーザープロファイル。
多要素認証(MFA)、侵害された資格情報のチェック、アカウント乗っ取り防止、電話およびメールの検証などのセキュリティ機能。
AWS Lambdaトリガーを通じたカスタマイズされたワークフローおよびユーザー移行。
アプリケーションのソースコード には通常、ユーザープールID およびクライアントアプリケーションID (および場合によってはアプリケーションシークレット ?)が含まれており、これらはユーザーがCognitoユーザープールにログインする ために必要です。
潜在的な攻撃
登録 :デフォルトでは、ユーザーは自分自身を登録できるため、自分用のユーザーを作成できます。
ユーザー列挙 :登録機能を使用して、既に存在するユーザー名を見つけることができます。この情報はブルートフォース攻撃に役立ちます。
ログインブルートフォース :認証 セクションには、ユーザーがログイン するためのすべての方法 が記載されており、それらをブルートフォースして有効な資格情報を見つける ことができます。
ペンテスト用ツール
Pacu は、cognito__enum
およびcognito__attack
モジュールを含むようになり、アカウント内のすべてのCognito資産の列挙を自動化し、弱い構成、アクセス制御に使用されるユーザー属性などをフラグ付けし、ユーザー作成(MFAサポートを含む)および変更可能なカスタム属性に基づく特権昇格を自動化します。
モジュールの機能の説明については、ブログ投稿 のパート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
Cognito Scanner は、不要なアカウント作成やアカウントオラクルを含むCognitoに対するさまざまな攻撃を実装したPythonのCLIツールです。詳細についてはこのリンク を確認してください。
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
)が使用されているのを見つけるかもしれません。デフォルトでは、自分の属性の値を変更できるため 、自分で値を変更することで特権を昇格させる ことができるかもしれません!
メール/ユーザー名の変更による特権昇格
これを使用して、ユーザーのメールアドレスと電話番号を変更 できますが、その後、アカウントが確認済みのままであっても、これらの属性は未確認の状態に設定されます (再度確認する必要があります)。
メールアドレスまたは電話番号でログインできなくなります が、ユーザー名でログインすることは可能です 。
メールが変更されて未確認であっても、email
フィールド 内のIDトークンに表示され、フィールド**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
の代わりに使用して 新しい電話番号 を変更/確認します。
管理者はまた、ユーザーが好むユーザー名でログインする オプションを有効にすることもできます。この値を 他のユーザーを偽装するために既に使用されている任意のユーザー名またはpreferred_username に変更することはできないことに注意してください。
パスワードの回復/変更
ユーザー名(またはメールまたは電話が受け入れられます)を知っているだけでパスワードを回復することが可能であり、そこにコードが送信されるため、アクセスが必要です。
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トークンは、ユーザーの属性値を含むトークン であり、カスタム属性も含まれます。
アクセストークン : これは、認証されたユーザーに関するクレーム、ユーザーのグループのリスト 、およびスコープのリスト を含んでいます。アクセストークンの目的は、ユーザープール内のユーザーのコンテキストで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操作 を呼び出します。AdminRespondToAuthChallenge
API操作は、AWS資格情報を提供した場合にのみ成功します。
この方法はデフォルトでは有効になっていません 。
ログインするためには 、以下を知っている必要があります:
クライアントシークレット(アプリがシークレットを使用するように構成されている場合のみ)
この方法でログインできるようにするためには 、そのアプリケーションが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>'