Saltar al contenido principal
en/blog/obscura/research/mitm-approaches/

obscura/research/mitm-approaches

3 min read

Overview

Obscura requires a MitM (Man-in-the-Middle) proxy to intercept and modify HTTPS traffic. This document evaluates the available options.

Approaches

Approach 1: Go mitmproxy Library

Library: github.com/elazarl/goproxy

Pros:

  • Mature, well-tested
  • Handles CONNECT tunnels automatically
  • Supports response modification
  • MITM with on-the-fly certificate generation

Cons:

  • HTTP/2 support is limited
  • Large dependency tree
  • Not designed for transparent proxy

Approach 2: Custom Rust Proxy with tokio + rustls

Pros:

  • Full control over TLS stack
  • Performance (zero-cost abstractions)
  • tokio-rustls for TLS termination
  • Hyper for HTTP/1 and HTTP/2
  • Can integrate utls for TLS fingerprint spoofing

Cons:

  • More development effort
  • Must handle certificate generation manually
  • HTTP/2 frame-level parsing required

Approach 3: Squid + External Modification

Pros:

  • Battle-tested proxy
  • SSL Bump for MITM
  • ICAP/eCAP for content modification

Cons:

  • Complex configuration
  • EOL versions still in use
  • Not designed for JS injection
  • Heavy container image

Approach 4: Envoy Proxy with Wasm Filter

Pros:

  • High performance
  • L4/L7 proxy
  • WebAssembly (Wasm) filters for modification
  • Native HTTP/2 and HTTP/3

Cons:

  • Complex configuration
  • Wasm filter development overhead
  • Not designed for client-side JS injection
  • Overkill for small-scale deployment

Approach 5: Custom TCP-Level Interception

Raw socket interception + TLS termination:

  1. Use iptables TPROXY to redirect traffic
  2. Raw TCP socket read
  3. Manual TLS handshake (via rustls/crypto/tls)
  4. HTTP/1.1 or HTTP/2 parsing
  5. Header modification + JS injection
  6. Forward to upstream

Pros:

  • Maximum control
  • No dependency on proxy frameworks
  • Can handle all edge cases

Cons:

  • Maximum development effort
  • Must implement HTTP/2 and HTTP/3 handling
  • Must handle connection pooling correctly

Recommendation

For Obscura, a custom Rust implementation (Approach 2) is the best trade-off:

  • Go's goproxy lacks HTTP/2 and TLS spoofing
  • Rust gives fine-grained control over TLS (utls integration)
  • Performance matters for a network gateway
  • Rust's safety guarantees reduce proxy bugs

Certificate Generation

For MITM, the proxy must generate TLS certificates on-the-fly:

  1. A CA certificate is generated at first startup
  2. For each new domain, a leaf certificate is signed by the CA
  3. The client must trust the CA certificate
Obscura CA (private key)
   *.example.com (leaf, generated on first request)
   *.anotherexample.com (leaf, generated on first request)

Certificate Storage

/var/lib/obscura/certs/
 ca.pem          # CA certificate (public)
 ca-key.pem      # CA private key
 cache/          # Generated leaf certs
    example.com.pem
    ...
 serial          # Certificate serial counter

Limitations

  • HPKP (HTTP Public Key Pinning): Now deprecated in Chrome, but some sites still use it
  • HSTS preloading: Sites in the HSTS preload list (e.g., google.com, stripe.com) will reject MITM certificates. Must be intercepted at DNS/network level first.
  • Certificate Transparency: Some sites require CT logs. The proxy must embed SCTs.
  • HTTP/3 (QUIC): Runs over UDP and is encrypted end-to-end. Must be blocked at the network level.

Conclusions

  • Rust with tokio-rustls + hyper is the recommended proxy stack
  • TLS fingerprint spoofing requires utls integration
  • HSTS preloaded sites must be handled at DNS/network level
  • HTTP/3 must be blocked (QUIC bypasses the proxy)