AWS WAFのCAPTCHA認証をページ遷移なしで利用できるようになりました

2023.05.16

初めに

先月のアップデートでリリースされたCAPTCHA統合(CAPTCHA integration)を利用することでページ遷移を挟まずにAWS WAFのCAPTCHA認証を利用可能となったようです。

自分の方でSPA + AWS WAFのCAPTCHA認証の構築をする機会がなかった関係で従来の動作についてはドキュメント等からの推察となってしまいますが、
AWS WAFのCAPTCHAを利用する場合はページ遷移を行うことは必須であったため、React等でSPAを構築しせっかく再読み込みなしで動作可能なサイトを作成してもAWS WAFのCAPTCHAを利用する際は一度遷移を挟む必要があったようです。

今回のリリースされた処理方式をとることでページ遷移の必要がなくなり、実行元の特定のエレメントに対して認証要素を埋め込むことが可能となりました。

試す時間が取れずリリースから少し時間が空いてしまいましたが、まだ当ブログで紹介されていない機能となりますので試してみます。

構成

今回はCloudFront + S3でCloudFrontにWAFを割り当てる設定をしています(図は省略)。

S3にはindex.htmllogin.jsonを設置し、WAFではlogin.jsonにアクセスした際にCAPTCHA認証を行う設定をしています。

設置ファイル内容

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <!--CAPTCHA integrationの画面から取得可能なタグを埋め込む(後述)-->
    <script type="text/javascript" src="https://xxxxxxxxx/jsapi.js" defer></script>
    <script type="text/javascript">
        function showMyCaptcha() {
            var container = document.querySelector("#my-captcha-container");
            
            AwsWafCaptcha.renderCaptcha(container, {
                //CAPTCHA integrationで発行するAPI Keyを埋め込む
                apiKey: "xxxx",
                onSuccess: captchaExampleSuccessFunction,
                onError: captchaExampleErrorFunction,
            });
        }
        
        function captchaExampleSuccessFunction(wafToken) {
            // Use WAF token to access protected resources
            var login = AwsWafIntegration.fetch("https://xxxxx.cloudfront.net/login.json");
            login.then((res)=> console.debug(res));
        }
        
        function captchaExampleErrorFunction(error) {
            console.error(error)
        }
    </script>
</head>
<body>
    <div>
        <input type="button" value="login" onclick="showMyCaptcha()">
    </div>
    <div id="my-captcha-container"></div>
</body>
</html>

login.json

{"result": "Success"}

index.htmlの内容は以下のドキュメントを参考に作成しています。

CAPTCHA統合からアプリに必要な情報を取得する

マネジメントコンソールのAWS WAFのApplication integration内のCAPTCHA integrationタブからタグの取得とAPIキーの発行を行います。

APIキーの発行はGenerate API keyから行い利用するドメインの入力を行います。

しっかり試せてないですが発行時に指定するドメインは取得先ではなくスクリプトの呼び出し元のようで、直接手元でファイルを開くとverifyの読み込みが400 Bad Requestとなり認証パズルは表示されるものの完了しないといった状態になりました。

所定の値が取得できたのでタグはそのままページに埋め込み、APIキーはAwsWafCaptcha.renderCaptcha()のパラメータとして指定します。

なお執筆時点ではドキュメントやマネジメントコンソール上でAPIキーの削除が上見当たらず、そもそもAWS WAFのAPI自体にキーの削除がないので、不要で削除したい場合どうすれば良いかは謎です。

WAF設定

CAPTCHA統合を利用する場合AWS側の設定としては、従来の設定に加え別途キャプチャ統合でAPIキーを発行やアプリ側にタグの埋め込み等が必要となりますがWebACL自体の設定に差異はありません。

CAPTHA統合の設定をしても指定の処理を埋め込まなければ従来の処理を続けることも可能ですので試験的に一部フローの処理のみを書き換え併用することも可能です。

WebACLのルールとしてはlogin.jsonアクセス時にCAPTCHAを行うルールのみを設定しております。

直接アクセス(従来の方式?)

今回追加されたアクセス方式を試す前に、まずはブラウザで直接アクセスして挙動を見てみます。

まずlogin.jsonにアクセスするとCAPTCHA認証のHTMLコンテンツが405 Method not Allowedとして返却されます。

この認証を突破することでCookieのaws-waf-tokenに値が格納され、実際のページに遷移します。

開発者ツールの設定として永続ログを無効化にしている状態でCAPTCHA認証を完了すると、先ほどのアクセス部分の記録が消えているため別のページとしてlogin.jsonが読み込まれていることがわかります。

おそらく従来はこの方式しかなくCAPTCHA認証コンテンツの返却形式上ページ遷移を回避するのが難しかったのではないかなと思います。
(自分が知らないだけでもしかしたら従来から何か方式があったかも知れません)

CATCHA統合を利用した場合のアクセス

index.html表示時はボタンのみが表示されています。

loginボタンをクリックしshowMyCaptcha()を実行することで指定した要素の内容がAWS WAFより提供されるCAPTCHA認証コンテンツに書き換えられ認証を行うことが可能となります。

この時点ではまだlogin.jsonに対するリクエストは行われません。

最終的にこの認証を完了することでfetch()が実行されlogin.jsonが取得できます。
ページ遷移をした場合にログが消えるように設定していますがページ表示時からログが消えず残っているためページ遷移が一度も行われていないことがわかります。


※最後だけキャプチャを撮り忘れて再度実行したため読み込み順がちょっと変わっています

終わりに

今回のアップデートでAWS WAFのCAPTCHA認証の使い勝手が向上しました。

見せ方の選択肢が1つ増えたという形にはなりますので、アップデートページで1つの例として挙げられているSPAに限らず綺麗に埋め込むことで不自然(露骨に外部で認証しているような感じ)を減らせるいいアップデートだと思います。

なお通常のページ遷移の場合Cookieにaws-waf-tokenが認証時に得られた正しい値の場合はCAPTCHA認証をスキップするのですが、このコードの場合は設定されていても都度認証が必要になっていました。
(実行後aws-waf-tokenがある状態で直接アクセスした場合等は表示される)

まだドキュメントが読みきれてないのですがこの辺りを対応しようとするとサンプル+何かの処理がいるのかなと思います。