はじめに
AWS上でWEBアプリケーション構築する際にAWS AmplifyとAmazon Cognitoを利用するケース多いと思います。公式チュートリアルの設定ではログイン識別子(ログインIDやEmail)がCookie(本記事ではローカルストレージ、セッションストレージ等も含む)上に残ってしまうことに気付いたので、その解決策を共有します。
対象読者
- AWS AmplifyとAmazon Cognitoを使ってアプリケーション構築をしている方
- セキュリティの監査要件としてログインIDやEmail情報をCookie上に残さない設定が求められている方
事象
Amplify Gen2の公式ドキュメントに従って、defineAuthライブラリを使って認証を実装したところ、CognitoIdentityServiceProviderで始まるレコードがCookie(ローカルストレージ)上に生成されます。
そのうちの一つのCognitoIdentityServiceProvider.{英数字列}.signinDetailsというキーの中にログインID(ログイン識別子なのでEmail等のケースあり)が保存されます。
(手元環境にあるGen1時代のアプリケーションでも確認してみましたが、同様にsinginDetailsキー内にログインIDが保存されていました)
例:ローカルストレージにログインユーザーのEmailが保存される例

解決策
Amplifyライブラリにはカスタムストレージの設定機能があり、ログイン時の認証トークン情報をコントロールすることができます。
力技ですがsetItemメソッドにおいて、signinDetailsキーをスキップするような実装を行うことで、ログインIDがCookie上に残ることを防ぐことができます。
import type { KeyValueStorageInterface } from 'aws-amplify/utils';
export class CustomStorage implements KeyValueStorageInterface {
setItem(key: string, value: string): Promise<void> {
// signInDetails が含まれるキーは保存しない (大文字小文字を区別しない)
if (/signInDetails/i.test(key)) {
console.log(`Preventing storage of sensitive key: ${key}`);
return Promise.resolve();
}
localStorage.setItem(key, value);
return Promise.resolve();
}
getItem(key: string): Promise<string | null> {
return Promise.resolve(localStorage.getItem(key));
}
removeItem(key: string): Promise<void> {
localStorage.removeItem(key);
return Promise.resolve();
}
clear(): Promise<void> {
localStorage.clear();
return Promise.resolve();
}
}
/////////////////////////////////////////////////////
// ここから呼び出す側のコード
/////////////////////////////////////////////////////
import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
cognitoUserPoolsTokenProvider.setKeyValueStorage(new MyCustomStorage());
最後に
Cookieにメールアドレスが残ってしまうと、
- ユーザーが学校設置の共有端末等を使っていた場合に、他人が意図せず閲覧してしまう可能性がある
- XSS等により悪意のあるスクリプトが実行され、Cookie情報を窃取
といったリスクが考えられます。
本トピックで取り上げたsinginDetailsキーを削除しても問題なく動作しましたので、不要かつ重要度が高い情報はなるべくクライアントに残さないことが望ましいはずです。
業務レベルでAmplify × Cognitoアプリケーションを構築している/ご検討いただいている皆様におきましては、留意いただければと思います。