ssrf_filter 1.5.0 → 1.6.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/lib/ssrf_filter/ssrf_filter.rb +32 -2
- data/lib/ssrf_filter/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '05509e34ae84e22f9e746604ec7717a095ea88a237c13dfabb2d840e24b38816'
|
|
4
|
+
data.tar.gz: 1c6694c52b643ec4992fd19c1822eb225c4e87d9cf75bd2b1b2654a5f06f9b10
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 352ca8aa91c7408f1b84d0791378e463da9e356feab9559209a05c43049879acf5f88445126fbb9532ce979a5ffed7960a057d9409399f5cba805cb062e19761
|
|
7
|
+
data.tar.gz: dbbdbb309c241adc37d81dc2f7a128834ce0bf04f0b87662121280aa37e81ddce6a39b2a206972fc63d72c492db81108ec67165bb7d3d5b8be45f1c46c579a55
|
|
@@ -59,13 +59,18 @@ class SsrfFilter
|
|
|
59
59
|
NAT64_LOCAL_PREFIX = ::IPAddr.new('64:ff9b:1::/48').freeze
|
|
60
60
|
|
|
61
61
|
IPV6_BLACKLIST = ([
|
|
62
|
+
::IPAddr.new('::/128'), # Unspecified address
|
|
62
63
|
::IPAddr.new('::1/128'), # Loopback
|
|
63
64
|
::IPAddr.new('100::/64'), # Discard prefix (RFC 6666)
|
|
65
|
+
::IPAddr.new('100:0:0:1::/64'), # Dummy IPv6 prefix (RFC 9780)
|
|
64
66
|
::IPAddr.new('2001::/32'), # Teredo tunneling
|
|
67
|
+
::IPAddr.new('2001:2::/48'), # Benchmarking (RFC 5180)
|
|
65
68
|
::IPAddr.new('2001:10::/28'), # Deprecated (previously ORCHID)
|
|
66
69
|
::IPAddr.new('2001:20::/28'), # ORCHIDv2
|
|
67
70
|
::IPAddr.new('2001:db8::/32'), # Addresses used in documentation and example source code
|
|
68
71
|
::IPAddr.new('2002::/16'), # 6to4
|
|
72
|
+
::IPAddr.new('3fff::/20'), # Documentation (RFC 9637)
|
|
73
|
+
::IPAddr.new('5f00::/16'), # Segment Routing (SRv6) SIDs (RFC 9602)
|
|
69
74
|
::IPAddr.new('fc00::/7'), # Unique local address
|
|
70
75
|
::IPAddr.new('fe80::/10'), # Link-local address
|
|
71
76
|
::IPAddr.new('ff00::/8') # Multicast
|
|
@@ -94,6 +99,15 @@ class SsrfFilter
|
|
|
94
99
|
DEFAULT_SENSITIVE_HEADERS = %w[authorization cookie].freeze
|
|
95
100
|
DEFAULT_ON_CROSS_ORIGIN_REDIRECT = :strip
|
|
96
101
|
|
|
102
|
+
CONNECTION_ERRORS = [
|
|
103
|
+
::Errno::EHOSTUNREACH,
|
|
104
|
+
::Errno::ENETUNREACH,
|
|
105
|
+
::Errno::EADDRNOTAVAIL,
|
|
106
|
+
::Errno::ECONNREFUSED,
|
|
107
|
+
::Errno::ETIMEDOUT,
|
|
108
|
+
::Net::OpenTimeout
|
|
109
|
+
].freeze
|
|
110
|
+
|
|
97
111
|
VERB_MAP = {
|
|
98
112
|
get: ::Net::HTTP::Get,
|
|
99
113
|
put: ::Net::HTTP::Put,
|
|
@@ -156,7 +170,7 @@ class SsrfFilter
|
|
|
156
170
|
[]
|
|
157
171
|
end
|
|
158
172
|
|
|
159
|
-
response, url =
|
|
173
|
+
response, url = fetch_with_fallback(uri, public_addresses, method,
|
|
160
174
|
options.merge(headers_to_strip: headers_to_strip), &block)
|
|
161
175
|
return response if url.nil?
|
|
162
176
|
end
|
|
@@ -206,6 +220,18 @@ class SsrfFilter
|
|
|
206
220
|
end
|
|
207
221
|
end
|
|
208
222
|
|
|
223
|
+
private_class_method def self.fetch_with_fallback(uri, public_addresses, verb, options, &block)
|
|
224
|
+
last_error = nil
|
|
225
|
+
|
|
226
|
+
public_addresses.shuffle.each do |ip_address|
|
|
227
|
+
return fetch_once(uri.dup, ip_address.to_s, verb, options, &block)
|
|
228
|
+
rescue *CONNECTION_ERRORS => e
|
|
229
|
+
last_error = e
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
raise last_error
|
|
233
|
+
end
|
|
234
|
+
|
|
209
235
|
private_class_method def self.fetch_once(uri, ip, verb, options, &block)
|
|
210
236
|
if options[:params]
|
|
211
237
|
params = uri.query ? ::URI.decode_www_form(uri.query).to_h : {}
|
|
@@ -217,6 +243,10 @@ class SsrfFilter
|
|
|
217
243
|
request['host'] = normalized_hostname(uri)
|
|
218
244
|
|
|
219
245
|
Array(options[:headers]).each do |header, value|
|
|
246
|
+
# Newer rubies raise ArgumentError when assigning a header name with control characters, which
|
|
247
|
+
# would pre-empt the CRLFInjection check in validate_request, so reject it with our own error here
|
|
248
|
+
raise CRLFInjection, "CRLF injection in header #{header} with value #{value}" if header.to_s.count("\r\n") != 0
|
|
249
|
+
|
|
220
250
|
request[header] = value
|
|
221
251
|
end
|
|
222
252
|
|
|
@@ -244,7 +274,7 @@ class SsrfFilter
|
|
|
244
274
|
ipaddr: ip
|
|
245
275
|
)
|
|
246
276
|
|
|
247
|
-
::Net::HTTP.start(uri.hostname, uri.port, **http_options) do |http|
|
|
277
|
+
::Net::HTTP.start(uri.hostname, uri.port, nil, **http_options) do |http|
|
|
248
278
|
response = http.request(request) do |res|
|
|
249
279
|
block&.call(res)
|
|
250
280
|
end
|
data/lib/ssrf_filter/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ssrf_filter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Arkadiy Tetelman
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
181
181
|
- !ruby/object:Gem::Version
|
|
182
182
|
version: '0'
|
|
183
183
|
requirements: []
|
|
184
|
-
rubygems_version: 3.
|
|
184
|
+
rubygems_version: 3.3.7
|
|
185
185
|
signing_key:
|
|
186
186
|
specification_version: 4
|
|
187
187
|
summary: A gem that makes it easy to prevent server side request forgery (SSRF) attacks
|