Skip to content

feat: Add optional URL signing for upload and download URLs - #259

Open
isaacsu wants to merge 2 commits into
falcondev-oss:masterfrom
isaacsu:isaacsu/url-signing
Open

feat: Add optional URL signing for upload and download URLs#259
isaacsu wants to merge 2 commits into
falcondev-oss:masterfrom
isaacsu:isaacsu/url-signing

Conversation

@isaacsu

@isaacsu isaacsu commented Aug 13, 2026

Copy link
Copy Markdown

Hello 👋. Would love to get your feedback on whether this is a good idea?

Summary

The server-proxied upload (/devstoreaccount1/upload/{id}) and download (/download/{id}) URLs are unauthenticated by default. This PR adds an optional, opt-in expiring HMAC signature on those URLs to limit enumeration and leakage.

What changed

  • New lib/url-signing.ts — the core signing/verification module:
    • signQuery() mints an ?exp=<unixMs>&sig=<base64url> suffix binding a canonical path + expiry, signed with the active secret.
    • verifySignedRequest() strictly verifies exp/sig against the canonical path, throwing 401 on any failure (missing/malformed/mismatched/expired). It supports a secondary verify-only secret for rotation.
    • redactSignedPath() strips the sig credential from any logged path.
    • Fixed 1h TTL (non-configurable).
  • URL generationStorage.getDownloadUrl (proxied path) and the CreateCacheEntry Twirp handler appends a signature when signing is enabled. The upload signature is minted once and covers every chunk PUT plus the final comp=blocklist PUT within the TTL (mutable Azure query params are excluded from the signed material).
  • URL verification — the upload and download route handlers call verifySignedRequest before doing any work, verifying against the invariant canonical path (/upload/{id}, /download/{id}) rather than event.path, so route aliases and reverse-proxy prefixes verify consistently.
  • Log redactionplugins/setup.ts and routes/[...path].ts route all path logging through redactSignedPath so the replayable sig never lands in logs.
  • Config & validation — three new env vars (URL_SIGNING_ENABLED, URL_SIGNING_SECRET, URL_SIGNING_SECRET_SECONDARY) with cross-field validation via envSchemaValidated (secrets required and ≥ 16 chars when enabled; boot fails otherwise).
  • Docs — new README section covering config, secret rotation, the fixed TTL, and the hard-cutover caveat when enabling.
  • Teststests/url-signing.test.ts (enabled/disabled/rotation/tamper/expiry cases) and tests/url-signing-e2e.test.ts (end-to-end upload/download flow).

Configuration

Env var Description
URL_SIGNING_ENABLED boolean, default false. When true, upload/download URLs are signed and strictly verified (no unsigned fallback).
URL_SIGNING_SECRET Active signing secret, ≥ 16 chars. Required when enabled.
URL_SIGNING_SECRET_SECONDARY Optional verify-only rotation secret, ≥ 16 chars when set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant