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 in whitelist)
- require_ssl Boolean (optional) - If true, and an absolute URL is provided, require a URL starting with https://
- whitelist String - Whitelisted domains for checking absolute URLs
- subdomains String - Whitelisted subdomains for checking absolute URLs. Must start with a leading ..
RedirectSafely.make_safe(url, default, options)
Return url if it's safe, otherwise return default.
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 by make_safe). In the event that you need more
control over the options (ie, dynamically producting a whitelist based on other model attributes), write a custom
validate 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