Metadata-Version: 2.4
Name: clienthello-probe
Version: 0.1.0
Summary: See what your HTTP client actually sends: TLS ClientHello, extension order, JA3, and header order.
Author-email: "proxy.wiki" <hello@proxy.wiki>
License: MIT
Project-URL: Homepage, https://proxy.wiki/research/tls-clienthello-fingerprints/
Project-URL: Header study, https://proxy.wiki/research/default-request-headers/
Project-URL: JA3 explained, https://proxy.wiki/glossary/ja3-fingerprint/
Keywords: tls,clienthello,ja3,fingerprint,http,headers,grease,scraping
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# clienthello-probe

See what your HTTP client actually sends. Point any client at a local listener
and read back its TLS ClientHello — extension order, cipher list, ALPN, GREASE
and JA3 — or, for plain HTTP, its exact header order.

No dependencies. Nothing is proxied anywhere: the tool reads the opening bytes
of the connection, prints them, and closes.

## Why

A client that lies about its `User-Agent` still sends the handshake its TLS
library built. That handshake is what filtering systems read first, and it is
produced below the layer most scrapers configure.

## Install

```
pip install clienthello-probe
```

## Use

```
clienthello-probe            # listens on 127.0.0.1:8443
clienthello-probe --once     # report one connection, then exit
```

Then point a client at it:

```
curl -k https://127.0.0.1:8443/     # TLS: parse the ClientHello
curl    http://127.0.0.1:8443/      # plain: show header order
```

## What it shows

Real output from `curl 8.7.1`:

```
TLS ClientHello
  hello version      TLS 1.2
  supported_versions TLS 1.3, TLS 1.2, TLS 1.1, TLS 1.0
  ALPN               h2, http/1.1

  extensions (6, in the order sent)
     1. supported_versions
     2. key_share
     3. ec_point_formats
     4. supported_groups
     5. signature_algorithms
     6. alpn

  GREASE             none sent
                     Browsers send GREASE. A client that sends none
                     is distinguishable on that alone.

  JA3 MD5            4f2655722e37c542ebeaf1eed48cbbbb
```

The same probe against a Chrome-impersonating client reports 17 extensions and
GREASE present in ciphers, extensions and groups. That difference is the point
of the tool.

For plain HTTP, `curl` sends three headers and no `Sec-Fetch-*` set. A browser
navigation sends considerably more, in its own fixed order.

## As a library

```python
from clienthello_probe import parse_client_hello, NotAClientHello

with open("hello.bin", "rb") as f:          # one raw TLS record
    hello = parse_client_hello(f.read())

print(hello["ja3"]["md5"])
print(hello["extensions"])                  # in the order sent
print(hello["grease"])                      # per-field: ciphers, extensions, groups
```

`parse_client_hello` raises `NotAClientHello` on anything that is not a
handshake record carrying a ClientHello, including a hello split across
records — it tells you to read more bytes rather than guessing.

## Notes and limits

- JA3 is computed as originally specified: five comma-separated fields with
  GREASE values removed. It is a fingerprint of the handshake, not an identity.
- The tool never completes a TLS handshake, so the client will report a
  connection error. That is expected.
- GREASE values are those reserved by RFC 8701.
- Extension names come from the IANA TLS ExtensionType registry. Unnamed
  extensions print as their number.

## Background reading

The measurement studies this tool grew out of:

- [Every browser TLS handshake differs; no library's does](https://proxy.wiki/research/tls-clienthello-fingerprints/)
- [What HTTP clients send before you configure anything](https://proxy.wiki/research/default-request-headers/)
- [JA3 fingerprint](https://proxy.wiki/glossary/ja3-fingerprint/)

## Licence

MIT.
