ruby / ruby/net-http

HTTPS proxy connection (p_use_ssl/proxy_use_ssl) does not verify the proxy's certificate

Open
#308 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
148
Forks
95
Avg merge
10h 54m
Merged PRs (30d)
4

Description

When connecting to a destination over TLS through a TLS proxy (an "HTTPS proxy"), enabling p_use_ssl encrypts the client→proxy hop but does not authenticate the proxy's certificate. The proxy TLS socket is built with no SSLContext and no post-connection check, so it defaults to VERIFY_NONE. This makes the proxy hop MITM-able, which matters because the Proxy-Authorization (Basic) credential is written over that socket in the CONNECT request.

Setup

Either of the documented ways to enable a TLS proxy:

  proxy = Net::HTTP.Proxy('proxy.example.com', 8080, 'user', 'pass', true)  # 5th arg -> @proxy_use_ssl
  http  = proxy.new('login.example.com', 443)
  http.use_ssl = true
  # ...or Net::HTTP.new(addr, port, p_addr, p_port, p_user, p_pass, p_no_proxy, true)
  http.get('/')
What happens

In Net::HTTP#connect, when @proxy_use_ssl is set, the proxy socket is wrapped as:

  proxy_sock = OpenSSL::SSL::SSLSocket.new(s)   # no SSLContext passed
  ssl_socket_connect(proxy_sock, @open_timeout)
  # ... then CONNECT + "Proxy-Authorization: Basic <creds>" is written to proxy_sock

SSLSocket.new(s) with no context uses a default context (verify_mode effectively VERIFY_NONE), and there is no post_connection_check on proxy_sock— the only post_connection_check in connect targets @address (the destination). So:

  • The destination cert is verified (via @ssl_context + post_connection_check(@address)). ✅
  • The proxy cert is neither verified nor hostname-checked. ❌

A MITM on the client→proxy path can therefore present any certificate, terminate the TLS, and read the Proxy-Authorization credential — the same credential exposure that enabling proxy TLS is meant to prevent.

Expected

The proxy TLS connection should verify the proxy certificate by default (use an SSLContext with VERIFY_PEER and run post_connection_check against the proxy host), consistent with how the destination connection is verified. At minimum there should be a way to supply verification settings (CA store, verify_mode, hostname) for the proxy connection distinct from the destination's.

Environment
  • Ruby 4.0.5
  • net-http 0.9.1
  • Reproduced by reading lib/net/http.rb#connect (the if @proxy_use_ssl branch) — the proxy SSLSocket is built without a context and gets no post_connection_check.
Related
  • jnunemaker/httparty#839 tracks a separate, complementary gap: HTTParty can't even set p_use_ssl (it passes only 6 of Net::HTTP.new's proxy args). This net-http issue is about the flag existing but not verifying the proxy cert.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in lib/net/http.rb#connect, specifically the @proxy_use_ssl branch that creates the proxy SSLSocket. Compare its setup with the destination TLS connection and determine how proxy certificate verification and hostname checking should be configured separately. Done means the proxy certificate is verified by default before Proxy-Authorization is sent, with any required verification settings covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
networking, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.