Use constant-time comparison for token and credential verification#506
Open
Use constant-time comparison for token and credential verification#506
Conversation
Replace standard == comparisons with subtle::ConstantTimeEq in the three places that verify secrets: tstoken signature in proxy.rs, clear-URL signature in http_util.rs, and Basic Auth credentials in auth.rs. The auth fix also removes the && short-circuit that created a username- existence oracle — both username and password are now always evaluated using bitwise & on subtle::Choice values. Adds log::warn on auth failure (path only, no credentials) and five targeted tests covering tampered tokens, wrong-username-right-password, and empty tokens. Closes #410
Collaborator
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Verdict: Clean, well-focused security hardening PR. Ready to merge with minor improvements.
Excellent anti-oracle design in auth.rs — bitwise & on subtle::Choice instead of && prevents username-existence oracle. Minimal, focused changes — only touches the 3 comparison sites + targeted tests. Good test coverage (5 new tests). subtle v2 is the right dependency choice.
ChristianPavilonis
approved these changes
Mar 17, 2026
Collaborator
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Approved — ready to merge
This PR correctly hardens the three token/credential comparison sites with constant-time operations from the subtle crate. The changes are minimal, focused, and well-documented.
Highlights
- Excellent anti-oracle design in
auth.rs: using bitwise&onsubtle::Choiceinstead of&&prevents username-existence oracles. The inline comment explaining why is exactly what future maintainers need. - Well-chosen tests covering tampered tokens (same length, wrong bytes), wrong-username/right-password, correct-username/wrong-password, and empty tokens.
- Good doc comments explaining security invariants on
enforce_basic_auth,verify_clear_url_signature, and inline inproxy.rs. log::warn!on auth failure logs path only (no credentials) — correct observability without leaking secrets.- Minimal, focused changes — only the 3 comparison sites plus targeted tests. No unnecessary refactoring.
- All CI checks pass (fmt, test, clippy, vitest, CodeQL).
Minor note (not actionable for this PR)
extract_credentialsinauth.rs(lines 49-73) has pre-existing early returns that leak timing about credential format (missing header, wrong scheme, malformed base64). This is not introduced by this PR and is fine — the CT comparison correctly protects credential values, not header format parsing.
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.
Summary
==comparisons withsubtle::ConstantTimeEqin all three secret-verification sites (tstoken, clear-URL signature, Basic Auth), eliminating timing side-channel attacks&&allowed an attacker to distinguish wrong-username from wrong-password via timing — replaced with bitwise&onsubtle::Choiceso both fields are always evaluatedlog::warn!on auth failure (path only, no credentials) and five new targeted tests covering each fixChanges
Cargo.tomlsubtle = "2"to workspace dependenciescrates/common/Cargo.tomlsubtleas direct dependencycrates/common/src/auth.rs&instead of&&;log::warn!on failure; 2 new testscrates/common/src/http_util.rsverify_clear_url_signature; 2 new testscrates/common/src/proxy.rsreconstruct_and_validate_signed_target; 1 new testCloses
Closes #410
Test plan
cargo test --workspacecargo clippy --all-targets --all-features -- -D warningscargo fmt --all -- --checkcd crates/js/lib && npx vitest runcd crates/js/lib && npm run formatcd docs && npm run formatcargo build --bin trusted-server-fastly --release --target wasm32-wasip1fastly compute serveChecklist
unwrap()in production code — useexpect("should ...")tracingmacros (notprintln!)