Blog

Thoughts from my daily grind

reCaptcha Spam Protection - V3 with V2 Fallback

Posted by Ziyan Junaideen |Published: 22 March 2021 |Category: Code
Default Upload |

When it comes to the job of keep spam-bots at bay, the first thing that comes to my mind is reCaptcha. I have used it as my go to solution in over 25 projects in the last 8 years. It's popular, battle tested and you can't go wrong choosing it.

Why Use Two Versions at Once

reCaptcha V3 is great. It doesn't add any badge or a checkbox in the client side which keeps it neat. In the server side we will score the request and then choose what to do if it falls in our definition of spam.

In many of the SaaS applications I build, if in doubt we do one or more of SMS confirmation, extensive field validation, manual validation before giving access to resources. But for a simple website that is on a budget this would be an unjustifiable cost.

Instead, when suspicious, we can invalidate the form and re-render it with the V2 "I'm not a robot" checkbox. This way many users will just go through without having an idea they have been vetted and spam will get challenged in a second step.

Before Getting Started

Unfortunately V2 and V3 keys are not compatible with one another. As a result you will have to create 2 reCaptcha applications and use both key pairs at once. The recaptcha gem, which we will be using for this example, can only support one key pair in its initialiser. For the other we will have to use inline configuration.

Create 2 reCaptcha Apps (v2 and v3) here: https://www.google.com/recaptcha/admin/create

Instructions

Add the recaptcha gem to your Gemfile and run bundle install.

gem 'recaptcha'

Then configure your system in an appropriate way to store the credentials. If you are prior to Rails 5.1 you might use secrets.yml file or a tool like dot-env-rails or figaro. For newer Rails you have Rails credentials to encrypt the credentials which is a better way to handle secrets. Here I would be simply using environment variables.

export RECAPTCHA_V2_SITE_KEY=...
export RECAPTCHA_V2_SECRET_KEY=...
export RECAPTCHA_V3_SITE_KEY=...
export RECAPTCHA_V3_SECRET_KEY=...

Then I will configure recaptcha gem with the V3 key. This way we only have to override the key when we use V2 methods of the gem.

Recaptcha.configure do |config|
  config.site_key  = ENV['RECAPTCHA_V3_SITE_KEY']
  config.secret_key = ENV['RECAPTCHA_V3_SECRET_KEY']
end

Then we need to update the form to use either V3 or V2 helper methods. To know which we will use the instance variable @show_checkbox_recaptcha.

- if @show_checkbox_recaptcha
  .row.mb-20
    .col-xs-12
      center = recaptcha_tags(site_key: ENV['RECAPTCHA_V2_SITE_KEY'])
  hr
- else
  = recaptcha_v3(action: 'register'

Then we need to vet the request in the controller and decide if we need to enable the V2 helper.

class Marketing::RegistrationsController < MarketingController
  def create
    success = verify_recaptcha(action: 'register')
    checkbox_success = verify_recaptcha(secret_key: ENV['RECAPTCHA_V2_SECRET_KEY') unless success

    @person = Person.new(registration_params)

    if (success || checkbox_success) && @person.save
      flash[:success] = 'Account created. Please login to continue.'
      redirect_to new_user_session_path
    else
      @show_checkbox_recaptcha = true unless success
      flash[:warning] = @person.errors.any? 'Check form for errors' : 'Please confirm that you are human'
      render :new
    end
  end
end

Thats it! When the user lands on the form for the first time it will not show any reCaptcha. Once the form is submitted and if the score is not satisfactory we will load the V2 "I'm not a robot" checkbox".

Hope it was helpful!

Tags
About the Author

Ziyan Junaideen -

Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.

Comments