Module: Roda::RodaPlugins::HostAuthorization
- Defined in:
- lib/roda/plugins/host_authorization.rb
Overview
The host_authorization plugin allows configuring an authorized host or an array of authorized hosts. Then in the routing tree, you can check whether the request uses an authorized host via the check_host_authorized!
method.
If the request doesn’t match one of the authorized hosts, the request processing stops at that point. Using this plugin can prevent DNS rebinding attacks if the application can receive requests for arbitrary hosts.
By default, an empty response using status 403 will be returned for requests with unauthorized hosts.
Because check_host_authorized!
is an instance method, you can easily choose to only check for authorization in certain routes, or to check it after other processing. For example, you could check for authorized hosts after serving static files, since the serving of static files should not be vulnerable to DNS rebinding attacks.
Usage
In your routing tree, call the check_host_authorized!
method at the point you want to check for authorized hosts:
plugin :host_authorization, 'www.example.com'
plugin :public
route do |r|
r.public
# ...
end
Specifying authorized hosts
For applications hosted on a single domain name, you can use a single string:
plugin :host_authorization, 'www.example.com'
For applications hosted on multiple domain names, you can use an array of strings:
plugin :host_authorization, %w'www.example.com www.example2.com'
For applications supporting arbitrary subdomains, you can use a regexp. If using a regexp, make sure you use \A<tt> and <tt>\z
in your regexp, and restrict the allowed characters to the minimum required, otherwise you can potentionally introduce a security issue:
plugin :host_authorization, /\A[-0-9a-f]+\.example\.com\z/
For applications with more complex requirements, you can use a proc. Similarly to the regexp case, the proc should be aware the host contains user-submitted values, and not assume it is in any particular format:
plugin :host_authorization, proc{|host| ExternalService.allowed_host?(host)}
If an array of values is passed as the host argument, the host is authorized if it matches any value in the array. All host authorization checks use the ===
method, which is why it works for strings, regexps, and procs. It can also work with arbitrary objects that support ===
.
For security reasons, only the Host
header is checked by default. If you are sure that your application is being run behind a forwarding proxy that sets the X-Forwarded-Host
header, you should enable support for checking that header using the :check_forwarded
option:
plugin :host_authorization, 'www.example.com', check_forwarded: true
In this case, the trailing host in the X-Forwarded-Host
header is checked, which should be the host set by the forwarding proxy closest to the application. In cases where multiple forwarding proxies are used that append to the X-Forwarded-Host
header, you should not use this plugin.
Customizing behavior
By default, an unauthorized host will receive an empty 403 response. You can customize this by passing a block when loading the plugin. For example, for sites using the render plugin, you could return a page that uses your default layout:
plugin :render
plugin :host_authorization, 'www.example.com' do |r|
response.status = 403
view(:content=>"<h1>Forbidden</h1>")
end
The block passed to this plugin is treated as a match block.
Defined Under Namespace
Modules: InstanceMethods
Class Method Summary collapse
Class Method Details
.configure(app, host, opts = OPTS, &block) ⇒ Object
95 96 97 98 99 100 101 102 |
# File 'lib/roda/plugins/host_authorization.rb', line 95 def self.configure(app, host, opts=OPTS, &block) app.opts[:host_authorization_host] = host app.opts[:host_authorization_check_forwarded] = opts[:check_forwarded] if opts.key?(:check_forwarded) if block app.define_roda_method(:host_authorization_unauthorized, 1, &block) end end |