Hello,
Since Rails 7.0, unpermitted open redirects raise an ActionController::Redirecting::UnsafeRedirectError
by default. For most applications running under a single domain, it’s a neat addition. But what about applications that use lots of subdomains (ex: based on user names / organisations / projects / etc.), need to redirect users across them and may not be able to add allow_other_host: true
on each call to redirect_to
? (ex: when using controllers bundled in a gem, say Devise).
Open redirects permissions can be turned off but there is currently no way to get benefits of it for more than one hostname (as long as you know these domains are all under your control).
Rails applications already have an hosts
config, used to configure the ActionDispatch::HostAuthorization
middleware with allowed host names. Do you think this could be reused (when configured) in ActionController::Redirecting#_url_host_allowed?
to check redirect location not only against request.host
? Or is there a better way to prevent widely open redirects while still being able to redirect across controlled (sub)domains?
A naive implementation in any ApplicationController
could look like this:
class ApplicationController
private
# Redefine a private and undocumented method, subject to changes in any future release!
def _url_host_allowed?(url)
return true if super
host_with_port = URI(url.to_s).authority
permissions = ActionDispatch::HostAuthorization::Permissions.new(Rails.application.config.hosts)
permissions.allows?(host_with_port)
rescue ArgumentError, URI::Error
false
end
end