How to render an reCAPTCHA challenge page with Action Token

140 views Asked by At

I have been unable to integrate reCAPTCHA with Cloud Armour when using an Action Token.

Firstly, The example for using Session tokens to display a challenge page at this codelab is working as expected.
The challenge page displays when clicking the median score link

<!doctype html>
<html>

<head>
    <title>ReCAPTCHA Testing</title>
    <script
        src="https://www.google.com/recaptcha/enterprise.js?render=<SESSION_TOKEN>&waf=session"></script>
</head>

<body>
    <h1>Main Page</h1>
    <p><a href="/good-score.html">Visit allow link</a></p>
    <p><a href="/bad-score.html">Visit blocked link</a></p>
    <p><a href="/median-score.html">Visit redirect link</a></p>
</body>

</html>

enter image description here

Next, I am trying to implement an Action Token. So I updated the the sample code from the codelab following the documentation here.

  • Created an Action token with the same test score as the Session token in the codelab
  • Updated the Cloud Armour rule to reference token.recaptcha_action.score
  • Updated the <script scr... HTML removing &waf=session and referencing the new Action token
  • Added the Javascript as per the sample code in the documentation.

    <!doctype html>
    <html>
    
    <head>
        <title>ReCAPTCHA Testing</title>
        <script
            src="https://www.google.com/recaptcha/enterprise.js?render=<ACTION_TOKEN>"></script>
        <script>
            function onSuccess(token) {
                const xhr = new XMLHttpRequest();
                xhr.open('GET', 'http://<LB_IP>/median-score.html', false);
                xhr.setRequestHeader("X-Recaptcha-Token", token);
    
                xhr.onreadystatechange = function () {
                    if (this.readyState == 4 && this.status == 200) {
                        // Display the response, it could be a reCAPTCHA challenge
                        // page based on your Google Cloud Armor security rule settings.
                        // I can see that xhr.responseText is a HTML document referencing the challenge page
                        document.open();
                        document.write(xhr.responseText)
                        document.close();
    
                    }
                };
                xhr.send(null);
            }
    
            grecaptcha.enterprise.ready(function () {
                document.getElementById("challenge-link").onclick = () => {
                    grecaptcha.enterprise.execute('<ACTION_TOKEN>', {}
                    ).then(onSuccess).catch(err => {
                        console.log('Something went wrong');
                        console.error({ err });
                    })
                };
            });
        </script>
    </head>
    
    <body>
        <h1>Main Page</h1>
        <p><a href="/good-score.html">Visit allow link</a></p>
        <p><a href="/bad-score.html">Visit blocked link</a></p>
        <p><a href="#" id="challenge-link">Visit redirect link</a></p>
    </body>
    
    </html>

The result looks like this - The challenge is never displayed enter image description here

I can see the result of xhr.responseText is a HTML document referencing reCAPTCHA so it is expecting to be display somewhere. I have tried all combinations of setting the xhr.responseText to innerHTML of a div, to within an iframe however have not been successful.

How can the challenge page be displayed when using the XMLHttpRequest() approach suggested in the documentation?

0

There are 0 answers