Write the link contract
Name the statement owner, the exact file, allowed method, expiry, and revocation rule. A storage signature can protect the path and expiry, but it cannot tell whether the customer has since lost account access unless your app checks again. Test a copied link in a private browser and after account lock. Keep raw links out of logs, referrer headers, and support messages. If reuse is allowed, document why; if it is single use, test simultaneous requests.
Test cases and proof
| Case | Expected result | Proof to keep |
|---|---|---|
| Open link after expiry | Deny | HTTP response |
| Swap statement path or owner | Deny | Object accessed |
| Revoke statement access before expiry | Apply revocation policy | Download result |
Synthetic example
A statement link for customer A should not open a statement for customer B when a path segment changes. A link copied into a support ticket may still be live until expiry. Record where links appear in logs and how a customer can revoke one.
Evidence to keep
A test link should point to a fake statement with a clear owner marker. Use one link for each expiry and scope case. Record the signed path, issue time, expiry, HTTP result, and storage access event without pasting the full secret URL into the report. When testing logs, search for the unique fake file name and token fragment, then redact both in the final evidence.
Expiry is a tradeoff, not revocation
A short URL lifetime limits how long a copied link works, but it can also break a customer download on a slow connection. A longer life helps the customer but extends exposure when the URL is shared. Choose a time based on the file and user flow, then test at the boundary. If the product promises immediate revocation after account lock, a direct presigned storage URL may be the wrong design. A checked app endpoint or revocable proxy can enforce that promise, with more server cost.
Related reading
Why these checks matter
AWS describes a presigned URL as a way to grant time-limited access to an object. OWASP’s authorization guide calls for checking permissions on every request. Those statements expose a design choice: a direct storage link follows its signature and expiry, while an app download route can recheck a customer’s current right.
Test expiry at request start
For an S3 download, expiry is checked when the request starts. A download started just before expiry can continue afterward. Test a new GET after expiry separately from an in-progress transfer. An interrupted download that reconnects after expiry is also a new request. Record those three outcomes so continued delivery is not wrongly labelled an expiry bypass.
Issue a five-minute URL for a synthetic statement key stmt-A-101. Open it signed out: for a bearer design this can be the expected result. Changing the signed object path should fail. An app account lock alone does not revoke a storage grant signed by a service credential. Test the precise storage policy or checked proxy that enforces any promised early revocation.
Pin the file and explain reuse
Replace the contents of stmt-A-101 while its URL is still valid. If the URL signs only the key, it may fetch the replacement content. For immutable statements, use unique object keys or a version-aware link and record the file hash/version returned. Do not reuse one key for different owners or statement periods.
Native S3 presigned URLs allow repeated use before expiry. A single-use promise needs a server-side consumption gate with concurrent-request tests; signing alone does not provide it. A checked app route that redirects to a storage URL also exposes that second bearer grant. Keep method, object version, request start, expiry, and returned hash in evidence, with the query secret redacted. AWS’s presigned URL guide defines these storage behaviors.