roda 3.42.0 → 3.43.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/doc/release_notes/3.43.0.txt +34 -0
- data/lib/roda/plugins/host_authorization.rb +156 -0
- data/lib/roda/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bca86a88a2d0e6fc0952ec2b2a91aa2e4d6dc0374546d5ac9d74d5b39a30abc
|
4
|
+
data.tar.gz: 20044ea95c1b1efabc06d8cda365384193c33ddd8140c7c91f9977483975e004
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2281aac1898e6a81c114023fefb15f77c14ad1ebcd37daad10a1f5c51815c0d175c68a052627bb5025e02c92821d6c64cf6eb3757d801b277b771e73daddc20f
|
7
|
+
data.tar.gz: a55217f87afb2989312e62804715b65c8213997699b187f52a78f8a96dfb592a62ee7adeb029a52663631887ef5cdd15c746930cf9dfba437b744df159b7090c
|
data/CHANGELOG
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A host_authorization plugin has been added to verify the requested
|
4
|
+
Host header is authorized. Using it can prevent DNS rebinding
|
5
|
+
attacks in cases where the application can receive requests for
|
6
|
+
arbitrary hosts.
|
7
|
+
|
8
|
+
To check for authorized hosts in your routing tree, you call the
|
9
|
+
check_host_authorization! method. For example, if you want to
|
10
|
+
check for authorized hosts after serving requests for public
|
11
|
+
files, you could do:
|
12
|
+
|
13
|
+
plugin :public
|
14
|
+
plugin :host_authorization, 'my-domain-name.example.com'
|
15
|
+
|
16
|
+
route do |r|
|
17
|
+
r.public
|
18
|
+
check_host_authorized!
|
19
|
+
|
20
|
+
# ... rest of routing tree
|
21
|
+
end
|
22
|
+
|
23
|
+
In addition to handling single domain names via a string, you can
|
24
|
+
provide an array of domain names, a regexp to match again, or a
|
25
|
+
proc.
|
26
|
+
|
27
|
+
By default, requests using unauthorized hosts receive an empty 403
|
28
|
+
response. If you would like to customize the response, you can
|
29
|
+
pass a block when loading the plugin:
|
30
|
+
|
31
|
+
plugin :host_authorization, 'my-domain-name.example.com' do |r|
|
32
|
+
response.status = 403
|
33
|
+
"Response Body Here"
|
34
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The host_authorization plugin allows configuring an authorized host or
|
7
|
+
# an array of authorized hosts. Then in the routing tree, you can check
|
8
|
+
# whether the request uses an authorized host via the +check_host_authorized!+
|
9
|
+
# method.
|
10
|
+
#
|
11
|
+
# If the request doesn't match one of the authorized hosts, the
|
12
|
+
# request processing stops at that point. Using this plugin can prevent
|
13
|
+
# DNS rebinding attacks if the application can receive requests for
|
14
|
+
# arbitrary hosts.
|
15
|
+
#
|
16
|
+
# By default, an empty response using status 403 will be returned for requests
|
17
|
+
# with unauthorized hosts.
|
18
|
+
#
|
19
|
+
# Because +check_host_authorized!+ is an instance method, you can easily choose
|
20
|
+
# to only check for authorization in certain routes, or to check it after
|
21
|
+
# other processing. For example, you could check for authorized hosts after
|
22
|
+
# serving static files, since the serving of static files should not be
|
23
|
+
# vulnerable to DNS rebinding attacks.
|
24
|
+
#
|
25
|
+
# = Usage
|
26
|
+
#
|
27
|
+
# In your routing tree, call the +check_host_authorized!+ method at the point you
|
28
|
+
# want to check for authorized hosts:
|
29
|
+
#
|
30
|
+
# plugin :host_authorization, 'www.example.com'
|
31
|
+
# plugin :public
|
32
|
+
#
|
33
|
+
# route do |r|
|
34
|
+
# r.public
|
35
|
+
# check_host_authorized!
|
36
|
+
#
|
37
|
+
# # ...
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# = Specifying authorized hosts
|
41
|
+
#
|
42
|
+
# For applications hosted on a single domain name, you can use a single string:
|
43
|
+
#
|
44
|
+
# plugin :host_authorization, 'www.example.com'
|
45
|
+
#
|
46
|
+
# For applications hosted on multiple domain names, you can use an array of strings:
|
47
|
+
#
|
48
|
+
# plugin :host_authorization, %w'www.example.com www.example2.com'
|
49
|
+
#
|
50
|
+
# For applications supporting arbitrary subdomains, you can use a regexp. If using
|
51
|
+
# a regexp, make sure you use <tt>\A<tt> and <tt>\z</tt> in your regexp, and restrict
|
52
|
+
# the allowed characters to the minimum required, otherwise you can potentionally
|
53
|
+
# introduce a security issue:
|
54
|
+
#
|
55
|
+
# plugin :host_authorization, /\A[-0-9a-f]+\.example\.com\z/
|
56
|
+
#
|
57
|
+
# For applications with more complex requirements, you can use a proc. Similarly
|
58
|
+
# to the regexp case, the proc should be aware the host contains user-submitted
|
59
|
+
# values, and not assume it is in any particular format:
|
60
|
+
#
|
61
|
+
# plugin :host_authorization, proc{|host| ExternalService.allowed_host?(host)}
|
62
|
+
#
|
63
|
+
# If an array of values is passed as the host argument, the host is authorized if
|
64
|
+
# it matches any value in the array. All host authorization checks use the
|
65
|
+
# <tt>===</tt> method, which is why it works for strings, regexps, and procs.
|
66
|
+
# It can also work with arbitrary objects that support <tt>===</tt>.
|
67
|
+
#
|
68
|
+
# For security reasons, only the +Host+ header is checked by default. If you are
|
69
|
+
# sure that your application is being run behind a forwarding proxy that sets the
|
70
|
+
# <tt>X-Forwarded-Host</tt> header, you should enable support for checking that
|
71
|
+
# header using the +:check_forwarded+ option:
|
72
|
+
#
|
73
|
+
# plugin :host_authorization, 'www.example.com', check_forwarded: true
|
74
|
+
#
|
75
|
+
# In this case, the trailing host in the <tt>X-Forwarded-Host</tt> header is checked,
|
76
|
+
# which should be the host set by the forwarding proxy closest to the application.
|
77
|
+
# In cases where multiple forwarding proxies are used that append to the
|
78
|
+
# <tt>X-Forwarded-Host</tt> header, you should not use this plugin.
|
79
|
+
#
|
80
|
+
# = Customizing behavior
|
81
|
+
#
|
82
|
+
# By default, an unauthorized host will receive an empty 403 response. You can
|
83
|
+
# customize this by passing a block when loading the plugin. For example, for
|
84
|
+
# sites using the render plugin, you could return a page that uses your default
|
85
|
+
# layout:
|
86
|
+
#
|
87
|
+
# plugin :render
|
88
|
+
# plugin :host_authorization, 'www.example.com' do |r|
|
89
|
+
# response.status = 403
|
90
|
+
# view(:content=>"<h1>Forbidden</h1>")
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# The block passed to this plugin is treated as a match block.
|
94
|
+
module HostAuthorization
|
95
|
+
def self.configure(app, host, opts=OPTS, &block)
|
96
|
+
app.opts[:host_authorization_host] = host
|
97
|
+
app.opts[:host_authorization_check_forwarded] = opts[:check_forwarded] if opts.key?(:check_forwarded)
|
98
|
+
|
99
|
+
if block
|
100
|
+
app.define_roda_method(:host_authorization_unauthorized, 1, &block)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module InstanceMethods
|
105
|
+
# Check whether the host is authorized. If not authorized, return a response
|
106
|
+
# immediately based on the plugin block.
|
107
|
+
def check_host_authorization!
|
108
|
+
r = @_request
|
109
|
+
return if host_authorized?(_convert_host_for_authorization(r.env["HTTP_HOST"].to_s.dup))
|
110
|
+
|
111
|
+
if opts[:host_authorization_check_forwarded] && (host = r.env["HTTP_X_FORWARDED_HOST"])
|
112
|
+
if i = host.rindex(',')
|
113
|
+
host = host[i+1, 10000000].to_s
|
114
|
+
end
|
115
|
+
host = _convert_host_for_authorization(host.strip)
|
116
|
+
|
117
|
+
if !host.empty? && host_authorized?(host)
|
118
|
+
return
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
r.on do
|
123
|
+
host_authorization_unauthorized(r)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# Remove the port information from the passed string (mutates the passed argument).
|
130
|
+
def _convert_host_for_authorization(host)
|
131
|
+
host.sub!(/:\d+\z/, "")
|
132
|
+
host
|
133
|
+
end
|
134
|
+
|
135
|
+
# Whether the host given is one of the authorized hosts for this application.
|
136
|
+
def host_authorized?(host, authorized_host = opts[:host_authorization_host])
|
137
|
+
case authorized_host
|
138
|
+
when Array
|
139
|
+
authorized_host.any?{|auth_host| host_authorized?(host, auth_host)}
|
140
|
+
else
|
141
|
+
authorized_host === host
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Action to take for unauthorized hosts. Sets a 403 status by default.
|
146
|
+
def host_authorization_unauthorized(_)
|
147
|
+
@_response.status = 403
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
register_plugin(:host_authorization, HostAuthorization)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.43.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -213,6 +213,7 @@ extra_rdoc_files:
|
|
213
213
|
- doc/release_notes/3.40.0.txt
|
214
214
|
- doc/release_notes/3.41.0.txt
|
215
215
|
- doc/release_notes/3.42.0.txt
|
216
|
+
- doc/release_notes/3.43.0.txt
|
216
217
|
- doc/release_notes/3.5.0.txt
|
217
218
|
- doc/release_notes/3.6.0.txt
|
218
219
|
- doc/release_notes/3.7.0.txt
|
@@ -262,6 +263,7 @@ files:
|
|
262
263
|
- doc/release_notes/3.40.0.txt
|
263
264
|
- doc/release_notes/3.41.0.txt
|
264
265
|
- doc/release_notes/3.42.0.txt
|
266
|
+
- doc/release_notes/3.43.0.txt
|
265
267
|
- doc/release_notes/3.5.0.txt
|
266
268
|
- doc/release_notes/3.6.0.txt
|
267
269
|
- doc/release_notes/3.7.0.txt
|
@@ -312,6 +314,7 @@ files:
|
|
312
314
|
- lib/roda/plugins/header_matchers.rb
|
313
315
|
- lib/roda/plugins/heartbeat.rb
|
314
316
|
- lib/roda/plugins/hooks.rb
|
317
|
+
- lib/roda/plugins/host_authorization.rb
|
315
318
|
- lib/roda/plugins/indifferent_params.rb
|
316
319
|
- lib/roda/plugins/json.rb
|
317
320
|
- lib/roda/plugins/json_parser.rb
|
@@ -401,7 +404,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
401
404
|
- !ruby/object:Gem::Version
|
402
405
|
version: '0'
|
403
406
|
requirements: []
|
404
|
-
rubygems_version: 3.2.
|
407
|
+
rubygems_version: 3.2.15
|
405
408
|
signing_key:
|
406
409
|
specification_version: 4
|
407
410
|
summary: Routing tree web toolkit
|