Cognitoを使うとログインID(メールアドレス等)が存在するかどうか判別可能になる
概要
タイトルに書いた以上のことはないのですが、Amazon Cognitoではログイン時のエラーで、ログインIDが存在する場合と存在しない場合が判別可能になります。
知らずに使い始めて、あとで困る人がいると良くないなと思ったので一応書いておきます。
詳細
CognitoはIDaaSとして利用でき、自分でID/PWを管理する必要がなくなるので非常に便利です。
自分で実装すると、パスワードにソルト付けてハッシュ化して...など考えることは多いです。
しかしCognitoを使えばそういう悩みから開放されるため、今開発してるサービスでも利用しています。
ログイン
CognitoはJavascriptから利用する事が多いかと思いますが、awsが提供しているSDKがあるため普通であればこちらを利用するかと思います。 GitHub - aws/amazon-cognito-identity-js: Amazon Cognito Identity SDK for JavaScript
ドキュメントを読むとUse case 4に以下のようなコードがあります。
var authenticationData = {
Username : 'username',
Password : 'password',
};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var poolData = {
UserPoolId : '...', // Your user pool id here
ClientId : '...' // Your client id here
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var userData = {
Username : 'username',
Pool : userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('access token + ' + result.getAccessToken().getJwtToken());
//POTENTIAL: Region needs to be set if not already set previously elsewhere.
AWS.config.region = '<region>';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId : '...', // your identity pool id here
Logins : {
// Change the key below according to the specific region your user pool is in.
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>' : result.getIdToken().getJwtToken()
}
});
//refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity()
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
} else {
// Instantiate aws sdk service objects now that the credentials have been updated.
// example: var s3 = new AWS.S3();
console.log('Successfully logged!');
}
});
},
onFailure: function(err) {
alert(err);
},
});
このauthenticateUserで認証をしています。
Web画面で言うとログイン画面で呼ばれることになるかと思います。
authenticateUser
ではこのauthenticateUserの中を見てみます。
ここの行を見るとAPIとしては initiateAuth を使っているようです(真面目に読んでないので間違っていたらすみません)
initiateAuth
initiateAuthについてはドキュメントがあるので、以下を確認してみます。
そうするとErrorsという項目があり、多くのエラーが定義されていることが分かります。
エラーを見ていくと、NotAuthorizedExceptionという項目があると思います。
説明を見ると、認証失敗時のエラーのようです。
NotAuthorizedException This exception is thrown when a user is not authorized. HTTP Status Code: 400
さらにドキュメントを読んでいくと、UserNotFoundExceptionという項目があります。 説明を読むと、名前から分かる通りユーザが存在しない場合に返されるエラーのようです。
UserNotFoundException This exception is thrown when a user is not found. HTTP Status Code: 400
ということで、Javascriptに返されるエラーからユーザが存在する場合と存在しない場合の判別が可能になります。
ユーザが存在するかどうか、というのは不必要情報にあたります。
メールアドレスの登録チェックが、余計なお世話に?:星野君のWebアプリほのぼの改造計画(8) - @IT
Cognitoではメールアドレスでのログインも可能なので、その場合はサービスに登録済みのメールアドレスか判別可能になってしまいます。
メールアドレスが登録済みか判別可能、というのは脆弱性診断をすると指摘項目になっていることも多いのですが、Cognitoを使っていると指摘されることになります。
スライドの通りログインIDが公開されているようなサイトの場合は気にしなくて良いかと思いますが、メールアドレスをログインIDとして使っていたり、他人に登録していることを知られたくないようなサイトの場合は問題になるかと思います。
www.slideshare.net経緯
何とか設定で出来ないのかと思いサポートに問い合わせさせていただいたところ、「以前は分かれていなかったが、ユーザから判別したいという要望が多かったためエラーを分けた」とのことでした。
歴史的な背景でエラーが分かれたようです。
今も議論されているようで、GitHub Issueから確認できます。
緩和策
ということで現時点では設定でエラーを統一などすることは出来ないようです。
緩和策としてはサポートにも確認させて頂きましたが、サービスユーザに見せるエラーメッセージを統一するぐらいしかなさそうです。
通信を見ればどちらのエラーか判別可能なのでほとんど意味は無いのですが、ライト層にはほんの少し分かりにくくなるかな、という感じです。
まとめ
現時点ではCognitoはログインIDの存在有無を判別可能です。
メールアドレスなどをログインIDとして使ったりなど、判別されると困るケースではCognitoだと要件を満たさない可能性があります。
自分は知らずに使っていて、あとで少し困ったので誰かの助けになればと思います。