fix: forward the visitor's own request signature on server-side detections - #47
Merged
Merged
Conversation
…tions The plugin beacons detections to the ingest service over its own HTTP connection, so the request that arrives there carries THIS SITE's outbound headers, not the visitor's. The service was composing the visitor's network identity from those — byte-identical on every beacon a given site sends — so every visitor a site ever reported was folded into one shared "actor". The platform side of this shipped first and fails safe: a forwarded detection with no visitor signature now composes no network identity at all, on the grounds that no actor beats a false one. Correct, but it means WordPress detections stopped correlating entirely. This restores them. SignalCollector::getClientSignals() builds the material and Detection carries it as `cs`. Header NAMES only, plus Accept-Language and Accept-Encoding, which are the two values the server's identity actually reads — so a visitor's cookies and Authorization header never leave the site, while the name set that carries the entropy is preserved intact. Proxy and CDN-injected names (cf-*, x-forwarded-*, true-client-ip) are excluded so the same visitor fingerprints consistently whether seen here or at a customer's edge. No TLS material: PHP is handed a decrypted request and never sees the ClientHello, so no JA3/JA4 is derivable. The header-name set carries the identity alone — weaker than what an edge sensor can produce, and honest about it. Tested for both properties that matter: that the material actually distinguishes two different crawlers and is stable for one, and that no header value beyond those two can leave the site — asserted by serializing the whole payload rather than checking the keys this test happened to think of.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Restores actor correlation for WordPress sites, which a platform-side fix disabled.
What broke
The plugin beacons detections to the ingest service over its own HTTP connection, so the request arriving there carries this site's outbound headers, not the visitor's. The service was composing the visitor's network identity from those — byte-identical on every beacon a site sends — so every visitor a site ever reported was folded into one shared "actor".
The platform side shipped first (WebDecoy/app#412) and fails safe: a forwarded detection with no visitor signature now composes no network identity, on the grounds that no actor beats a false one. Correct — but it means WordPress detections stopped correlating entirely. This restores them.
What is sent
SignalCollector::getClientSignals()builds the material;Detectioncarries it ascs.Accept-LanguageandAccept-Encoding, the two values the server's identity actually readsAuthorizationheader never leave the site, while their names are retained so the entropy is intactcf-*,x-forwarded-*,true-client-ip,cdn-loop,x-vercel-*,fastly-*) excluded, so a visitor fingerprints consistently whether seen here or at a customer's edgeNo TLS material. PHP is handed a decrypted request and never sees the ClientHello, so no JA3/JA4 is derivable. The header-name set carries the identity alone — weaker than what an edge sensor produces, and the code says so rather than pretending otherwise.
Tests
tests/ClientSignalsTest.php, 10 cases, pinning both properties that matter:hn/al/aepinned, since they're matched by name across a repository boundary and a rename is silent data loss rather than a build error.Full suite: 75 passed, 0 failed.
Release
Version bumped to 2.3.1 across
webdecoy.php(header + constant),readme.txt(stable tag + changelog) andchangelog.txt.I have not run
./release.shor pushed anything to R2/wp.org — publishing an update to every install is your call, not a side effect of a code review.