Back to Home

Configuring NaiveProxy in sing-box: a secure alternative to VLESS

The article describes setting up NaiveProxy using sing-box and Caddy. Mechanisms of masking through the Chromium stack, fixing the padding vulnerability, and TLS termination configuration are discussed in detail. Practical recommendations for middle/senior developers are provided.

NaiveProxy: complete setup instructions with Chromium stack
Advertisement 728x90

# NaiveProxy: A Secure Alternative to VLESS Based on Chromium

Amid aggressive blocking efforts, the NaiveProxy protocol offers a unique traffic camouflage approach—leveraging Chromium's original networking stack. We'll walk through setting up the client and server using sing-box and Caddy, dodging common pitfalls.

Traffic Camouflage Basics: Why NaiveProxy Beats uTLS?

Standard proxy protocols disguise themselves as HTTPS traffic, but the initial ClientHello packet stays vulnerable. It sends the TLS version, cipher list, and domain in plaintext. Go-based implementations (including Xray and sing-box) feature a telltale ClientHello fingerprint unique to the language, making them identifiable even with uTLS. The uTLS library only mimics browser behavior in that first packet, failing to replicate network stack subtleties like data transmission rhythm, frame lengths, and HTTP/2 quirks. NaiveProxy tackles this head-on by embedding a Chromium fragment that delivers pixel-perfect browser traffic emulation.

NaiveProxy Architecture: From Chromium to Proxy

The protocol's creator, klzgrad, stripped Chromium's source code down to just 0.3% of its functionality, keeping only what's needed for networking. Key features:

Google AdInline article slot
  • Uses Chromium's native HTTP/2 stack for multiplexing
  • Perfect match for ClientHello and subsequent packets to real browser traffic
  • Ditches custom ciphers for standard TLS mechanisms

Important: It's fully compatible with standard HTTP/2 proxies in both directions. Naive clients work with any HTTP/2 proxy, and Naive servers accept connections from standard clients. But true camouflage only happens with Chromium's network stack—like in sing-box. Other clients (e.g., Go-based ones) may connect to a Naive server but won't provide full anonymity.

Padding: Three Layers of Protection Against Traffic Analysis

The protocol employs multi-level padding to thwart packet length analysis:

  • DATA frames: The first 8 frames of each stream add a header (2 bytes for data length + 1 byte for padding length), followed by original data and padding bytes.
  • CONNECT requests: Random-length headers bulk up frame sizes arbitrarily.
  • END_STREAM: Extra frames before each RST_STREAM.

Testing revealed a critical flaw in sing-box: Instead of zeroing the buffer when adding padding, it sent leftover data from prior requests. This leaked sensitive info (like domain names and headers). Fixed in versions 1.13.1+ after merging two PRs that force buffer zeroing.

Google AdInline article slot

Client Setup: sing-box Outbound

Requires sing-box 1.13+. Client config:

{
  "type": "naive",
  "tag": "Proxy1",
  "server": "1.2.3.4",
  "server_port": 443,
  "username": "username",
  "password": "password",
  "insecure_concurrency": 1,
  "udp_over_tcp": {
    "enabled": true
  },
  "quic": false,
  "tls": {
    "enabled": true,
    "server_name": "s1.example.com"
  }
}

Key parameters:

  • insecure_concurrency: Stick to 1. Higher values make traffic easier to analyze.
  • udp_over_tcp: Enable for UDP support.
  • server_name: Domain set up in Caddy. Must match the TLS section's server_name.

Caddy as TLS Terminator: Config and Fallback

Caddy handles TLS connections and routes traffic to the proxy or a decoy. Config (/etc/caddy/Caddyfile):

Google AdInline article slot
{
    email [email protected]
    auto_https disable_redirects
}

:443, https://s1.example.com {
    tls {
        issuer acme {
            disable_http_challenge
        }
    }

    route {
        @naive {
            method CONNECT
            header Proxy-Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
        }

        handle @naive {
            reverse_proxy h2c://127.0.0.1:1080 {
                header_up Proxy-Authorization {header.Proxy-Authorization}
            }
        }

        handle {
            root * /srv/naive-fallback
            file_server
        }
    }
}

Key points:

  • Proxy-Authorization header holds base64-encoded username:password (generate with echo -n "username:password" | base64).
  • /srv/naive-fallback directory serves a static decoy site to fend off scans.
  • auto_https disable_redirects skips HTTP→HTTPS redirects since port 443 is HTTPS-only.

Server Side: sing-box Inbound and Caddy Integration

Server sing-box config (/etc/sing-box/config.json):

{
  "log": {
    "level": "warn",
    "output": "/var/log/sing-box/sing-box.log"
  },
  "inbounds": [
    {
      "type": "naive",
      "tag": "naive-in",
      "network": "tcp",
      "listen": "127.0.0.1",
      "listen_port": 1080,
      "users": [
        {
          "username": "username",
          "password": "password"
        }
      ]
    }
  ],
  "outbounds": [
    {
      "type": "direct"
    }
  ]
}

Important:

  • Server listens only on localhost:1080, as Caddy handles external connections.
  • warn log level minimizes disk I/O.
  • Passwords must exactly match client and Caddy settings.

Key Takeaways

  • Full camouflage needs Chromium stack: Only implementations using the original network code (like sing-box) match browser traffic perfectly.
  • Concurrency = risk: insecure_concurrency over 1 heightens vulnerability to packet length analysis.
  • Keep components updated: Use sing-box 1.13.1+ to fix padding data leaks.
  • Decoy site is essential: Static site in Caddy hides the proxy from scans.
  • Reality isn't foolproof: As Reality's history shows, even clever solutions can get blocked by new fingerprints (e.g., connection counts).

— Editorial Team

Advertisement 728x90

Read Next