ruby-proxy-headers 0.2.1 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b268cd14cb2ce0cd1b3c0a59ddf0c9020f65af6cd414b23202996d3868f837e
4
- data.tar.gz: 16a7d3756a1bc7b0b90e85ce5b8dca41959f79a178238a051a256ca49b0e55fa
3
+ metadata.gz: 227e0393d4ab8a6f03fa72d69541f07a20c73cec9eb3458266dbaa0b74fee36d
4
+ data.tar.gz: 299ef710e77b061929ce18159f37e82f002c7a8522b5f0c5ed4319f3d2ab517f
5
5
  SHA512:
6
- metadata.gz: 450bd0c6e87d23873d11f0970989743c8171772d38ba8db7c3094d8badfc7eb354ad690c4b8b19a0c881255e7613e07054ca113a7f64b0a3956a2d80aacc1cb7
7
- data.tar.gz: 762c4662050a554d9b8e280766322ee5e4aee6611d9ed6fbd5414b79b3703bd5328398cb290e2ad4edb8c3a7cb46e95f3997b6f734c6d9eb5f12eb67e9f33c48
6
+ metadata.gz: deae95ea2297961bc962a5d9e476ec09b88c85a6a2ac741e1c5d1cb15972f1dc096f2b52e16a70aaca28a77ce04568f00a1109abd2edbdfee45a9727841bff61
7
+ data.tar.gz: 55096cb62498dc26f1c1695c8bc46213db91bea6be4c2d056af152cdbbabd07873bc646c2db07a2e36764f8cd8a78188942c77d15b784c3c71acc3e91e2f8a75
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Gem Version](https://badge.fury.io/rb/ruby-proxy-headers.svg)](https://badge.fury.io/rb/ruby-proxy-headers)
1
2
  # Ruby Proxy Headers
2
3
 
3
4
  Send and receive custom proxy headers during HTTPS `CONNECT` tunneling in modern Ruby HTTP workflows (for example [ProxyMesh](https://proxymesh.com) `X-ProxyMesh-IP` / `X-ProxyMesh-Country`).
@@ -31,6 +31,8 @@ module RubyProxyHeaders
31
31
  # @param target_port [Integer] Target port (default: 443)
32
32
  # @return [OpenSSL::SSL::SSLSocket] TLS-wrapped socket to target
33
33
  def connect(target_host, target_port = 443)
34
+ validate_connect_target!(target_host, target_port)
35
+
34
36
  # Connect to proxy
35
37
  @socket = TCPSocket.new(@proxy[:host], @proxy[:port])
36
38
  @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
@@ -74,6 +76,7 @@ module RubyProxyHeaders
74
76
 
75
77
  # Add custom proxy headers
76
78
  @proxy_headers.each do |name, value|
79
+ RubyProxyHeaders.validate_header!(name, value)
77
80
  request_lines << "#{name}: #{value}"
78
81
  end
79
82
 
@@ -131,6 +134,10 @@ module RubyProxyHeaders
131
134
  @socket = ssl_socket
132
135
  end
133
136
 
137
+ def validate_connect_target!(host, port)
138
+ RubyProxyHeaders.validate_connect_target!(host, port)
139
+ end
140
+
134
141
  def raise_connect_error
135
142
  case @proxy_response_status
136
143
  when 407
@@ -48,6 +48,12 @@ module RubyProxyHeaders
48
48
  @ssl_context = OpenSSL::SSL::SSLContext.new
49
49
  end
50
50
 
51
+ if use_ssl? && proxy?
52
+ # Fail before any socket I/O: CONNECT interpolates these into a raw request line.
53
+ RubyProxyHeaders.validate_connect_target!(conn_address, @port)
54
+ RubyProxyHeaders.validate_connect_target!(@address, @port)
55
+ end
56
+
51
57
  if proxy?
52
58
  conn_addr = proxy_address
53
59
  conn_port = proxy_port
@@ -82,6 +88,7 @@ module RubyProxyHeaders
82
88
  end
83
89
  if proxy_connect_request_headers&.any?
84
90
  proxy_connect_request_headers.each do |k, v|
91
+ RubyProxyHeaders.validate_header!(k, v)
85
92
  buf << "#{k}: #{v}\r\n"
86
93
  end
87
94
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyProxyHeaders
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.3'
5
5
  end
@@ -4,8 +4,35 @@ require_relative 'ruby_proxy_headers/version'
4
4
  require_relative 'ruby_proxy_headers/net_http'
5
5
 
6
6
  module RubyProxyHeaders
7
+ INVALID_HEADER_NAME_RE = /[\r\n\0]/
8
+ INVALID_HEADER_VALUE_RE = /[\r\n\0]/
9
+
7
10
  # CONNECT response headers from the last Net::HTTP-based proxied HTTPS request on this thread.
8
11
  def self.proxy_connect_response_headers
9
12
  Thread.current[:ruby_proxy_headers_connect_headers]
10
13
  end
14
+
15
+ # Raises ArgumentError if +name+ or +value+ contain CR, LF, or NUL bytes
16
+ # that would allow HTTP header injection in a raw CONNECT request.
17
+ def self.validate_header!(name, value)
18
+ if INVALID_HEADER_NAME_RE.match?(name.to_s)
19
+ raise ArgumentError, "proxy CONNECT header name contains invalid characters (CR, LF, or NUL): #{name.inspect}"
20
+ end
21
+ if INVALID_HEADER_VALUE_RE.match?(value.to_s)
22
+ raise ArgumentError, "proxy CONNECT header value contains invalid characters (CR, LF, or NUL): #{value.inspect}"
23
+ end
24
+ end
25
+
26
+ # Raises ArgumentError if +host+ or +port+ contain CR, LF, or NUL bytes that
27
+ # would allow HTTP request smuggling when interpolated into a CONNECT line.
28
+ def self.validate_connect_target!(host, port)
29
+ if INVALID_HEADER_VALUE_RE.match?(host.to_s)
30
+ raise ArgumentError,
31
+ "CONNECT target host contains invalid characters (CR, LF, or NUL): #{host.inspect}"
32
+ end
33
+ if INVALID_HEADER_VALUE_RE.match?(port.to_s)
34
+ raise ArgumentError,
35
+ "CONNECT target port contains invalid characters (CR, LF, or NUL): #{port.inspect}"
36
+ end
37
+ end
11
38
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-proxy-headers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ProxyMesh
@@ -163,6 +163,20 @@ dependencies:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
165
  version: '1.6'
166
+ - !ruby/object:Gem::Dependency
167
+ name: webmock
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '3.18'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '3.18'
166
180
  description: |
167
181
  Extensions for Ruby HTTP stacks to send custom headers on HTTPS CONNECT to a proxy
168
182
  and read headers from the proxy CONNECT response (e.g. X-ProxyMesh-IP).
@@ -207,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
221
  - !ruby/object:Gem::Version
208
222
  version: '0'
209
223
  requirements: []
210
- rubygems_version: 3.6.7
224
+ rubygems_version: 4.0.16
211
225
  specification_version: 4
212
226
  summary: Custom proxy CONNECT headers for Ruby HTTP clients (ProxyMesh, etc.)
213
227
  test_files: []