2

I have a Laravel registration form with the invisible google recaptcha v2 installed with the security set to highest level within the recaptcha admin console - code as follows:

<div>
  <div class="js-recaptcha-holder"></div>
    <button type="submit">Create account</button>
    {!! errors_for('g-recaptcha-response', $errors) !!}
  </div>
</div>

The javascript:

var captchaSiteKey = window['CAPTCHA_SITEKEY'] || false

win.renderGoogleInvisibleRecaptcha = function() {

    if (!captchaSiteKey) {
        console.error('No captcha sitekey available to implement reCaptcha')
        return
    }

    for (var i = 0; i < document.forms.length; ++i) {
        var form = document.forms[i];
        var holder = form.querySelector('.js-recaptcha-holder');
        if (null === holder) {
            continue;
        }

        (function(frm) {

            var holderId = grecaptcha.render(holder, {
                'sitekey': captchaSiteKey,
                'size': 'invisible',
                'badge': 'bottomright', // possible values: bottomright, bottomleft, inline
                'callback': function(recaptchaToken) {
                    HTMLFormElement.prototype.submit.call(frm);
                }
            });


            frm.onsubmit = function(evt) {
                evt.preventDefault();
                grecaptcha.execute(holderId);

            };

        })(form);
    }
};

Reviewing the access logs I notice a spammer/bot/automated programme hitting the form with a couple hundred fake submissions daily using up bandwidth.

In a normal scenario when using a browser the user/bot would be forced to solve the challenge before they can submit the form. How is the user bypassing the recaptcha? The google recaptcha admin console doesn't have any failed attempts. The captcha works if I try to submit the form i.e. the challenge is presented before you can submit form

These are some recent logs:

189.41.110.180  --  [01/Apr/2023:02:38:28   +0000]  GET / HTTP/1.1                  301 178 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:32   +0000]  GET / HTTP/1.1                  301 178 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:36   +0000]  GET / HTTP/1.1                  200 22327   -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:39   +0000]  GET /user/login HTTP/1.1    200 6188    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:40   +0000]  POST /user/login HTTP/1.1   302 430 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:41   +0000]  GET /user/login HTTP/1.1    200 6352    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:42   +0000]  POST /user/login HTTP/1.1   302 430 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:43   +0000]  GET /user/login HTTP/1.1    200 6352    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:44   +0000]  POST /user/login HTTP/1.1   302 430 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:45   +0000]  GET /user/login HTTP/1.1        200 6352    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:46   +0000]  POST /user/register HTTP/1.1    302 442 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:47   +0000]  GET /user/register HTTP/1.1 200 6395    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:48   +0000]  POST /user/register HTTP/1.1    302 442 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:49   +0000]  GET /user/register HTTP/1.1 200 6383    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:50   +0000]  POST /user/register HTTP/1.1    302 442 -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
189.41.110.180  --  [01/Apr/2023:02:38:51   +0000]  GET /user/register HTTP/1.1 200 6395    -   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36

The logs show user is managing to post the form/payload but getting a 302 which I think is the server side validation kicking in as the recaptcha would be missing from payload or are they actually managing to bypass the captcha somehow and some other server side form validation is redirecting back to the form with 302?

The form has a CSRF token so I would have expected to see 419 status code in the access logs if they were using something like curl to send the payload?

The user attempts the same with the login form. On that I've implemented login throttling but user still keeps making attempts - they simply get a 302 message as the server side validation/throttling kicks in.

I was thinking about blocking their IP using something like fail2ban but the user keeps rotating their IP address.

Is their any other suggestion how I can prevent this malicious user/bot submitting the form.

Any help advice appreciated.

*** Update ***

I added some logging to the form and it seems the bot is managing to post the form bypassing the recaptcha as the payload would include the recapture response token so I suspect its using a programmatic mechanism to submit the form. Below is example of their payload and the server side validation kicking in.

[2023-04-03 00:49:04] production.ERROR: Validation failed for IP 115.84.79.60 with data: {"_token":"DF2q8mTYWYl99W2NFM92xmDlQ3Y20hYxdrzw1YK1","first_name":"GrwCsTLWYq","last_name":"ogbLBjqX","email":"[email protected]","password":"iL7ghtnp0INc!","password_confirmation":"iL7ghtnp0INc!","remember":"true","site_marketing":"true","third_party_marketing":"true","text_only_email":"true","terms_accepted":"true"}. Error: Password must be at least 8 characters long and contain both letters and numbers  
[2023-04-03 00:49:09] production.ERROR: Validation failed for IP 115.84.79.60 with data: {"_token":"DF2q8mTYWYl99W2NFM92xmDlQ3Y20hYxdrzw1YK1","first_name":"JRbSlutIjCH","last_name":"GhfOYXIWgKB","email":"[email protected]","password":"WdGHfMXvwpUz!","password_confirmation":"WdGHfMXvwpUz!","remember":"true","site_marketing":"true","third_party_marketing":"true","text_only_email":"true","terms_accepted":"true"}. Error: Password must be at least 8 characters long and contain both letters and numbers 

I suppose my question is how is the csrf token in that payload still valid. I attempted to replicate the same using curl to initially do a curl GET request of the page and grab the CSRF token and then immediately submit a curl POST attempt using that csrf token and it always returns a 419 error?

7
  • OK. further investigation I've managed to replicate it using a curl request which typically allows you to bypass the recaptcha challenge to submit the form. However the server side validation requires a recaptcha token and so the bot would still fail even when all inputs have been validated. The question remain how do you stop such malicious attempts hammering your bandwith as they keep rotating their ip?
    – adam78
    Apr 3, 2023 at 10:39
  • So, with this comment, has the question fundamentally changed?
    – schroeder
    Apr 3, 2023 at 11:10
  • "How do I keep random IPs from accessing my site while keeping it accessible from other random IPs?" -- can you see that that's not possible?
    – schroeder
    Apr 3, 2023 at 11:11
  • @schroeder surely if the automated program is hammering the same form within seconds of each get/post request then that a good indication its a malicious bot and so the ip could blocked?
    – adam78
    Apr 3, 2023 at 15:49
  • there are services out there that will solve the captcha manually and send back the token (unused) to the bot. (yes, they actually employ people to sit there and solve captchas all day) Sure seems like that's the case here. Those services that block certain IPs usually work pretty well, but if you find those don't work for you, you might try Cloudflare and it's bot detection feature which I think might be a little more comprehensive than reCaptcha. (not sure if it would prevent a bot using a manual service though...) Apr 3, 2023 at 19:01

0

You must log in to answer this question.

Browse other questions tagged .