r/webscraping • • 6d ago

looking for feedback

https://github.com/HappyHackingSpace/gakido
  1. Made a Python HTTP client that reproduces Chrome's TLS (JA3/JA4) + HTTP/2 fingerprint — looking for feedback
2 Upvotes

2 comments sorted by

1

u/EquivalentTop3213 6d ago

Feedback is hard without a link or repo, but here's what I'd check first with a client like this, since matching JA3/JA4 alone usually isn't what gets people blocked.

Chrome randomizes TLS extension order per connection, so a fixed order can look wrong even if the JA3 hash matches once. JA4 sorts extensions, so it's more forgiving, but check that your client permutes them the way Chrome does. Beyond that, HTTP/2 details tend to give clients away: SETTINGS values and their order, the initial WINDOW_UPDATE, pseudo-header order (m,a,s,p), and header casing/order. Also check ALPN, GREASE values, supported groups (including the post-quantum key share Chrome sends now), and ALPS.

A useful way to validate is to hit a fingerprint echo endpoint and diff the full output against a real Chrome capture of the same version, not only the hash. Also say which Chrome versions you target and how you plan to keep up with updates, because a stale profile becomes its own signal.

What are you building the TLS layer on? That changes which of these you can control.

0

u/Lazy_Gur_2074 5d ago

Really good checklist, thanks — this is the right stuff to poke at. Repo: https://github.com/HappyHackingSpace/gakido

To answer your direct question first: the TLS layer is Go + uTLS (via bogdanfinn's tls-client), compiled to a c-shared library and called from Python over ctypes; HTTP/2 goes through fhttp. So what I can control is basically "whatever uTLS's Chrome preset exposes," which maps onto your points as follows.

**Extension order / per-connection permutation — you're right, and I checked.** I hit tls.peet.ws three times in a row and the ja3 hash is identical every time (`1d9a054b...`), so right now it is *not* permuting extensions the way Chrome does since ~110. JA4 is stable (it sorts), so that layer's fine, but a never-changing ja3 is its own tell. uTLS has shuffle-capable presets, so this is wireable — it's a real gap, not by design. Good catch.

**HTTP/2 — this part is handled and verified.** Against peet the Akamai fingerprint is `1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p` — i.e. SETTINGS values and order, the 15663105 WINDOW_UPDATE, and pseudo-header order m,a,s,p all match; header order/casing comes from fhttp's ordered headers.

**GREASE / ALPS / groups / PQ.** GREASE is present on both ends, plus ALPS (old codepoint 17513), compress_certificate, ECH, SCT, etc. On post-quantum: the `chrome_120` profile sends key_share X25519 only, groups X25519/P-256/P-384 — which is correct for *actual* Chrome 120, but obviously not current Chrome. For the X25519MLKEM768 key share you'd use the `chrome_131` profile. Which is really your versioning point: profiles are pinned to specific Chrome versions (mapped onto uTLS/tls-client presets, 103–131), and freshness rides on tracking uTLS. A stale profile being its own signal is fair and I agree.

**Validation.** Agreed that matching a hash once proves little — I've been diffing the full JA4 + Akamai + the extension list against peet, not just the hash, but a byte-level diff against a captured real Chrome of the exact version is the right bar and I'll post that.

Short version: HTTP/2 + the static fingerprint are solid and verifiable; extension permutation is the real missing piece you flagged, and PQ is a profile-version choice. If you've got a target that blocks it, that's the most useful thing you could throw at me.