Invisible Captcha
repository·master·Indexed 23 days ago
https://github.com/markets/invisible_captchaA spam protection solution for Rails applications (compatible with Rails >= 5.2 and Ruby >= 2.7) that deters bots using honeypot fields, time-sensitive submission checks, and IP-based spinner validation. It provides view helpers for form integration, controller filters for spam detection, and configurable options for timestamp thresholds and honeypot management.
What's inside invisible_captcha
- Invisible Captcha relies on data set by the Rails backend. For the protection to work correctly, your forms must be rendered by Rails. Forms generated entirely via JavaScript may not function as expected.
Configure Content Security Policy (CSP) for Invisible Captcha
masterIf your application uses a Content Security Policy, you must pass
nonce: trueto the view helper. Ensure your Rails configuration is set up to generate nonces for styles.- Configure CSP in
config/initializers/content_security_policy.rb:
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } Rails.application.config.content_security_policy_nonce_directives = %w(style-src)(If you already use nonces for scripts, include
script-srcin the directives list).- Use the nonce in your view:
<%= invisible_captcha nonce: true %>- Configure CSP in
Install Invisible Captcha
masterAdd
invisible_captchato your Gemfile and runbundle install. The gem is compatible with Rails>= 5.2and Ruby>= 2.7.gem 'invisible_captcha'Test Invisible Captcha in Controller tests
masterWhen testing controllers, you may need to adjust settings to avoid false positives from the timestamp or spinner checks.
Disable timestamp check in test environment:
InvisibleCaptcha.setup do |config| config.timestamp_enabled = !Rails.env.test? endSet a known honeypot for testing:
config.honeypots = ['my_honeypot_field'] if Rails.env.test?Disable spinner validation in test environment:
config.spinner_enabled = !Rails.env.test?Provide a valid spinner value in RSpec:
session[:invisible_captcha_spinner] = '32ab649161f9f6faeeb323746de1a25d' post :create, params: { topic: { title: 'foo' }, spinner: '32ab649161f9f6faeeb323746de1a25d' }Display spam error messages
masterThe
invisible_captchagem sends error messages toflash[:error]. To ensure users see these messages, you must include the flash error display in your application layout (e.g.,app/views/layouts/application.html.erb).<body <%= flash[:error] %> <%= yield %> </body>Configure Invisible Captcha for multiple Rails instances
masterWhen running multiple Rails instances behind a load balancer, you must ensure they share the same honeypots collection and the same
secret. Since honeypots are stored in memory by default, they will differ across instances unless explicitly shared.Use
Rails.cacheto share the honeypots collection and provide thesecretvia an environment variable (ENV['INVISIBLE_CAPTCHA_SECRET']) to ensure consistency.InvisibleCaptcha.setup do |config| config.honeypots = Rails.cache.fetch('invisible_captcha_honeypots') do (1..20).map { InvisibleCaptcha.generate_random_honeypot } end endImplement Invisible Captcha in Rails views
masterTo add the honeypot protection to your forms, use the
invisible_captchahelper. You can use it within aform_forblock or as a standalone helper. If you provide a symbol (e.g.,:subtitle), it will use that specific attribute as the honeypot field. If no attribute is provided, the engine will select a random field fromInvisibleCaptcha.honeypots.<%# Using with form_for %> <%= form_for(@topic) do |f| <%= f.invisible_captcha :subtitle %> <% end %> <%# Or using the standalone helper %> <%= form_for(@topic) do |f| <%= invisible_captcha :subtitle, :topic %> <% end %> <%# Using with a random honeypot field %> <%= form_tag(new_contact_path) do |f| <%= invisible_captcha %> <% end %>Run the Invisible Captcha test suite
masterTo verify the implementation, you can run the RSpec test suite. If you are testing against multiple supported versions of Rails, useappraisalto manage the different environments.Run the Dummy App demo
masterThe
Dummy Appis a Rails application used to testInvisible Captchaand serves as a live demonstration of the library in action. To run the application, execute the following command from the root of the project repository:bundle exec rake webConfigure Invisible Captcha plugin options
masterYou can customize the global behavior of the
invisible_captchaplugin using an initializer (e.g.,config/initializers/invisible_captcha.rb).Key configuration options include:
sentence_for_humans: Text shown to real users if the field is visible. Uses I18n by default.honeypots: A collection of honeypot field names. A random collection is generated by default.visual_honeypots: Set totrueto make honeypots visible (useful for debugging).timestamp_threshold: The minimum time in seconds required for a human to submit a form (default: 4s).timestamp_enabled: Boolean to enable/disable the time threshold check.timestamp_error_message: Flash error message for fast submissions. Uses I18n by default.injectable_styles: Iftrue, you must call<%= invisible_captcha_styles %>in your layout (e.g., in<head>). Otherwise, styles are injected inline.spinner_enabled: Boolean to enable/disable IP spinner validation (default:true).honeypot_enabled: Boolean to enable/disable honeypot fields (default:true).secret: The secret key for encoding internal values. Defaults toENV['INVISIBLE_CAPTCHA_SECRET'].
InvisibleCaptcha.setup do |config| # config.honeypots << ['more', 'fake', 'attribute', 'names'] # config.visual_honeypots = false # config.timestamp_threshold = 2 # config.timestamp_enabled = true # config.injectable_styles = false # config.spinner_enabled = true # config.honeypot_enabled = true # Leave these unset if you want to use I18n # config.sentence_for_humans = 'If you are a human, ignore this field' # config.timestamp_error_message = 'Sorry, that was too quick! Please resubmit.' endInject honeypot styles in your layout
masterIf you have enabled
injectable_stylesin your configuration, you must call theinvisible_captcha_styleshelper within your application layout to ensure honeypot fields are correctly hidden from human users.<%= invisible_captcha_styles %>Integrate Invisible Captcha with Rails
masterWhen used in a Rails application,
InvisibleCaptchaautomatically integrates via a Railtie. This integration provides several key capabilities:- Controller Extensions: Adds methods to
ActionControllerfor handling captcha logic. - View Helpers: Provides helpers to
ActionViewfor rendering captcha elements. - Form Builder Helpers: Extends
ActionView::Helpers::FormBuilderto allow seamless integration of captcha fields within Rails forms.
- Controller Extensions: Adds methods to