Google reCAPTCHA response success: false, no error codes

12,373

Solution 1

You will get timeout-or-duplicate problem if your captcha is validated twice. Save logs in a file in append mode and check if you are validating a Captcha twice.
Here is an example

$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret.'&response='.$_POST['g-recaptcha-response'])

file_put_contents( "logfile",  $verifyResponse, FILE_APPEND );

Now read the content of logfile created above and check if captcha is verified twice

Solution 2

This is an interesting question, but it's going to be impossible to answer with any sort of certainly. I can give an educated guess about what's occurring.

As far as the old submissions go, that could simply be users leaving the page open in the browser and coming back later to finally submit. You can handle this scenario in a few different ways:

  1. Set a meta refresh for the page, such that it will update itself after a defined period of time, and hopefully either get a new ReCAPTCHA validation code or at least prompt the user to verify the CAPTCHA again. However, this is less than ideal as it increases requests to your server and will blow out any work the user has done on the form. It's also very brute-force: it will simply refresh after a certain amount of time, regardless of whether the user is currently actively using the page or not.

  2. Use a JavaScript timer to notify the user about the page timing out and then refresh. This is like #1, but with much more finesse. You can pop a warning dialog telling the user that they've left the page sitting too long and it will soon need to be refreshed, giving them time to finish up if they're actively using it. You can also check for user activity via events like onmousemove. If the user's not moving the mouse, it's very likely they aren't on the page.

  3. Handle it server-side, by catching this scenario. I actually prefer this method the most as it's the most fluid, and honestly the easiest to achieve. When you get back success: false with no error codes, simply send the user back to the page, as if they had made a validation error in the form. Provide a message telling them that their CAPTCHA validation expired and they need to verify again. Then, all they have to do is verify and resubmit.

The double-submit issue is a perennial one that plagues all web developers. User behavior studies have shown that the vast majority occur because users have been trained to double-click icons, and as a result, think they need to double-click submit buttons as well. Some of it is impatience if something doesn't happen immediately on click. Regardless, the best thing you can do is implement JavaScript that disables the button on click, preventing a second click.

Share:
12,373
Admin
Author by

Admin

Updated on July 31, 2022

Comments

  • Admin
    Admin almost 2 years

    UPDATE: Google has recently updated their error message with an additional error code possibility: "timeout-or-duplicate".

    This new error code seems to cover 99% of our previously mentioned mysterious cases.

    We are still left wondering why we get that many validation requests that are either timeouts or duplicates. Determinining this with certainty is likely to be impossible, but now I am just hoping that someone else has experienced something like it.


    Disclaimer: I cross posted this to Google Groups, so apologies for spamming the ether for the ones of you who frequent both sites.

    I am currently working on a page as part of a ASP.Net MVC application with a form that uses reCAPTCHA validation. The page currently has many daily users. In my server side validation** of a reCAPTCHA response, for a while now, I have seen the case of the reCAPTCHA response having its success property set to false, but with an accompanying empty error code array. Most of the requests pass validation, but some keep exhibiting this pattern.

    So after doing some research online, I explored the two possible scenarios I could think of:

    1. The validation has timed out and is no longer valid.
    2. The user has already been validated using the response value, so they are rejected the second time.

    After collecting data for a while, I have found that all cases of "Success: false, error codes: []" have either had the validation be rather old (ranging from 5 minutes to 10 days(!)), or it has been a case of a re-used response value, or sometimes a combination of the two. Even after implementing client side prevention of double-clicking my submit-form button, a lot of double submits still seem to get through to the server side Google reCAPTCHA validation logic.

    My data tells me that 1.6% (28) of all requests (1760) have failed with at least one of the above scenarios being true ("timeout" or "double submission"). Meanwhile, not a single request of the 1760 has failed where the error code array was not empty.

    I just have a hard time imagining a practical use case where a ChallengeTimeStamp gets issued, and then after 10 days validation is attempted, server side.

    My question is:

    What could be the reason for a non-negligible percentage of all Google reCAPTCHA server side validation attempts to be either very old or a case of double submission?

    **By "server side validation" I mean logic that looks like this:

        public bool IsVerifiedUser(string captchaResponse, string endUserIp)
        {            
            string apiUrl = ConfigurationManager.AppSettings["Google_Captcha_API"];
            string secret = ConfigurationManager.AppSettings["Google_Captcha_SecretKey"];
            using (var client = new HttpClient())
            {
                var parameters = new Dictionary<string, string>
                {
                    { "secret", secret },
                    { "response", captchaResponse },
                    { "remoteip", endUserIp },
                };
                var content = new FormUrlEncodedContent(parameters);
                var response = client.PostAsync(apiUrl, content).Result;                
                var responseContent = response.Content.ReadAsStringAsync().Result;
                GoogleCaptchaResponse googleCaptchaResponse = JsonConvert.DeserializeObject<GoogleCaptchaResponse>(responseContent);
    
                if (googleCaptchaResponse.Success)
                {
                    _dal.LogGoogleRecaptchaResponse(endUserIp, captchaResponse);
                    return true;
                }
                else 
                {
                   //Actual code ommitted
                       //Try to determine the cause of failure
                       //Look at googleCaptchaResponse.ErrorCodes array (this has been empty in all of the 28 cases of "success: false")
                       //Measure time between googleCaptchaResponse.ChallengeTimeStamp (which is UTC) and DateTime.UtcNow
                       //Check reCAPTCHAresponse against local database of previously used reCAPTCHAresponses to detect cases of double submission
                   return false;
                }
            }
       }
    

    Thank you in advance to anyone who has a clue and can perhaps shed some light on the subject.