Dev.to Security 🔐 Cybersecurity 👁 0 📖 1 min read

A presigned URL is not ongoing authorization

A presigned S3 (or GCS, or Azure SAS) URL feels like an access check, because the storage service rejects anyone without a valid signature. But the signature only proves one thing: at the moment you minted it, your app d

A presigned S3 (or GCS, or Azure SAS) URL feels like an access check, because the storage service rejects anyone without a valid signature. But the signature only proves one thing: at the moment you minted it, your app decided this caller could read this object.

After that, the URL is a bearer token. Anyone holding it can use it until it expires, even if:

  • the user was removed from the workspace five minutes later
  • the document was moved to a restricted folder
  • the link was pasted into a ticket, a chat, or a log line

A small example

# Minting is the authorization moment
def get_download_url(user, doc_id):
    doc = docs.get(doc_id)
    if not authorize(user, "read", doc):
        raise Forbidden()
    return s3.generate_presigned_url(
        "get_object",
        Params={"Bucket": BUCKET, "Key": doc.key},
        ExpiresIn=60,  # keep this short
    )

The check happens in authorize(user, "read", doc), not in S3. S3 only verifies your signature.

What helps

  1. Authorize at mint time, every time. Never cache "this user can download" and hand out fresh URLs from the cache.
  2. Keep expiry short. Seconds to a few minutes for downloads. Hours-long URLs are standing grants.
  3. Don't treat the URL as the permission. If a page re-renders, mint a new URL after a new check instead of reusing an old one.
  4. Keep URLs out of logs and analytics. Query strings travel further than you expect.
  5. For revocation-sensitive data, proxy instead. Stream through your app so every request gets a fresh decision.

The takeaway

A presigned URL is the output of an authorization decision, not a replacement for one. Make the decision in your app, make it per object, and keep the output short-lived.

How do you handle revocation for long-lived download links in your apps?

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.