rack-protection 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -0
- data/lib/rack/protection/authenticity_token.rb +4 -4
- data/lib/rack/protection/base.rb +7 -0
- data/lib/rack/protection/host_authorization.rb +110 -0
- data/lib/rack/protection/version.rb +1 -1
- data/lib/rack/protection.rb +1 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c04192c3b3ef137443ac72495e4d948a544c1f7c7fd514f422045b870071b54
|
4
|
+
data.tar.gz: 5fc1d9022ef2d26e1c18dd56752883d3d99c6293fbd2a67708628bd414ab2f3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26d822dde064625a3520d8bd95b0b2499e4d94d081e8943bfeb4283cab18fd0f70d98b7e5e3cdea5298a75edc70a0a5fc44444e5563fab90db179136901758b6
|
7
|
+
data.tar.gz: d9618b6af6ffc69006e8404a1dc18dc4bd082a516042f25d804613e67438a27830f81b3fc87f2f82d2c7ff5e6607d461e30117515bf2f0be9ea36a0ff094f28d
|
data/README.md
CHANGED
@@ -34,6 +34,10 @@ run MyApp
|
|
34
34
|
|
35
35
|
# Prevented Attacks
|
36
36
|
|
37
|
+
## DNS rebinding and other Host header attacks
|
38
|
+
|
39
|
+
* [`Rack::Protection::HostAuthorization`][host-authorization] (not included by `use Rack::Protection`)
|
40
|
+
|
37
41
|
## Cross Site Request Forgery
|
38
42
|
|
39
43
|
Prevented by:
|
@@ -109,6 +113,7 @@ The instrumenter is passed a namespace (String) and environment (Hash). The name
|
|
109
113
|
[escaped-params]: http://www.sinatrarb.com/protection/escaped_params
|
110
114
|
[form-token]: http://www.sinatrarb.com/protection/form_token
|
111
115
|
[frame-options]: http://www.sinatrarb.com/protection/frame_options
|
116
|
+
[host-authorization]: https://github.com/sinatra/sinatra/blob/main/rack-protection/lib/rack/protection/host_authorization.rb
|
112
117
|
[http-origin]: http://www.sinatrarb.com/protection/http_origin
|
113
118
|
[ip-spoofing]: http://www.sinatrarb.com/protection/ip_spoofing
|
114
119
|
[json-csrf]: http://www.sinatrarb.com/protection/json_csrf
|
@@ -46,15 +46,15 @@ module Rack
|
|
46
46
|
# Install the gem, then run the program:
|
47
47
|
#
|
48
48
|
# gem install 'rack-protection'
|
49
|
-
#
|
49
|
+
# puma server.ru
|
50
50
|
#
|
51
|
-
# Here is <tt>server.
|
51
|
+
# Here is <tt>server.ru</tt>:
|
52
52
|
#
|
53
53
|
# require 'rack/protection'
|
54
54
|
# require 'rack/session'
|
55
55
|
#
|
56
56
|
# app = Rack::Builder.app do
|
57
|
-
# use Rack::Session::Cookie, secret: '
|
57
|
+
# use Rack::Session::Cookie, secret: 'CHANGEMEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
58
58
|
# use Rack::Protection::AuthenticityToken
|
59
59
|
#
|
60
60
|
# run -> (env) do
|
@@ -88,7 +88,7 @@ module Rack
|
|
88
88
|
# end
|
89
89
|
# end
|
90
90
|
#
|
91
|
-
#
|
91
|
+
# run app
|
92
92
|
#
|
93
93
|
# == Example: Customize which POST parameter holds the token
|
94
94
|
#
|
data/lib/rack/protection/base.rb
CHANGED
@@ -58,6 +58,13 @@ module Rack
|
|
58
58
|
result if (Array === result) && (result.size == 3)
|
59
59
|
end
|
60
60
|
|
61
|
+
def debug(env, message)
|
62
|
+
return unless options[:logging]
|
63
|
+
|
64
|
+
l = options[:logger] || env['rack.logger'] || ::Logger.new(env['rack.errors'])
|
65
|
+
l.debug(message)
|
66
|
+
end
|
67
|
+
|
61
68
|
def warn(env, message)
|
62
69
|
return unless options[:logging]
|
63
70
|
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/protection'
|
4
|
+
require 'ipaddr'
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
module Protection
|
8
|
+
##
|
9
|
+
# Prevented attack:: DNS rebinding and other Host header attacks
|
10
|
+
# Supported browsers:: all
|
11
|
+
# More infos:: https://en.wikipedia.org/wiki/DNS_rebinding
|
12
|
+
# https://portswigger.net/web-security/host-header
|
13
|
+
#
|
14
|
+
# Blocks HTTP requests with an unrecognized hostname in any of the following
|
15
|
+
# HTTP headers: Host, X-Forwarded-Host, Forwarded
|
16
|
+
#
|
17
|
+
# If you want to permit a specific hostname, you can pass in as the `:permitted_hosts` option:
|
18
|
+
#
|
19
|
+
# use Rack::Protection::HostAuthorization, permitted_hosts: ["www.example.org", "sinatrarb.com"]
|
20
|
+
#
|
21
|
+
# The `:allow_if` option can also be set to a proc to use custom allow/deny logic.
|
22
|
+
class HostAuthorization < Base
|
23
|
+
DOT = '.'
|
24
|
+
PORT_REGEXP = /:\d+\z/.freeze
|
25
|
+
SUBDOMAINS = /[a-z0-9\-.]+/.freeze
|
26
|
+
private_constant :DOT,
|
27
|
+
:PORT_REGEXP,
|
28
|
+
:SUBDOMAINS
|
29
|
+
default_reaction :deny
|
30
|
+
default_options allow_if: nil,
|
31
|
+
message: 'Host not permitted'
|
32
|
+
|
33
|
+
def initialize(*)
|
34
|
+
super
|
35
|
+
@permitted_hosts = []
|
36
|
+
@domain_hosts = []
|
37
|
+
@ip_hosts = []
|
38
|
+
@all_permitted_hosts = Array(options[:permitted_hosts])
|
39
|
+
|
40
|
+
@all_permitted_hosts.each do |host|
|
41
|
+
case host
|
42
|
+
when String
|
43
|
+
if host.start_with?(DOT)
|
44
|
+
domain = host[1..-1]
|
45
|
+
@permitted_hosts << domain.downcase
|
46
|
+
@domain_hosts << /\A#{SUBDOMAINS}#{Regexp.escape(domain)}\z/i
|
47
|
+
else
|
48
|
+
@permitted_hosts << host.downcase
|
49
|
+
end
|
50
|
+
when IPAddr then @ip_hosts << host
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def accepts?(env)
|
56
|
+
return true if options[:allow_if]&.call(env)
|
57
|
+
return true if @all_permitted_hosts.empty?
|
58
|
+
|
59
|
+
request = Request.new(env)
|
60
|
+
origin_host = extract_host(request.host_authority)
|
61
|
+
forwarded_host = extract_host(request.forwarded_authority)
|
62
|
+
|
63
|
+
debug env, "#{self.class} " \
|
64
|
+
"@all_permitted_hosts=#{@all_permitted_hosts.inspect} " \
|
65
|
+
"@permitted_hosts=#{@permitted_hosts.inspect} " \
|
66
|
+
"@domain_hosts=#{@domain_hosts.inspect} " \
|
67
|
+
"@ip_hosts=#{@ip_hosts.inspect} " \
|
68
|
+
"origin_host=#{origin_host.inspect} " \
|
69
|
+
"forwarded_host=#{forwarded_host.inspect}"
|
70
|
+
|
71
|
+
if host_permitted?(origin_host)
|
72
|
+
if forwarded_host.nil?
|
73
|
+
true
|
74
|
+
else
|
75
|
+
host_permitted?(forwarded_host)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def extract_host(authority)
|
85
|
+
authority.to_s.split(PORT_REGEXP).first&.downcase
|
86
|
+
end
|
87
|
+
|
88
|
+
def host_permitted?(host)
|
89
|
+
exact_match?(host) || domain_match?(host) || ip_match?(host)
|
90
|
+
end
|
91
|
+
|
92
|
+
def exact_match?(host)
|
93
|
+
@permitted_hosts.include?(host)
|
94
|
+
end
|
95
|
+
|
96
|
+
def domain_match?(host)
|
97
|
+
return false if host.nil?
|
98
|
+
return false if host.start_with?(DOT)
|
99
|
+
|
100
|
+
@domain_hosts.any? { |domain_host| host.match?(domain_host) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def ip_match?(host)
|
104
|
+
@ip_hosts.any? { |ip_host| ip_host.include?(host) }
|
105
|
+
rescue IPAddr::InvalidAddressError
|
106
|
+
false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/rack/protection.rb
CHANGED
@@ -12,6 +12,7 @@ module Rack
|
|
12
12
|
autoload :EscapedParams, 'rack/protection/escaped_params'
|
13
13
|
autoload :FormToken, 'rack/protection/form_token'
|
14
14
|
autoload :FrameOptions, 'rack/protection/frame_options'
|
15
|
+
autoload :HostAuthorization, 'rack/protection/host_authorization'
|
15
16
|
autoload :HttpOrigin, 'rack/protection/http_origin'
|
16
17
|
autoload :IPSpoofing, 'rack/protection/ip_spoofing'
|
17
18
|
autoload :JsonCsrf, 'rack/protection/json_csrf'
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-protection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- https://github.com/sinatra/sinatra/graphs/contributors
|
8
|
+
autorequire:
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date:
|
11
|
+
date: 2024-11-18 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: base64
|
@@ -77,6 +78,7 @@ files:
|
|
77
78
|
- lib/rack/protection/escaped_params.rb
|
78
79
|
- lib/rack/protection/form_token.rb
|
79
80
|
- lib/rack/protection/frame_options.rb
|
81
|
+
- lib/rack/protection/host_authorization.rb
|
80
82
|
- lib/rack/protection/http_origin.rb
|
81
83
|
- lib/rack/protection/ip_spoofing.rb
|
82
84
|
- lib/rack/protection/json_csrf.rb
|
@@ -98,6 +100,7 @@ metadata:
|
|
98
100
|
homepage_uri: http://sinatrarb.com/protection/
|
99
101
|
documentation_uri: https://www.rubydoc.info/gems/rack-protection
|
100
102
|
rubygems_mfa_required: 'true'
|
103
|
+
post_install_message:
|
101
104
|
rdoc_options: []
|
102
105
|
require_paths:
|
103
106
|
- lib
|
@@ -112,7 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
115
|
- !ruby/object:Gem::Version
|
113
116
|
version: '0'
|
114
117
|
requirements: []
|
115
|
-
rubygems_version: 3.
|
118
|
+
rubygems_version: 3.5.22
|
119
|
+
signing_key:
|
116
120
|
specification_version: 4
|
117
121
|
summary: Protect against typical web attacks, works with all Rack apps, including
|
118
122
|
Rails.
|