Skip to content
Cloudflare toolkit and Rack middleware
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin
data
lib/rack
spec
.gitignore
.rspec
.rubocop.yml
.travis.yml
Gemfile
README.md
Rakefile
rack-cloudflare.gemspec

README.md

Rack::Cloudflare

Deal with Cloudflare features in your Ruby app using Rack middleware. Also provides a Ruby toolkit to deal with Cloudflare in other contexts if you'd like.

Installation

Add this line to your application's Gemfile:

gem 'rack-cloudflare'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rack-cloudflare

Usage

Whitelist Cloudflare IP addresses

You can block access to non-Cloudflare networks using Rack::Cloudflare::Middleware::AccessControl.

require 'rack/cloudflare'

# In config.ru (recommended for Rails as well to preempt application loading)
use Rack::Cloudflare::Middleware::AccessControl

# In Rails middleware: config/application.rb
config.middleware.unshift Rack::Cloudflare::Middleware::AccessControl

# Configure custom blocked message (defaults to "Forbidden")
Rack::Cloudflare::Middleware::AccessControl.message = "You don't belong here..."

# Fully customize the Rack response (such as making it a redirect)
Rack::Cloudflare::Middleware::AccessControl.response = lambda do |_env|
    [301, { 'Location' => 'https://somewhere.else.xyz' }, ["Redirecting...\n"]]
end

Alternatively, using Rack::Attack you can easily add a "safelist" rule.

Rack::Attack.safelist('Only allow requests through the Cloudflare network') do |request|
    Rack::Cloudflare::Headers.trusted?(request.env)
end

Utilizing the trusted? helper method, you can implement a similar check using other middleware.

See Toolkits: Detect Cloudflare Requests for alternative uses.

Rewrite Cloudflare Remote/Client IP address

You can set REMOTE_ADDR to the correct remote IP using Rack::Cloudflare::Middleware::RewriteHeaders.

require 'rack/cloudflare'

# In config.ru
use Rack::Cloudflare::Middleware::RewriteHeaders

# In Rails config/application.rb
config.middleware.use Rack::Cloudflare::Middleware::RewriteHeaders

You can customize whether rewritten headers should be backed up and what names to use.

# Toggle header backups (default: true)
Rack::Cloudflare::Headers.backup = false

# Rename backed up headers (defaults: "ORIGINAL_REMOTE_ADDR", "ORIGINAL_FORWARDED_FOR")
Rack::Cloudflare::Headers.original_remote_addr   = 'BACKUP_REMOTE_ADDR'
Rack::Cloudflare::Headers.original_forwarded_for = 'BACKUP_FORWARDED_FOR'

You can set the HTTP_X_FORWARDED_FOR header to exactly HTTP_CF_CONNECTING_IP, which effectively removes proxies.

Rack::Cloudflare::Headers.remove_proxies = true

See Toolkits: Rewrite Headers for alternative uses.

Logging

You can enable logging to see what requests are blocked or headers are rewritten.

Rack::Cloudflare.logger = Logger.new(STDOUT)

Log levels used are INFO, DEBUG and WARN.

Toolkits

Detect Cloudflare Requests

You can very easily check your HTTP headers to see if the request came from a Cloudflare network.

# Your headers are in a `Hash` format
# e.g. { 'REMOTE_ADDR' => '0.0.0.0', ... }
# Verifies the remote address
Rack::Cloudflare::Headers.trusted?(headers)

Note that we can only trust the REMOTE_ADDR header to verify a request came from Cloudflare. The HTTP_X_FORWARDED_FOR header can be modified and therefore not trusted.

Make sure your web server does not modify REMOTE_ADDR because it could cause security holes. Read this article, for example: Anatomy of an Attack: How I Hacked StackOverflow

Rewrite Headers

We can easily rewrite REMOTE_ADDR and add HTTP_X_FORWARDED_FOR based on verifying the request comes from a Cloudflare network.

# Get a list of headers relevant to Cloudflare (unmodified)
headers = Rack::Cloudflare::Headers.new(headers).target_headers

# Get a list of headers that will be rewritten (modified)
headers = Rack::Cloudflare::Headers.new(headers).rewritten_headers

# Get a list of headers relevant to Cloudflare with rewritten values
headers = Rack::Cloudflare::Headers.new(headers).rewritten_target_headers

# Update original headers with rewritten ones
headers = Rack::Cloudflare::Headers.new(headers).rewrite

Up-to-date Cloudflare IP addresses

Cloudflare provides a list of IP addresses that are important to keep up-to-date.

A copy of the IPs are kept in /data. The list is converted to a IPAddr list and is accessible as:

# Configurable list of IPs
# Defaults to Rack::Cloudflare::IPs::DEFAULTS
Rack::Cloudflare::IPs.list

The list can be updated to Cloudflare's latest published IP lists in-memory:

# Fetches Rack::Cloudflare::IPs::V4_URL and Rack::Cloudflare::IPs::V6_URL
Rack::Cloudflare::IPs.update!

# Updates cached list in-memory
Rack::Cloudflare::IPs.list

Credits

Inspired by:

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/joelvh/rack-cloudflare.

You can’t perform that action at this time.