Invisible Captcha

repository·master·Indexed 23 days ago

https://github.com/markets/invisible_captcha

A 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.

Tokens
4.6K
Snippets
14
Records
28
Agent score
74%

What's inside invisible_captcha

  1. Configure Content Security Policy (CSP) for Invisible Captcha

    master

    If your application uses a Content Security Policy, you must pass nonce: true to the view helper. Ensure your Rails configuration is set up to generate nonces for styles.

    1. 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-src in the directives list).

    1. Use the nonce in your view:
    <%= invisible_captcha nonce: true %>
  2. Test Invisible Captcha in Controller tests

    master

    When 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?
    end

    Set 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' }
  3. Display spam error messages

    master

    The invisible_captcha gem sends error messages to flash[: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>
  4. Configure Invisible Captcha for multiple Rails instances

    master

    When 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.cache to share the honeypots collection and provide the secret via 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
    end
  5. Implement Invisible Captcha in Rails views

    master

    To add the honeypot protection to your forms, use the invisible_captcha helper. You can use it within a form_for block 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 from InvisibleCaptcha.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 %>
  6. Configure Invisible Captcha plugin options

    master

    You can customize the global behavior of the invisible_captcha plugin 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 to true to 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: If true, 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 to ENV['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.'
    end
  7. Integrate Invisible Captcha with Rails

    master

    When used in a Rails application, InvisibleCaptcha automatically integrates via a Railtie. This integration provides several key capabilities:

    • Controller Extensions: Adds methods to ActionController for handling captcha logic.
    • View Helpers: Provides helpers to ActionView for rendering captcha elements.
    • Form Builder Helpers: Extends ActionView::Helpers::FormBuilder to allow seamless integration of captcha fields within Rails forms.