RedirectSafely
Sanitize return_to
-style URLs, including some edge cases that you probably missed.
RedirectSafely
is used in production and extracted from Shopify.
Installation
Add these lines to your application's Gemfile:
gem 'redirect_safely', '~> 1.0'
And then execute:
$ bundle
Usage
-
RedirectSafely.safe?(url, options)
Return true if the URL is considered "safe", false otherwise.
Parameters:
-
url
String (required) - The URL to test
Options:
-
path_match
Regexp (optional) - Match the path portion of the URL against a regexp -
require_absolute
Boolean (optional) - If true, require an absolute URL (domain must be included inwhitelist
) -
require_ssl
Boolean (optional) - If true, and an absolute URL is provided, require a URL starting withhttps://
-
whitelist
String[] (optional) - Whitelisted domains for checking absolute URLs -
subdomains
String[] (optional) - Whitelisted subdomains for checking absolute URLs. Must start with a leading.
.
-
-
RedirectSafely.make_safe(url, default, options)
Return
url
if it's safe, otherwise returndefault
.Shares options with
safe?
, and is roughly equivalent to:safe_url = RedirectSafely.safe?(url) ? url : default
-
RedirectSafelyValidator
If you persist a redirect URL on a model, you can validate that it is
safe?
:class Request validates :return_to, redirect_safely: true end
You can pass any options supported by
safe?
(but not those added bymake_safe
). In the event that you need more control over the options (ie, dynamically producting a whitelist based on other model attributes), write a customvalidate
method:class Request validates :store_url, presence: true validate :return_to, presence: true validate :return_to_is_safe private def return_to_is_safe errors.add(:return_to, :invalid) unless RedirectSafely.safe?(return_to, whitelist: URI.parse(store_uri).host) end end