はじめに

はじめまして。デザイン&エンジニアリング部の鎌田です。

Spring Security、Amazon Cognito(以下Cognito)、AWS Lambda(以下Lambda)を組み合わせたカスタム二段階認証の実装は、複雑な処理が数多く組み合わさっています。

この記事では、実際にこの機能を構築する中で得られた知見を基に、認証処理がどのように行われるのか、各コンポーネントの連携とその詳細な流れについて、具体的な例を交えて解説していきます。

 

※ 2024年9月13日、Amazon Cognito ユーザープールが多要素認証 (MFA) オプションとしてメールの提供を開始しました。
https://aws.amazon.com/jp/about-aws/whats-new/2024/09/amazon-cognito-user-pools-email-authentication-option/

Cognitoの新しい機能を活用することで、本記事で採用したカスタム認証より簡単にメールによる二段階認証を導入できる可能性があります。
本記事では、Lambdaでどのようにメール送信による認証を実装していたのか、その具体的なコードを付録に掲載していますので必要に応じて参考にしていただければと思います。

この記事を読む前に

この記事では、以下の基礎知識がある読者を対象としています。

  • Spring Securityについて
  • Cognito/Lambda、特にこの二つを用いたカスタム認証について
    • Lambdaの実装内容については、付録に記載しています。必要に応じてご確認ください。
  • 二段階認証と二要素認証の違い

今回は主に処理の流れを説明することに重きを置いているため、これらの基本的な説明については割愛させていただきますのでご了承ください。

使用している技術要素

本実装に使用している技術要素を以下に示します。特に使用しているSDKが1.x系であるため、2.x系と実装内容が異なる場合があることに留意してください。

ソフトウェア 種類及びバージョン
Java OpenJDK 17
Spring Boot 3.3.0
AWS SDK 1.12.728
Python 3.12

システム全体の処理の流れ

カスタム二段階認証システムの全体的な処理フローを5つの主要なパターンに分けて説明します。

    一段階目の認証(成功)

    ユーザーが正しいIDとパスワードを入力して認証に成功した場合の処理フローを説明します。

    1. ID/PASSWORD送信

      • ユーザーがブラウザからIDとパスワードを入力し、アプリケーションに送信します。
      • アプリケーションは、受信したIDとパスワードをCognitoに送信し、ユーザーの認証を行います。
    2. 一段階目の認証

      • Cognitoは、認証結果をアプリケーションに返します。
      • 入力されたIDとパスワードが正しい場合、認証は成功と判断されます。
    3. 二段階認証コードの生成

      • 認証が成功すると、Lambda関数がトリガーされ、二段階認証コードとしてランダムな数字6桁を生成します。
    4. 二段階認証コードの送信

      • 生成されたコードは、Amazon Simple Email Service(以下SES)を利用して、ユーザーにメールで送信されます。
    5. Cognitoセッション情報の保存

      • 認証成功後、アプリケーションはCognitoのセッション情報をデータベースに保存します。この情報は、以降の認証処理で利用されます。
    6. 二段階認証画面への遷移

      • アプリケーションは、ユーザーに二段階認証コードを入力するための画面を表示します。

    一段階目の認証(失敗)

    ユーザーが誤ったIDまたはパスワードを入力して認証に失敗した場合の処理フローを説明します。

    1. ID/PASSWORD送信

      • ユーザーがブラウザからIDとパスワードを入力し、アプリケーションに送信します。
      • アプリケーションは、受信したIDとパスワードをCognitoに送信し、ユーザーの認証を行います。
    2. 一段階目の認証

      • Cognitoは、認証結果をアプリケーションに返します。
      • 今回のケースでは、認証が失敗したためエラーが返されます。
    3. ログインページへのリダイレクト

      • アプリケーションは、認証失敗の結果を受け取り、ユーザーを再度ログインページにリダイレクトします。

    二段階目の認証(成功)

    ユーザーが正しい二段階認証コードを入力して認証に成功した場合の処理フローを説明します。

    1. 二段階認証コード送信(ユーザー)

      • ユーザーが、メールで受信した二段階認証コードをアプリケーションに入力します。
    2. Cognitoセッション情報取得

      • アプリケーションは、データベースから一段階目の認証成功時に保存したセッション情報を取得します。
    3. 二段階認証コード送信(アプリケーション)

      • アプリケーションは、セッション情報と受信した二段階認証コードをCognitoへ送信します。
    4. 二段階目の検証

      • Cognitoは、認証結果をアプリケーションに返します。
      • 入力されたコードが正しい場合、二段階認証が成功と判断されます。
    5. 認証成功

      • アプリケーションは、認証成功の結果を受け取ります。
    6. Cognitoセッション情報の更新

      • 認証が成功すると、データベース上に保存してあるCognitoのセッション情報及び最終ログイン日時が更新されます。
    7. ホーム画面への遷移:

      • 認証が成功すると、ユーザーは認証成功後の画面へ遷移します。

    二段階目の認証(失敗/認証コードが異なる)

    ユーザーが誤った二段階認証コードを入力した場合の処理フローを説明します。

    1. 二段階認証コード送信(ユーザー)

      • ユーザーが、メールで受信した二段階認証コードをアプリケーションに入力します。
    2. Cognitoセッション情報取得

      • アプリケーションは、データベースから一段階目の認証成功時に保存したセッション情報を取得します。
    3. 二段階認証コード送信(アプリケーション)

      • アプリケーションは、セッション情報と受信した二段階認証コードをCognitoへ送信します。
    4. 二段階目の検証

      • Cognitoは、認証結果をアプリケーションに返します。
      • 入力されたコードが誤っている場合、二段階認証が失敗と判断されます。
    5. 認証失敗

      • アプリケーションは、認証失敗の結果を受け取ります。
    6. Cognitoセッション情報保存

      • 再度二段階認証コードが入力できるよう、認証失敗後もCognitoのセッション情報はデータベースに保持されます。
    7. 再度二段階認証画面を表示

      • アプリケーションは、ユーザーに再度二段階認証コードを入力するメッセージと共に二段階認証画面を表示します。

    二段階目の認証(失敗/認証コードの有効期限切れ)

    ユーザーが有効期限切れの二段階認証コードを入力した場合の処理フローを説明します。

     

    1. 二段階認証コード送信(ユーザー)

      • ユーザーが、メールで受信した二段階認証コードをアプリケーションに入力します。
    2. Cognitoセッション情報取得

      • アプリケーションは、データベースから一段階目の認証成功時に保存したセッション情報を取得します。
    3. 二段階認証コード送信(アプリケーション)

      • アプリケーションは、セッション情報と受信した二段階認証コードをCognitoへ送信します。
    4. 二段階認証コード検証:

      • Cognitoは、認証結果をアプリケーションに返します。
      • 今回はコードの有効期限が切れているため、入力したコードに関わらず二段階認証が失敗と判断されます。
    5. 認証失敗:

      • アプリケーションは、認証失敗の結果を受け取ります。
    6. ログインページへ遷移:

      • 認証処理をはじめから再実施する必要があるため、ユーザーをログインページにリダイレクトします。