Implementing SSL/TLS Transparent Proxy for Domain-Based Filtering Without Decryption


2 views

When dealing with modern encrypted traffic, traditional transparent proxy approaches hit a fundamental limitation: you can't inspect/modify SSL/TLS traffic without performing MITM (Man-in-the-Middle) decryption. However, for domain-based filtering without content inspection, we have alternative approaches.

The primary obstacles in implementing SSL transparent proxying are:

  • SNI (Server Name Indication) extraction requires packet inspection
  • TCP connection splicing must maintain encryption integrity
  • IPVS/NAT complications with encrypted payloads

Here are three operational approaches:

# Method 1: iptables + SNI inspection
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j TPROXY \
--on-port 3128 --tproxy-mark 1/1

# Requires proxy supporting TPROXY and SNI extraction:
# Example with haproxy configuration
frontend https-in
    bind :3128 transparent
    mode tcp
    tcp-request inspect-delay 5s
    tcp-request content capture req.ssl_sni len 100
    use_backend %[req.ssl_sni,lower]

For domain whitelisting/blacklisting, consider this Python pseudocode:

def handle_sni(sni):
    with open('/etc/proxy/domains.list') as f:
        blocked_domains = set(line.strip() for line in f)
    
    if sni in blocked_domains:
        reset_connection()
    else:
        forward_traffic()

To prevent bypass attempts:

# Block direct HTTPS access except from proxy
iptables -A OUTPUT -p tcp --dport 443 -m owner ! --uid-owner proxyuser -j REJECT

# Alternative: Network-level enforcement
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 3128
Tool SNI Support Transparent Mode
HAProxy Yes Yes (TPROXY)
Nginx Yes (1.11.5+) Limited
Privoxy No No

Here's a complete configuration for domain filtering using HAProxy:

global
    tune.ssl.default-dh-param 2048

frontend https
    bind :3128 transparent
    mode tcp
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    acl valid_domain req_ssl_sni -f /etc/haproxy/allowed_domains.lst
    tcp-request content reject if !valid_domain

    use_backend upstream_%[req_ssl_sni]

backend upstream_example.com
    mode tcp
    server example 93.184.216.34:443

Note that this approach maintains full encryption while still providing domain-level access control.


Setting up a transparent proxy for SSL traffic (port 443) presents unique technical hurdles because:

  • HTTPS encrypts both the request and response, including the domain name in the initial TLS handshake (SNI)
  • Traditional transparent proxies work at layer 4 (TCP) while domain filtering requires layer 7 visibility
  • Any MITM approach would require certificate installation on clients

One working solution without breaking encryption is using DNS filtering combined with iptables:

# Example iptables rules for DNS redirection
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 53
iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-port 53

# Block direct HTTPS access if not via proxy
iptables -A FORWARD -p tcp --dport 443 -m state --state NEW -j DROP

This requires running a DNS server (like dnsmasq) with domain blacklists:

# dnsmasq.conf example
address=/bad-domain.com/127.0.0.1
address=/another-bad-site.com/0.0.0.0
server=/good-domain.com/8.8.8.8

Modern solutions can inspect Server Name Indication (SNI) in TLS handshakes:

# nftables example for SNI filtering
table inet filter {
    chain output {
        type filter hook output priority 0; policy accept;
        tcp dport 443 tls_sni "blacklisted.com" counter drop
    }
}

Tools like:

  • sniproxy - Lightweight SNI-based proxy
  • tlsproxy - MITM-capable proxy with optional decryption
  • Pound - Reverse proxy with SNI awareness

For corporate environments, consider these architectural approaches:

  1. Transparent proxy at gateway level using PF_SENSE/OPNSense
  2. Endpoint-based solutions using authenticated proxies
  3. Cloud-based secure web gateways

Example enterprise deployment:

# Enterprise firewall rules example
# Allow only proxy server to initiate HTTPS
iptables -A FORWARD -p tcp --dport 443 -s ! $PROXY_IP -j DROP

# Redirect all HTTP to proxy
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to $PROXY_IP:3128