/rack-corsgate

Modern CORS-based CSRF-protection for Rack apps

Primary LanguageRubyMIT LicenseMIT

Rack CorsGate middleware

Inspired by CorsGate as introduced by Mixmax, this Gem implements the same CSRF-protection for Rack. In short, we use Rack::Cors to configure whether or not requests are allowed to occur, and we enforce them via this middleware. Requests that are potential threats are blocked with a 403 response. Please read Using CORS policies to implement CSRF protection for the philosophy behind this middleware.

Installation

Install the gem:

gem install rack-corsgate

Or in your Gemfile:

gem 'rack-corsgate'

Dependencies

Your application must have Rack::Cors available. See: Rack CORS Middleware

Follow the configuration requirements given in its readme.

Configuration

CorsGate is actually two middleware functions:

  • The CorsGateOriginProcessor middleware checks if we have an origin header. If we don't, it will try to determine the origin based on the Referer header. This middleware should be triggered before Rack::Cors.
  • The CorsGate middleware enforces the result of the CORS test on the request, by actively blocking requests that are potential CSRF-attacks. This middleware should be triggered after Rack::Cors.

The easiest way to sandwich Rack::Cors with these two middlewares is as follows:

# Rack::CorsGate.use middleware, opts = {}, &forbidden_handler
Rack::CorsGate.use config.middleware

This is essentially a shortcut for the following:

config.middleware.insert_before Rack::Cors, Rack::CorsGateOriginProcessor
config.middleware.insert_after Rack::Cors, Rack::CorsGate

The options hash passed to Rack::CorsGate.use is passed on to both middlewares. The block applies to Rack::CorsGate only (see API below).

API

config.middleware.insert_before Rack::Cors, Rack::CorsGateOriginProcessor, { remove_null_origin: false }

Options:

  • remove_null_origin (boolean, default: false): Treats null (string) origin headers as if no origin header was set.
config.middleware.insert_after Rack::Cors, Rack::CorsGate, { simulation: false, strict: false, allow_safe: true } do |env, origin, method|
  # env: https://www.rubydoc.info/github/rack/rack/master/file/SPEC#label-The+Environment

  Rails.logger.warn("Blocked #{method} request from origin #{origin} to #{env['PATH_INFO']}")
end

Options:

  • simulation (boolean, default: false): Allows potential attacks to be carried out as if the middleware wasn't there. This can be useful during implementation trials and tests (see also the block signature below).
  • strict (boolean, default: false): If true, requires an origin to be present on all requests. Note that a Referer header will stand in for a missing Origin header if the CorsGateOriginProcessor is used.
  • allow_safe (boolean, default: false): If true, allows GET and HEAD requests through, even if the origin is not allowed by CORS, or if the Origin header is missing.

Block |env, origin, method|:

This optional block gets invoked whenever a request is about to be rejected (even in simulation mode).

License

MIT