Artikel

S3 Presigned URLs: was sie sind, wie sie funktionieren, Ablaufgrenzen und Codebeispiele

Was eine S3 Presigned URL ist, was jeder X-Amz-Parameter bedeutet, die 7-Tage-Grenze, Code für Upload und Download (CLI, boto3, JS) und typische Fehler.

Eine S3 Presigned URL ist ein temporärer Link auf ein Objekt in einem privaten Bucket. Sie trägt eine Signatur im Query-String, sodass jeder, der sie hat, dieses Objekt ohne AWS-Zugangsdaten herunterladen (oder hochladen) kann, bis der Link abläuft, und der Bucket wird nie öffentlich. Du erstellst sie mit deinen eigenen Schlüsseln, in deinem Code oder mit der AWS CLI, und sie kann von 1 Sekunde bis zu 7 Tagen gültig sein. Diese Anleitung erklärt, wie sie funktioniert, was jeder X-Amz-*-Parameter bedeutet, wie lange sie gültig sein kann, zeigt Code für Downloads und Uploads und die Fehler, auf die du am ehesten stößt. Die Grenzen stammen aus der Dokumentation von AWS und Cloudflare, Stand Oktober 2026.

S3 Presigned URLs auf einen Blick

FrageAntwort
Was erlaubt sie?Eine Operation (GET, PUT, HEAD, DELETE…) auf einem Objekt
Maximale Gültigkeit7 Tage (604.800 Sekunden) mit SigV4 und Schlüsseln eines IAM-Benutzers
Gültigkeit mit temporären SchlüsselnEndet mit der Rollensitzung oder den STS-Zugangsdaten, je nachdem, was zuerst eintritt
Spanne in der S3-Konsole1 Minute bis 12 Stunden
Standardgültigkeit3.600 s in der AWS CLI und boto3, 900 s im JavaScript-v3-Presigner
Lässt sie sich mehrfach nutzen?Ja, so oft jeder will, bis sie abläuft
Lässt sich eine einzelne URL widerrufen?Nein, nur durch Widerruf der signierenden Zugangsdaten oder per Richtlinie
Ruft das Erstellen S3 auf?Nein, die Signatur wird lokal berechnet

Wie eine Presigned URL funktioniert

  1. Dein Code (oder die CLI) nimmt den Bucket, den Objektschlüssel, die HTTP-Methode und eine Ablaufzeit.
  2. Das SDK signiert diese Werte mit deinem Secret Access Key per AWS Signature Version 4. Dabei wird nichts an S3 gesendet.
  3. Du gibst die entstandene URL an jemanden weiter: einen Browser, eine Kollegin, eine mobile App.
  4. Wenn sie genutzt wird, berechnet S3 die Signatur mit dem Secret neu, das zum Access Key in der URL gehört. Stimmt sie überein, ist die URL nicht abgelaufen und darf der Signierende diese Operation ausführen, geht die Anfrage durch.

Die URL trägt die Berechtigungen dessen, der sie signiert hat. AWS sagt das ausdrücklich: Wenn der IAM-Benutzer oder die Rolle, die die URL erzeugt hat, das Objekt nicht lesen darf, liefert die URL 403, egal wie gültig die Signatur ist.

Was die X-Amz-Parameter bedeuten

Eine SigV4 Presigned URL sieht so aus (Zeilenumbrüche hinzugefügt):

https://my-bucket.s3.eu-west-1.amazonaws.com/reports/q3.pdf
  ?X-Amz-Algorithm=AWS4-HMAC-SHA256
  &X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20261017%2Feu-west-1%2Fs3%2Faws4_request
  &X-Amz-Date=20261017T093000Z
  &X-Amz-Expires=3600
  &X-Amz-SignedHeaders=host
  &X-Amz-Signature=5f2c...e91a
ParameterBedeutung
X-Amz-AlgorithmDer Signaturalgorithmus: AWS4-HMAC-SHA256 für SigV4
X-Amz-CredentialAccess Key ID plus Geltungsbereich: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request
X-Amz-DateZeitpunkt der Signatur, in UTC, yyyyMMddTHHmmssZ
X-Amz-ExpiresWie viele Sekunden die URL nach X-Amz-Date gültig ist, von 1 bis 604800
X-Amz-SignedHeadersVon der Signatur abgedeckte Header, immer mindestens host
X-Amz-SignatureDie Signatur, 64 hexadezimale Zeichen
X-Amz-Security-TokenNur vorhanden, wenn die URL mit temporären Zugangsdaten signiert wurde (STS, Rollen, EC2, ECS, SSO)

Änderst du einen signierten Teil (den Schlüssel, die Methode, die Ablaufzeit oder einen signierten Header), passt die Signatur nicht mehr. Beachte auch, was die URL im Klartext verrät: den Bucket-Namen, den vollständigen Objektschlüssel und deine Access Key ID. Der Secret Key steht nie in der URL.

Wie lange eine Presigned URL gültig ist

Die Grenze hängt von den Zugangsdaten ab, mit denen sie signiert wird:

Signiert mitMaximale Gültigkeit
Zugriffsschlüssel eines IAM-Benutzers (SigV4)7 Tage, weil der SigV4-Signaturschlüssel selbst 7 Tage gültig ist
IAM-Rollensitzung (STS AssumeRole)Bis die Sitzung endet, standardmäßig 1 Stunde
EC2-InstanzprofilBis die Zugangsdaten der Rolle rotieren, höchstens etwa 6 Stunden
ECS-Task-RolleBis die Zugangsdaten der Task rotieren, typischerweise alle 1 bis 6 Stunden
Widerrufene oder gelöschte ZugangsdatenSofort ungültig, egal was X-Amz-Expires sagt
S3-KonsoleDu wählst zwischen 1 Minute und 12 Stunden

Das erklärt die häufigste Überraschung: Du forderst aus einer Lambda-Funktion oder einer EC2-Instanz 7 Tage an und der Link ist nach einer Stunde oder ein paar Stunden tot. Die URL lebt nur so lange wie die Zugangsdaten dahinter. Wenn du lange Links brauchst, signiere mit einem eigenen IAM-Benutzer, der nur Lesezugriff auf diesen Bucket hat.

S3 prüft die Ablaufzeit, wenn eine Anfrage beginnt. Ein großer Download, der eine Sekunde vor der Frist startet, läuft normal zu Ende, aber ein erneuter Versuch nach der Frist scheitert mit AccessDenied und der Meldung „Request has expired“. Mehr als 604.800 Sekunden anzufordern wird direkt abgelehnt.

So erzeugst du eine Presigned URL

AWS CLI

aws s3 presign s3://my-bucket/reports/q3.pdf --expires-in 3600

Der Befehl signiert eine Download-URL (GET). Standard sind 3.600 Sekunden, das Maximum 604.800. Aktuelle CLI-Versionen nutzen immer SigV4, achte also darauf, dass eine Region konfiguriert ist. Für Upload-URLs brauchst du ein SDK.

Python (boto3)

import boto3
from botocore.config import Config

s3 = boto3.client('s3', region_name='eu-west-1', config=Config(signature_version='s3v4'))

url = s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={
        'Bucket': 'my-bucket',
        'Key': 'reports/q3.pdf',
        'ResponseContentDisposition': 'attachment; filename="q3.pdf"',
    },
    ExpiresIn=3600,
)

Setze signature_version='s3v4' ausdrücklich. Die boto3-Referenz warnt, dass es sonst aus Gründen der Abwärtskompatibilität in Regionen, die das noch akzeptieren, mit der älteren Signature Version 2 signieren kann, die stillschweigend einige Parameter und Header wie Range verwirft. ResponseContentDisposition ist optional: Damit speichert der Browser die Datei mit einem sauberen Namen, statt sie direkt zu öffnen.

JavaScript (AWS SDK v3)

import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const client = new S3Client({ region: 'eu-west-1' })

const url = await getSignedUrl(
  client,
  new GetObjectCommand({ Bucket: 'my-bucket', Key: 'reports/q3.pdf' }),
  { expiresIn: 3600 }
)

Lässt du expiresIn weg, nutzt der JavaScript-Presigner 900 Sekunden (15 Minuten).

Presigned URLs für Uploads (PUT)

Dasselbe Prinzip funktioniert in die andere Richtung. Du signierst ein PutObject für einen Schlüssel, und wer die URL hat, kann dieses Objekt schreiben. Die Datei geht direkt von seinem Gerät in den Bucket und dein Server fasst die Bytes nie an. Existiert schon ein Objekt mit diesem Schlüssel, wird es ersetzt.

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const client = new S3Client({ region: 'eu-west-1' })

const url = await getSignedUrl(
  client,
  new PutObjectCommand({
    Bucket: 'my-bucket',
    Key: 'incoming/brief.pdf',
    ContentType: 'application/pdf',
  }),
  { expiresIn: 900, signableHeaders: new Set(['content-type']) }
)

await fetch(url, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/pdf' },
  body: file,
})

Wenn du content-type zu signableHeaders hinzufügst, ist die URL an diesen Typ gebunden, und ein Upload mit anderem Content-Type wird abgelehnt. In boto3 ist das Gegenstück generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), und der Client muss denselben Header senden.

Drei Dinge solltest du vor einem Upload aus dem Browser prüfen:

  • CORS. Der Bucket braucht eine CORS-Regel, die deinen Origin und die Methode PUT erlaubt. Für Multipart-Uploads muss sie außerdem den Header ETag freigeben, weil der Browser ihn aus jedem Teil lesen muss.
  • Fester Schlüssel. Erzeuge auf dem Server einen eindeutigen Schlüssel (zum Beispiel mit einem UUID-Präfix), damit niemand die Datei eines anderen überschreiben kann.
  • Prüfsummen. Aktuelle AWS SDKs fügen Uploads standardmäßig eine CRC-Prüfsumme hinzu. Wenn Presigned Uploads bei einem S3-kompatiblen Provider mit Signatur- oder Prüfsummenfehlern scheitern, setze requestChecksumCalculation: 'WHEN_REQUIRED' im Client.

Presigned POST ist ein eigener Mechanismus für einfache HTML-Formulare, mit einer Richtlinie, die Größe und Inhaltstyp begrenzen kann. Nicht jeder S3-kompatible Provider unterstützt ihn (R2 nicht), deshalb ist Presigned PUT die portablere Wahl.

Große Dateien: Multipart-Uploads mit Presigned URLs

Ein einzelnes PUT zu S3 ist auf 5 GB begrenzt, und AWS empfiehlt Multipart ab etwa 100 MB. Multipart teilt die Datei in bis zu 10.000 Teile, jeweils von 5 MiB bis 5 GiB außer dem letzten, die unabhängig, parallel und mit Wiederholung pro Teil hochgeladen werden. Das Signieren funktioniert pro Teil: Der Server startet den Upload, signiert eine UploadPart-URL pro Teil, der Browser sendet jedes Stück und meldet dessen ETag zurück, und der Server schließt den Upload ab.

import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand,
} from '@aws-sdk/client-s3'

const { UploadId } = await client.send(
  new CreateMultipartUploadCommand({ Bucket: 'my-bucket', Key: 'video/raw.mov' })
)

const partUrl = await getSignedUrl(
  client,
  new UploadPartCommand({ Bucket: 'my-bucket', Key: 'video/raw.mov', UploadId, PartNumber: 1 }),
  { expiresIn: 3600 }
)

await client.send(
  new CompleteMultipartUploadCommand({
    Bucket: 'my-bucket',
    Key: 'video/raw.mov',
    UploadId,
    MultipartUpload: { Parts: [{ PartNumber: 1, ETag: etagFromPartResponse }] },
  })
)

Füge eine Lifecycle-Regel hinzu, die unvollständige Multipart-Uploads nach ein paar Tagen abbricht, sonst belegen verwaiste Teile weiter kostenpflichtigen Speicher.

Presigned URLs bei R2, B2, Spaces und Wasabi

Provider, die die S3-API mit SigV4 umsetzen, akzeptieren denselben Code: Du änderst nur den Endpoint, die Region und die Schlüssel. Die Details unterscheiden sich, prüfe also die Dokumentation des Providers:

  • Cloudflare R2 unterstützt signierte GET, HEAD, PUT und DELETE, mit einer Gültigkeit von 1 Sekunde bis 7 Tagen. Signierte POST werden nicht unterstützt, und Presigned URLs funktionieren nur auf der Domain der S3-API (<ACCOUNT_ID>.r2.cloudflarestorage.com), nicht auf eigenen Domains. Verwende region: 'auto'.
  • Backblaze B2 gibt an, dass seine S3-kompatible API Presigned URLs unterstützt, die mit der AWS CLI oder den SDKs erzeugt werden.
  • DigitalOcean Spaces und Wasabi funktionieren mit denselben SDK-Aufrufen, die auf ihre Endpoints zeigen.

Die Preise der einzelnen Provider findest du im Vergleich von S3, R2, Spaces, Wasabi und B2.

Typische Fehler mit Presigned URLs und ihre Lösung

FehlerÜbliche UrsacheLösung
SignatureDoesNotMatchMethode, Header oder Query weichen vom Signierten ab; Uhr nicht synchronSende denselben Content-Type und dieselben Header; synchronisiere die Uhr per NTP
AccessDenied „Request has expired“Die URL ist über X-Amz-Date + X-Amz-Expires hinausErzeuge eine neue URL; verkürze die Zeit zwischen Signieren und Nutzen
URL läuft früher ab als angefordertMit temporären Zugangsdaten signiert (Rolle, EC2, ECS, Lambda)Signiere mit Zugangsdaten, die so lange leben, wie der Link halten soll
ExpiredTokenDie STS-Sitzung hinter X-Amz-Security-Token ist beendetErneuere die Zugangsdaten vor dem Signieren
403 AccessDenied bei einer neuen URLDem Signierenden fehlt s3:GetObject oder s3:PutObject, oder eine Richtlinie verweigert esGib dem signierenden Principal die Berechtigung; prüfe die Bucket-Richtlinien
AuthorizationQueryParametersErrorGültigkeit über 604.800 Sekunden oder fehlerhafter Credential-GeltungsbereichHalte X-Amz-Expires bei höchstens 7 Tagen; signiere in der Region des Buckets
Browser durch CORS blockiertKeine CORS-Regel für deinen Origin und deine Methode am BucketFüge eine CORS-Regel mit deinem Origin, GET/PUT und freigegebenem ETag hinzu
AccessDenied mit HeadersNotSignedRange wurde signiert, aber If-Range unsigniert gesendetFüge If-Range zu den signierten Headern hinzu

Auch Firmen-Proxys, die Header oder Query-Strings umschreiben, machen Signaturen kaputt. Wenn eine URL in einem Netzwerk funktioniert und in einem anderen nicht, teste ohne den Proxy.

Bewährte Praktiken für die Sicherheit

AWS nennt Presigned URLs Bearer-Token und empfiehlt, sie zu schützen. In der Praxis:

  • Halte sie kurz. Minuten für Uploads und sensible Dateien, Stunden für normale Downloads. Erzeuge eine neue, wenn jemand die Datei erneut braucht.
  • Signiere mit einer eng gefassten Identität. Ein eigener IAM-Benutzer oder eine Rolle, die nur das betreffende Präfix lesen (oder nur schreiben) darf, begrenzt den Schaden, wenn ein Link nach außen gelangt.
  • Setze Leitplanken in der Bucket-Richtlinie. Die Bedingung s3:signatureAge lehnt Signaturen ab, die älter als ein festgelegtes Alter sind, und aws:SourceIp beschränkt, aus welchen Netzwerken sie genutzt werden können.
  • Protokolliere sie nicht. Vollständige Presigned URLs in Anwendungslogs, Analysen oder Chatverläufen sind funktionierende Zugangsdaten, bis sie ablaufen.
  • Plane ein, was ihnen fehlt. Es gibt kein Passwort, keinen Download-Zähler und keinen Widerruf pro Link, also setz eine Anwendung davor, wenn du das brauchst.

Mehr zum Teilen, mit Optionen, die genau diese Kontrollen ergänzen, findest du unter wie du S3-Dateien teilst, ohne den Bucket öffentlich zu machen.

Wie Nubbo Presigned URLs nutzt

Nubbo baut auf diesem Muster auf. Wenn du im Explorer hochlädst, signiert der Server ein PUT (oder ab 100 MB einen Multipart-Upload mit drei parallelen Teilen) und dein Browser sendet die Bytes direkt an deinen Bucket. Downloads einzelner Dateien nutzen signierte GET-URLs, die eine Stunde gültig sind. Deine Zugriffsschlüssel werden mit AES-256-GCM verschlüsselt gespeichert und nur auf dem Server zum Signieren verwendet.

Freigabelinks ergänzen, was reinen Presigned URLs fehlt: ein optionales Passwort, Ablaufdatum und Download-Limit, die Nubbo prüft, bevor es eine kurzlebige URL ausgibt, und du kannst einen Link jederzeit deaktivieren. ZIP-Downloads mehrerer Dateien setzt dein Browser zusammen, der jede Datei direkt aus deinem Bucket lädt: Nubbo sieht den Inhalt nie. Eine ehrliche Ausnahme: Vorschaubilder werden in deinem eigenen Bucket unter .nubbo-thumbs/ abgelegt. Es funktioniert genauso bei Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 und öffentlichen S3-kompatiblen Endpoints.

Häufige Fragen

Was ist eine Presigned URL in S3?

Ein normaler HTTPS-Link auf ein Objekt in einem privaten Bucket, an dessen Query-String eine Signatur angehängt ist. Wer den Link hat, kann die eine Operation ausführen, für die er signiert wurde, meist einen Download (GET) oder einen Upload (PUT), bis er abläuft. Der Bucket bleibt privat und wer den Link nutzt, braucht keine AWS-Zugangsdaten.

Wie lange kann eine S3 Presigned URL maximal gültig sein?

Sieben Tage (604.800 Sekunden), wenn du mit Signature Version 4 und dauerhaften Schlüsseln eines IAM-Benutzers signierst. Eine URL, die mit temporären Zugangsdaten signiert wurde, etwa mit einer übernommenen Rolle oder einem EC2-Instanzprofil, funktioniert nicht mehr, sobald diese Zugangsdaten ablaufen, selbst wenn du eine längere Dauer angefordert hast. In der S3-Konsole kannst du zwischen 1 Minute und 12 Stunden wählen.

Was bedeuten X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders und X-Amz-Signature?

Das sind die Authentifizierungsparameter von SigV4. Algorithm ist das Signaturverfahren (AWS4-HMAC-SHA256), Credential ist deine Access Key ID plus Datum, Region und Dienst, Date ist der Zeitpunkt der Signatur, Expires gibt an, wie viele Sekunden sie gültig bleibt, SignedHeaders listet die von der Signatur abgedeckten Header auf und Signature ist die Signatur selbst. X-Amz-Security-Token erscheint nur, wenn die URL mit temporären Zugangsdaten signiert wurde.

Kann ich eine S3 Presigned URL widerrufen, bevor sie abläuft?

Nicht einzeln. Eine Presigned URL hört nur dann vorzeitig auf zu funktionieren, wenn die Zugangsdaten, mit denen sie signiert wurde, widerrufen, gelöscht oder deaktiviert werden oder wenn eine Bucket-Richtlinie die Anfrage verweigert. Wenn du einzelne Links sperren musst, setz eine Anwendung davor, die kurzlebige URLs erst nach eigenen Prüfungen ausgibt.

Sind S3 Presigned URLs sicher?

Die Signatur lässt sich weder fälschen noch verändern, und der Bucket bleibt privat. AWS beschreibt Presigned URLs aber als Bearer-Token: Jeder, der den Link bekommt, kann ihn nutzen, so oft er will, bis er abläuft. Halte die Ablaufzeiten kurz, nutze HTTPS und veröffentliche die Links nicht dort, wo sie kopiert werden können.

Funktionieren Presigned URLs mit Cloudflare R2, Backblaze B2 oder Wasabi?

Provider, die die S3-API mit Signature Version 4 umsetzen, unterstützen sie in der Regel, und du nutzt dieselben SDK-Aufrufe mit dem Endpoint des Providers. Cloudflare R2 unterstützt zum Beispiel signierte GET, HEAD, PUT und DELETE mit einer Gültigkeit von 1 Sekunde bis 7 Tagen, aber keine POST-Formular-Uploads und keine eigenen Domains.

Warum liefert meine Presigned URL SignatureDoesNotMatch?

AWS nennt drei häufige Ursachen: eine Computeruhr, die nicht synchron läuft, ein Proxy, der Header oder den Query-String verändert, und eine Anfrage, deren Methode, Header oder Parameter von den signierten abweichen. Bei Uploads ist der übliche Grund ein anderer Content-Type als der, mit dem die URL erzeugt wurde.

Quellen

Preise und Limits stammen von den unten verlinkten offiziellen Seiten. Provider ändern sie, prüfe sie also, bevor du dich festlegst.