1

I am trying to implement reCAPTCHA validation via Marketing Cloud - cloud page.

I have used this guide to do that: https://ampscript.xyz/how-tos/how-to-implement-google-recaptcha-on-marketing-cloud-forms/

What I want to do is to create a post request instead of use the action form property.

My Clint side script:

<!doctype html>
<html>
<head>
 <meta charset="utf-8">
 <title></title>
 <meta name="description" content="">
 <meta name="viewport" content="width=device-width, initial-scale=1">

 <script src="https://www.google.com/recaptcha/api.js"></script>
</head>

<body>



<form id="form" >
    <label>Email: </label>
    <input type="email" name="EmailAddress">
    <div 
        class="g-recaptcha" 
        data-sitekey="XXXXXXXXXXXXXXXXXXXXXX" 
        data-callback="grecaptchaCallback" 
        data-size="invisible"
    ></div>
    <br>
    <button>Send</button>
</form>


<script>
    var form = document.getElementById('form');

    form.addEventListener('submit', grecaptchaValidate);

    function grecaptchaCallback() {
        return new Promise(function (resolve, reject) {
            if (grecaptcha.getResponse() !== '') {
                var x=grecaptcha.getResponse();
                console.log(x);
                var xhttp = new XMLHttpRequest();
                xhttp.open("POST", "https://pub.s7.exacttarget.com/jnmlkgsfquv", true);
                xhttp.setRequestHeader("Content-type",  'text/html',['Accept-Encoding'], ['identity'] );
                xhttp.send();
                http.onreadystatechange =  function() {
        if (this.readyState == 4 && this.status == 200) {
        
        var response=this.responseText;
        console.log(response);
        response=response.split("<script>");
        console.log(response);
        console.log(response[0].trim());
    }

}
            }
            grecaptcha.reset();
        })
    }

    function grecaptchaValidate(e) {
        e.preventDefault();
        grecaptcha.execute();
    }
</script>


</body>
</html>
    </script>
</body>
</html>

And this is my server-side script:


<script runat="server">
 
    Platform.Load("core", "1.1.1");

    try {

        var g_recaptcha_response = Request.GetFormField("g-recaptcha-response");
        var secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";
        var payload = "secret=" + secret + "&response=" + g_recaptcha_response;
  var contentType = "application/x-www-form-urlencoded";
  var endpoint = "https://www.google.com/recaptcha/api/siteverify";
        var req = HTTP.Post(endpoint, contentType, payload);

        if (req.StatusCode == 200) {

            var resp = Platform.Function.ParseJSON(String(req.Response));

            if (!resp.success) throw "Wrong reCAPTCHA";

        } else {
            throw "reCAPTCHA API error";
        }

        /// DO SOMETHING

        Write(Stringify(resp));

    } catch (error) {
        Write(Stringify({ status: "Error", message: error }));
    }

</script>

The error I get when I send the request is:

{"status":"Error","message":"Wrong reCAPTCHA"}




<script>(function(a,m,i,g,o,s){o=a.createElement(g);s=a.getElementsByTagName(i)[0];o.src=m.origin+m.pathname+"/_t?eventType=CLOUDPAGESVISIT";o.width=0;o.height=0;o.style.display="none";s.appendChild(o);})(document,window.location,"body","img");</script>
    <script src="https:&#x2F;&#x2F;7231513.collect.igodigital.com&#x2F;collect.js"></script>
    <script>
        if (_etmc && typeof _etmc.push === 'function') {
            _etmc.push(['setOrgId', '7231513']);
            _etmc.push(['trackPageView']);
        }
    </script>

Another conclusion I came to- If I insert manually the value that I received from the client-side from x object (the grecaptcha.getResponse() ) The response correct:

 {"success":true,"challenge_ts":"2020-07-29T09:30:03Z","hostname":"pub.s7.exacttarget.com"}

I would love to get an idea of how I create the request from the client-side to the server-side page according to post I am initiating?

Is there anything I'm missing? Or maybe I'm not working correctly?

Edit:

The problem was with the payload at server-side page, because the variable g_recaptcha_response was null.

My workaround is to catch the variable with query string variable:


%%[
  set @x = RequestParameter("x")
]%%
<script runat="server">
 
    Platform.Load("core", "1.1.1");
  var x = Variable.GetValue("@x");  
 

    try {

 
      //  var g_recaptcha_response = Request.GetFormField("g-recaptcha-response");
      
        var secret = "XXXXXXXXXXXXXXXXXXXXXXXXX";
        var payload = "secret=" + secret + "&response=" + x;
  var contentType = "application/x-www-form-urlencoded";
  var endpoint = "https://www.google.com/recaptcha/api/siteverify";
        var req = HTTP.Post(endpoint, contentType, payload);

        if (req.StatusCode == 200) {

            var resp = Platform.Function.ParseJSON(String(req.Response));

            if (!resp.success) throw "Wrong reCAPTCHA";

        } else {
            throw "reCAPTCHA API error";
        }

        /// DO SOMETHING

        Write(Stringify(resp));

    } catch (error) {
        Write(Stringify({ status: "Error", message: error }));
    }

</script>

Because there is no way to catch URL data on SSJS I using AMPscript to catch x and pass it to payload, now I get a success response.

But I'm not sure if there have any security problem in this way.

nadav_z
  • 21
  • 3

1 Answers1

2

First of all, you need to create your Cloud page using the Content Builder option. This will remove the script tags in your response.

Second, you are sending your data in the content type of text/html, try using application/x-www-form-urlencoded instead.

I believe, your Form Handler doesn't capture the g-recaptcha-response because it can't be retrieved with Request.GetFormField when you are sending text/html content type.

Please have a look at this article: https://ampscript.xyz/how-tos/perform-an-http-request/

Otherwise, use Axios for your client-side requests: https://github.com/axios/axios

  • Hi @Ivan Razine, Thanks for your detailed comment. I tried to implement the solution you proposed, but it did not help at all. still, there is the same response. I also create a Cloud page using the Content Builder option, although I did not get the extra script I got more STYLE and BODY tags. and the response still Error. Moreover, I read the article you sent and they are talking about a separate server-side page. I wanna get the response to my client page and continue my custom flow. – nadav_z Jul 30 '20 at 08:06
  • maybe you have an idea why the request not work? and when I put the same URL (=https://pub.s7.exacttarget.com/jnmlkgsfquv) on form action property I get a success response? – nadav_z Jul 30 '20 at 08:06
  • When you were putting manually the `g_recaptcha_response` in your Form Handler, it was working, correct? If so, this means that your ajax request and the Form Handler fail to communicate. There can be many reasons why it does that, I therefore suggest you try a simple page where you send 1 parameter to a Cloud page with Ajax and display it in the result. – Ivan Razine Jul 31 '20 at 10:22
  • I was able to solve the problem. Thanks for your comments, they helped me understand the source of the problem. – nadav_z Aug 01 '20 at 17:52
  • I edited my question and write my solution. You welcome to look and say your opinion. Thanks for the help:) – nadav_z Aug 01 '20 at 18:15