fix(security): use constant-time bearer-token comparison in client API#114
Merged
fix(security): use constant-time bearer-token comparison in client API#114
Conversation
…etection Introduce a complete, self-describing OpenAPI 3.1 contract for the hypercache-server client REST API, with tooling to ensure the spec and binary never silently drift apart. - Add `cmd/hypercache-server/openapi.yaml`: covers all 11 routes (single-key PUT/GET/HEAD/DELETE, owners lookup, three batch operations, /healthz, /v1/openapi.yaml) with reusable component schemas, bearerAuth security scheme, and operationId on every operation for codegen friendliness. - Embed spec via `//go:embed` in `openapi.go` and serve it at `GET /v1/openapi.yaml` — every running node is self-describing, and the deployed contract is always in lockstep with the binary. - Extract `registerClientRoutes` from `runClientAPI` so the drift test (and handler tests) can drive the exact production route wiring without spinning up a real listener. - Add `openapi_test.go` drift detector: asserts every fiber route in `registerClientRoutes` has a matching path in `openapi.yaml` (and vice-versa), preventing silent spec/code divergence. - Add `.github/workflows/openapi.yml` CI workflow with two jobs: `redocly lint` validates the spec against the OpenAPI 3.1 meta-spec; the Go drift test runs on every change to `main.go` or the spec. - Add `redocly.yaml` config (extends `recommended`, disables two intentional no-ops: localhost server URL and missing 4xx on auth-free meta endpoints). - Add `docs/api.md` with inline Swagger UI powered by `mkdocs-swagger-ui-tag`; `_mkdocs/hooks.py` injects the binary's embedded spec as a virtual docs asset via an `on_files` hook, keeping a single source of truth across binary, docs, and codegen. - Promote `gopkg.in/yaml.v3` from indirect to direct dependency (used by the drift test).
Replace the plaintext `got != want` string check in `bearerAuth` (cmd/hypercache-server/main.go) with `crypto/subtle.ConstantTimeCompare`. A naive string compare returns on the first differing byte, leaking per-byte equality of HYPERCACHE_AUTH_TOKEN to an attacker who can measure response latency. The fix mirrors the constant-time check already present in the dist transport (pkg/backend/dist_http_server.go). No public API change; the env-var contract and the zero-config "empty token → open mode" backcompat behaviour are preserved. Add cmd/hypercache-server/auth_test.go to pin the auth contract: - Missing, wrong, malformed, lowercase-scheme, and wrong-length Authorization headers all return 401 on protected routes. - Public meta routes (/healthz, /v1/openapi.yaml) remain reachable without credentials (K8s liveness probes, self-describing spec). - All cache and batch endpoints are asserted to require auth, catching future wiring regressions when new routes are added without the bearerAuth wrapper.
Introduce pkg/httpauth — the v2 successor to the single-token
bearerAuth helper — with the following capabilities:
- Multi-token bearer auth: multiple TokenIdentity entries each
carrying explicit scopes (read/write/admin), resolved in
constant time across all configured tokens to prevent
token-cardinality timing leaks.
- Per-route scope enforcement: GET/HEAD/owners-lookup/batch-get
require ScopeRead; PUT/DELETE/batch-put/batch-delete require
ScopeWrite.
- mTLS support: HYPERCACHE_API_TLS_CERT + HYPERCACHE_API_TLS_KEY
enable standard TLS; adding HYPERCACHE_API_TLS_CLIENT_CA upgrades
to RequireAndVerifyClientCert with peer CN mapped to CertIdentity.
- YAML policy config via HYPERCACHE_AUTH_CONFIG; legacy
HYPERCACHE_AUTH_TOKEN still works byte-identical as a single
all-scopes identity shortcut. Both env vars are orthogonal:
CONFIG governs the client API, AUTH_TOKEN drives dist peer auth.
- Fail-closed startup: loadConfig() now returns an error and exits
non-zero on missing/malformed HYPERCACHE_AUTH_CONFIG. Zero-config
dev posture preserved via AllowAnonymous with a startup warning.
Add pkg/httpauth/{policy,loader,policy_test,loader_test}.go and
cmd/hypercache-server/{mtls_test,mtls_e2e_test}.go. Update
auth_test.go and openapi_test.go to use httpauth.Policy. Document
auth surfaces in CHANGELOG and docs/distributed.md.
Introduce pkg/httpauth — the v2 successor to the single-token
bearerAuth helper — with the following capabilities:
- Multi-token bearer auth: multiple TokenIdentity entries each
carrying explicit scopes (read/write/admin), resolved in
constant time across all configured tokens to prevent
token-cardinality timing leaks.
- Per-route scope enforcement: GET/HEAD/owners-lookup/batch-get
require ScopeRead; PUT/DELETE/batch-put/batch-delete require
ScopeWrite.
- mTLS support: HYPERCACHE_API_TLS_CERT + HYPERCACHE_API_TLS_KEY
enable standard TLS; adding HYPERCACHE_API_TLS_CLIENT_CA upgrades
to RequireAndVerifyClientCert with peer CN mapped to CertIdentity.
- YAML policy config via HYPERCACHE_AUTH_CONFIG; legacy
HYPERCACHE_AUTH_TOKEN still works byte-identical as a single
all-scopes identity shortcut. Both env vars are orthogonal:
CONFIG governs the client API, AUTH_TOKEN drives dist peer auth.
- Fail-closed startup: loadConfig() now returns an error and exits
non-zero on missing/malformed HYPERCACHE_AUTH_CONFIG. Zero-config
dev posture preserved via AllowAnonymous with a startup warning.
Add pkg/httpauth/{policy,loader,policy_test,loader_test}.go and
cmd/hypercache-server/{mtls_test,mtls_e2e_test}.go. Update
auth_test.go and openapi_test.go to use httpauth.Policy. Document
auth surfaces in CHANGELOG and docs/distributed.md.
Introduce pkg/httpauth — the v2 successor to the single-token
bearerAuth helper — with the following capabilities:
- Multi-token bearer auth: multiple TokenIdentity entries each
carrying explicit scopes (read/write/admin), resolved in
constant time across all configured tokens to prevent
token-cardinality timing leaks.
- Per-route scope enforcement: GET/HEAD/owners-lookup/batch-get
require ScopeRead; PUT/DELETE/batch-put/batch-delete require
ScopeWrite.
- mTLS support: HYPERCACHE_API_TLS_CERT + HYPERCACHE_API_TLS_KEY
enable standard TLS; adding HYPERCACHE_API_TLS_CLIENT_CA upgrades
to RequireAndVerifyClientCert with peer CN mapped to CertIdentity.
- YAML policy config via HYPERCACHE_AUTH_CONFIG; legacy
HYPERCACHE_AUTH_TOKEN still works byte-identical as a single
all-scopes identity shortcut. Both env vars are orthogonal:
CONFIG governs the client API, AUTH_TOKEN drives dist peer auth.
- Fail-closed startup: loadConfig() now returns an error and exits
non-zero on missing/malformed HYPERCACHE_AUTH_CONFIG. Zero-config
dev posture preserved via AllowAnonymous with a startup warning.
Add pkg/httpauth/{policy,loader,policy_test,loader_test}.go and
cmd/hypercache-server/{mtls_test,mtls_e2e_test}.go. Update
auth_test.go and openapi_test.go to use httpauth.Policy. Document
auth surfaces in CHANGELOG and docs/distributed.md.
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.
Replace the plaintext
got != wantstring check inbearerAuth(cmd/hypercache-server/main.go) with
crypto/subtle.ConstantTimeCompare.A naive string compare returns on the first differing byte, leaking
per-byte equality of HYPERCACHE_AUTH_TOKEN to an attacker who can
measure response latency. The fix mirrors the constant-time check
already present in the dist transport (pkg/backend/dist_http_server.go).
No public API change; the env-var contract and the zero-config
"empty token → open mode" backcompat behaviour are preserved.
Add cmd/hypercache-server/auth_test.go to pin the auth contract:
Authorization headers all return 401 on protected routes.
without credentials (K8s liveness probes, self-describing spec).
future wiring regressions when new routes are added without the
bearerAuth wrapper