ssrf_filter 1.1.0 → 1.1.1
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/patch/resolv.rb +44 -0
- data/lib/ssrf_filter/patch/ssl_socket.rb +3 -2
- data/lib/ssrf_filter/ssrf_filter.rb +9 -5
- data/lib/ssrf_filter/version.rb +1 -1
- data/lib/ssrf_filter.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0230e20c7cd24b24dad277ee01042f3a4885fa68a8ea593fe0607de92023026
|
4
|
+
data.tar.gz: 6ce71a83907b1acfc382acc5d859a26fc1471dc3cd2dbc48d14b3e1dfca12051
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb56468fb4bdcf10168efbc18f004d996363b9dcc8877a1fab1eff508ef1519b86c7eeb750fedd8b565a162804746f9a036b54e584520137c1c2b1a86d5c9421
|
7
|
+
data.tar.gz: 9d5e0ea62956d551caa2474a384fa90e827c6d133bbfe04831f77dd49cabe5bcb3abc7008eefc63bccedf1634a33bcc27f8178253ec26f7e051075dcfba7066e
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'resolv'
|
4
|
+
|
5
|
+
class SsrfFilter
|
6
|
+
module Patch
|
7
|
+
module Resolv
|
8
|
+
# As described in ssl_socket.rb, we want to patch ruby's http connection code to allow us to make outbound network
|
9
|
+
# requests while ensuring that both:
|
10
|
+
# 1) we're connecting to a public / non-private ip address
|
11
|
+
# 2) https connections continue to work
|
12
|
+
#
|
13
|
+
# This used to work fine prior to this change in ruby's net/http library:
|
14
|
+
# https://github.com/ruby/net-http/pull/36
|
15
|
+
# After this changed was introduced our patch no longer works - we need to set the hostname to the correct
|
16
|
+
# value on the SSLSocket (`s.hostname = ssl_host_address`), but that code path no longer executes due to the
|
17
|
+
# modification in the linked pull request.
|
18
|
+
#
|
19
|
+
# To work around this we introduce the patch below, which forces our ip address string to not match against the
|
20
|
+
# Resolv IPv4/IPv6 regular expressions. This is ugly and cumbersome but I didn't see any better path.
|
21
|
+
class PatchedRegexp < Regexp
|
22
|
+
def ===(other)
|
23
|
+
if ::Thread.current.key?(::SsrfFilter::FIBER_ADDRESS_KEY) &&
|
24
|
+
other.object_id.equal?(::Thread.current[::SsrfFilter::FIBER_ADDRESS_KEY].object_id)
|
25
|
+
false
|
26
|
+
else
|
27
|
+
super(other)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.apply!
|
33
|
+
return if instance_variable_defined?(:@patched_resolv)
|
34
|
+
|
35
|
+
@patched_resolv = true
|
36
|
+
|
37
|
+
old_ipv4 = ::Resolv::IPv4.send(:remove_const, :Regex)
|
38
|
+
old_ipv6 = ::Resolv::IPv6.send(:remove_const, :Regex)
|
39
|
+
::Resolv::IPv4.const_set(:Regex, PatchedRegexp.new(old_ipv4))
|
40
|
+
::Resolv::IPv6.const_set(:Regex, PatchedRegexp.new(old_ipv6))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -35,13 +35,14 @@ class SsrfFilter
|
|
35
35
|
::OpenSSL::SSL::SSLSocket.class_eval do
|
36
36
|
original_post_connection_check = instance_method(:post_connection_check)
|
37
37
|
define_method(:post_connection_check) do |hostname|
|
38
|
-
original_post_connection_check.bind(self).call(::Thread.current[::SsrfFilter::
|
38
|
+
original_post_connection_check.bind(self).call(::Thread.current[::SsrfFilter::FIBER_HOSTNAME_KEY] ||
|
39
|
+
hostname)
|
39
40
|
end
|
40
41
|
|
41
42
|
if method_defined?(:hostname=)
|
42
43
|
original_hostname = instance_method(:hostname=)
|
43
44
|
define_method(:hostname=) do |hostname|
|
44
|
-
original_hostname.bind(self).call(::Thread.current[::SsrfFilter::
|
45
|
+
original_hostname.bind(self).call(::Thread.current[::SsrfFilter::FIBER_HOSTNAME_KEY] || hostname)
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -83,7 +83,8 @@ class SsrfFilter
|
|
83
83
|
patch: ::Net::HTTP::Patch
|
84
84
|
}.freeze
|
85
85
|
|
86
|
-
|
86
|
+
FIBER_HOSTNAME_KEY = :__ssrf_filter_hostname
|
87
|
+
FIBER_ADDRESS_KEY = :__ssrf_filter_address
|
87
88
|
|
88
89
|
class Error < ::StandardError
|
89
90
|
end
|
@@ -106,6 +107,7 @@ class SsrfFilter
|
|
106
107
|
%i[get put post delete head patch].each do |method|
|
107
108
|
define_singleton_method(method) do |url, options = {}, &block|
|
108
109
|
::SsrfFilter::Patch::SSLSocket.apply!
|
110
|
+
::SsrfFilter::Patch::Resolv.apply!
|
109
111
|
|
110
112
|
original_url = url
|
111
113
|
scheme_whitelist = options[:scheme_whitelist] || DEFAULT_SCHEME_WHITELIST
|
@@ -187,7 +189,7 @@ class SsrfFilter
|
|
187
189
|
http_options = options[:http_options] || {}
|
188
190
|
http_options[:use_ssl] = (uri.scheme == 'https')
|
189
191
|
|
190
|
-
with_forced_hostname(hostname) do
|
192
|
+
with_forced_hostname(hostname, ip) do
|
191
193
|
::Net::HTTP.start(uri.hostname, uri.port, **http_options) do |http|
|
192
194
|
http.request(request) do |response|
|
193
195
|
case response
|
@@ -219,11 +221,13 @@ class SsrfFilter
|
|
219
221
|
end
|
220
222
|
private_class_method :validate_request
|
221
223
|
|
222
|
-
def self.with_forced_hostname(hostname, &_block)
|
223
|
-
::Thread.current[
|
224
|
+
def self.with_forced_hostname(hostname, ip, &_block)
|
225
|
+
::Thread.current[FIBER_HOSTNAME_KEY] = hostname
|
226
|
+
::Thread.current[FIBER_ADDRESS_KEY] = ip
|
224
227
|
yield
|
225
228
|
ensure
|
226
|
-
::Thread.current[
|
229
|
+
::Thread.current[FIBER_HOSTNAME_KEY] = nil
|
230
|
+
::Thread.current[FIBER_ADDRESS_KEY] = nil
|
227
231
|
end
|
228
232
|
private_class_method :with_forced_hostname
|
229
233
|
end
|
data/lib/ssrf_filter/version.rb
CHANGED
data/lib/ssrf_filter.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.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkadiy Tetelman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler-audit
|
@@ -144,6 +144,7 @@ extensions: []
|
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
146
|
- lib/ssrf_filter.rb
|
147
|
+
- lib/ssrf_filter/patch/resolv.rb
|
147
148
|
- lib/ssrf_filter/patch/ssl_socket.rb
|
148
149
|
- lib/ssrf_filter/ssrf_filter.rb
|
149
150
|
- lib/ssrf_filter/version.rb
|