Cache and transport fingerprints
Transport preservation is automatic only inside cache-enabled HTTPS connections. Without a cache suffix, Litport leaves CONNECT opaque and does not terminate the client's TLS connection. With cache mode, Litport attempts to reproduce the supported fingerprint shape on origin-bound misses and bypasses; unsupported input uses one verified standard TLS profile instead. A cache hit makes no origin connection at all.
This feature reduces transport differences introduced by HTTPS interception. It does not impersonate a different client: curl remains curl, Chrome remains Chrome, and a mobile app keeps the compatible traits Litport actually observed from that app.
Exactly when it runs#
The existing password suffix enables both caching and transport-shape preservation:
PASSWORD_cache-images,fonts
PASSWORD_cache-all_cacheduration-30
Litport attempts preservation when all of these are true:
- The client uses the Litport HTTP proxy endpoint and sends
CONNECTfor an HTTPS target. - The password contains a valid cache suffix and authentication succeeds.
- The hub's cache and certificate authority are ready, so Litport accepts cache interception.
If the password has no cache suffix, the CONNECT tunnel stays opaque. Litport forwards the client's TLS records and encrypted HTTP bytes without reading or rewriting them. “Unchanged” refers to the application transport through Litport: the target still sees the selected proxy exit IP and that exit's TCP/IP behavior, not the customer's local network identity.
If cache interception cannot be admitted before CONNECT begins, Litport keeps the existing opaque path. Plain HTTP targets, SOCKS5 ingress, and HTTP/3/QUIC do not enter this feature.
What happens on the wire#
A cache-enabled CONNECT has two independent TLS connections:
client ── TLS leg 1 ──> Litport hub ── TLS leg 2 ──> verified HTTPS origin
Litport CA cache public Web PKI
The implementation processes them in this order:
- Observe the ClientHello. A bounded, memory-only observer reassembles the first TLS handshake message across TLS records while passing the exact input to the verified standard TLS stack. The captured bytes live only inside that CONNECT and are never used as cryptographic material.
- Complete the client handshake. The client verifies the target certificate issued by the Litport cache CA. Litport verifies that TLS SNI matches the authenticated CONNECT authority.
- Parse HTTP safely. The negotiated ALPN selects the inbound HTTP/1.1 or HTTP/2 server. Bounded observers retain only the ordering and connection settings needed for reproduction.
- Check the local cache. A hit is returned immediately. There is no origin socket, ClientHello, HTTP request, or target-side fingerprint for that hit.
- Keep the selected route. A miss or intercepted bypass opens the origin through the same Litport route, product, pool, geography, and accounting path already selected for the request. Preservation never performs its own direct DNS route around the proxy.
- Create fresh origin TLS. Litport sanitizes the observed profile, creates new cryptographic values, verifies the origin hostname and certificate chain, and offers the compatible observed protocols. The origin's ALPN result chooses HTTP/1.1 or HTTP/2 on that same live connection.
- Serialize the request. Litport emits the supported HTTP shape, streams request and response bodies, and applies the ordinary cache and decoded-byte accounting rules.
No raw ClientHello, header block, JA3/JA4 value, or per-client profile identifier is written to persistent storage or operational logs.
What is preserved—and what must be new#
TLS ClientHello shape#
For a supported ClientHello, Litport preserves compatible observable structure such as:
- protocol-version and cipher-suite ordering;
- extension ordering and safe compatible extension contents;
- supported-group, signature-algorithm, point-format, and ALPN ordering;
- key-share group order, certificate-compression choices, GREASE positions, and compatible padding.
Every origin connection gets a fresh client random, session ID, and key share. Litport removes PSK identities and binders, keeps only an empty session-ticket offer when that extension was present, and does not replay early data, TLS cookies, or other connection-bound material. A GREASE ECH placeholder is regenerated safely in the same position; a real ECH payload is not replayed. Opaque extensions are rejected by default; the reviewed exception is the empty, stateless OpenSSL extension pair used by common curl builds.
HTTP/1.1 shape#
Litport preserves the order and original casing of fields that remain after proxy sanitation,
including repeated field positions. Proxy-only credentials are always stripped. Message framing is
reconstructed from the parsed body, so Content-Length or Transfer-Encoding remains valid even when
its observed position and casing can be retained. Fields added only by the HTTP parser are not mistaken
for client input or forwarded as part of the shape, and Litport does not add a default User-Agent when
the client sent none.
Upgrades, Expect: 100-continue, malformed framing, or an observer/parser mismatch use deterministic
standard HTTP serialization. They do not cause Litport to change the TLS profile halfway through a
CONNECT.
HTTP/2 shape#
Litport preserves supported initial SETTINGS order and values, connection WINDOW_UPDATE behavior,
pre-request PRIORITY frames, per-request HEADERS priority, pseudo-header order, and regular field
order. A single Cookie field remains one field instead of being split at semicolons, and an absent
User-Agent remains absent. A request with no body ends on its initial HEADERS frame instead of
gaining a synthetic empty DATA frame. Request metadata is isolated per stream so concurrent requests
cannot borrow another stream's shape.
Exact HPACK bytes and dynamic-table history are not a compatibility promise. Responses, cache hits, concurrency, and connection reuse can make the two compression histories diverge even when the same fields appear in the same order.
Implementation boundaries#
The preservation state belongs to one authenticated CONNECT. It is never shared across customers, tokens, target authorities, or later client connections.
| Stage | Bound and lifetime | If observation cannot be reproduced safely |
|---|---|---|
| ClientHello | Up to 64 KiB, memory-only, for the current CONNECT | Use one verified standard TLS profile for that CONNECT |
| HTTP/1.1 request observation | Up to 72 KiB for an active header/trailer block and 16 queued pipelined headers | Use deterministic HTTP/1.1 serialization on the already chosen TLS identity |
| HTTP/2 connection observation | Up to 64 KiB from the client preface through the first HEADERS frame | Use deterministic HTTP/2 defaults on the already chosen TLS identity |
| Origin connections | A private HTTP/1.1 or HTTP/2 pool owned by the current CONNECT | Close the pool when the CONNECT ends; never share TLS or compression history with another client |
For HTTP/1.1, the observer tracks fixed-length and chunked bodies—including trailers—so bytes inside a body cannot be mistaken for the next pipelined request. Before applying an observed field sequence, Litport matches the method, request target, and canonical field/value counts against the parsed request. Proxy authentication fields are removed regardless of their observed position.
For HTTP/2, Litport combines two views. A frame-level observer captures the initial SETTINGS, connection WINDOW_UPDATE, and pre-request PRIORITY frames. The HTTP/2 decoder attaches only the current stream's pseudo-header order, regular-field order, and HEADERS priority to that request's in-memory context. The origin transport then uses those values on the matching stream, which prevents concurrent requests from borrowing each other's ordering or priority.
When the client CONNECT ends, Litport closes both the protocol pool and every raw origin socket owned by it. This also terminates an HTTP/2 read loop that is still retiring its final stream; it cannot live on and become available to a later CONNECT.
The origin socket is always opened through Litport's already selected upstream route. Hostname and public-chain verification remain enabled. The HTTP engine is chosen from the origin's ALPN result on that same socket; Litport does not reconnect just to obtain a preferred protocol. If an HTTP/2 client reaches an HTTP/1.1-only origin, the request uses ordered HTTP/1.1.
Why a fully identical fingerprint is impossible#
TLS interception cannot preserve the complete connection byte for byte. Litport is one TLS server to the client and a separate TLS client to the target. Reusing the first connection's secrets on the second connection would be invalid and insecure.
The following necessarily differ or may diverge:
| Signal | Why it cannot be identical |
|---|---|
| TLS randoms, key shares, binders and transcript | They are cryptographically bound to one handshake. |
| Session tickets, PSK identity and 0-RTT | A ticket issued for the client-to-Litport leg is not valid at the origin. |
| Server certificate and ServerHello | The client sees a Litport-issued target certificate; Litport sees the origin's public certificate. |
| TCP SYN, source address and operating-system stack | The target connection originates from the selected proxy exit. |
| TLS records, packet sizes and timing | Buffering, routing, cache lookup, scheduling and network conditions create new boundaries. |
| HTTP/2 flow control, reuse and HPACK history | Hits remove requests from the origin leg and both connections evolve independently. |
The honest guarantee is therefore compatible transport fingerprint-shape preservation, not full fingerprint preservation. It targets the stable features commonly consumed by JA3, JA4, and HTTP/2 fingerprinting while keeping all connection-bound material fresh.
Fallback and failure rules#
Safety takes priority over resemblance:
- A supported capture uses the sanitized preserved TLS profile for every origin connection belonging to that client CONNECT.
- An oversized, malformed, or unsafe ClientHello uses the verified standard TLS profile for that entire CONNECT. Litport never alternates two TLS identities within one client tunnel.
- Request-specific HTTP metadata can fall back to deterministic standard serialization without changing the CONNECT's chosen TLS profile.
- If a preserved origin handshake has sent bytes and fails, Litport returns an origin error. It does not retry with a contradictory ClientHello or weaken certificate verification.
- Every origin dial is restricted to the authenticated CONNECT authority and still uses the selected upstream route.
Customers see cache hit, miss, and bypass, plus free bytes and savings, in Traffic statistics and the Account API. Transport preservation has no customer-facing per-request status.
Client and protocol behavior#
| Client or protocol | Cache-enabled behavior |
|---|---|
| curl, SDKs and command-line clients | Works when that process trusts the Litport cache root. Their own compatible TLS/HTTP shape is reproduced; they are not changed into browsers. |
| Chrome, Firefox and browser automation | HTTP/1.1 and HTTP/2 shape can be preserved. The browser profile must trust the Litport root without disabling certificate checks. |
| Android and iOS apps you control | Works when the app's effective trust configuration accepts the Litport root and the app does not pin the target certificate. |
| Certificate-pinned apps | Cache interception fails by design. Remove the cache suffix to use an opaque tunnel. |
| Real ECH | Its encrypted payload is bound to the original server configuration and cannot be replayed on Litport's separate origin TLS leg; cache interception is unsupported. |
| HTTP/3/QUIC | Not part of the TCP CONNECT cache path. Applications may negotiate HTTP/2 instead. |
| Plain HTTP and SOCKS5 | Never intercepted by this feature. They keep their existing uncached behavior. |
See certificate setup for per-client trust instructions.
Verify with a fingerprint endpoint#
For an optional external check, make one opaque request and one cache-enabled intercepted request through the same hub. The endpoint below returns JA3, JA4, HTTP/2, and TCP observations:
# Opaque: Litport does not terminate TLS
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
'https://tls.peet.ws/api/all'
# Intercepted bypass: extensionless diagnostic URL is not stored, but transport preservation runs
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
--cacert litport-cache-root.crt \
'https://tls.peet.ws/api/all'
# A second independent JA3/JA4 and HTTP/2 view
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
'https://tls.browserleaks.com/json'
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
--cacert litport-cache-root.crt \
'https://tls.browserleaks.com/json'
Compare tls.ja3_hash, tls.ja4, the ordered TLS fields, and the HTTP/2 fingerprint. Do not compare
client_random, session_id, source IP, TCP fingerprint, or timing; those are expected to change.
On the BrowserLeaks response, the equivalent fields are ja3_hash, ja4, and akamai_hash.
This is a third-party diagnostic service, so it will observe the proxy exit IP and request metadata.
Use it only when that disclosure is acceptable.
Further reading#
The Litport blog post TLS fingerprinting through a proxy: JA3 and JA4 explains how opaque tunnels, intercepting proxies, and cache mode each affect JA3, JA4, and HTTP/2 fingerprints, with measured results for common clients.
Return to the cache overview or review eligibility and troubleshooting.