Zum Inhalt springen

System-Design

Downloads sicher bereitstellen: Einmal-Links und signierte URLs

Links weitergeben, aber nur Berechtigte laden lassen? Wie Einmal-Links und signierte URLs funktionieren und worauf du bei Zeitzonen und Schlüsselrotation achten musst.

Christopher CEO · IT Architect

Aktualisiert am · 5 Min. Lesezeit

Viele Webanwendungen müssen Dateien zum Download bereitstellen, etwa wenn Nutzer:innen Vertragsunterlagen als PDF herunterladen sollen. Sobald du genauer hinschaust, landest du typischerweise bei Anforderungen wie diesen:

  • REQ#1: Als Nutzer:in möchte ich Dateien aus der Anwendung herunterladen.
  • REQ#2: Als Nutzer:in möchte ich den Download-Link an eine andere Person schicken.
  • REQ#3: Als Nutzer:in möchte ich eine Datei auch später herunterladen, ohne angemeldet zu sein.
  • REQ#4: Als Sicherheitsbeauftragte:r möchte ich, dass nur berechtigte Personen Dateien herunterladen.
  • REQ#5: Als Compliance-Verantwortliche:r verlange ich, dass Dateien auf unserem eigenen Speicher liegen und nicht in einer Cloud-Umgebung.
  • REQ#6: Als Compliance-Verantwortliche:r möchte ich nicht, dass ein Download-Link später erneut verwendet werden kann.
  • REQ#7: Als DevOps-Engineer möchte ich, dass alle Zugangsdaten regelmäßig automatisch rotiert werden.
  • REQ#8: Als Softwarearchitekt:in möchte ich die Verwaltung von Downloads in einem eigenen, separat deploybaren Modul oder Microservice haben.

Da kommt einiges zusammen. REQ#2 und REQ#3 stehen zum Beispiel in direktem Widerspruch zu REQ#4. Eine mögliche Lösung sind Einmal-Links (One-Time Links, OTL).

Ein Einmal-Link lässt sich per Definition nur einmal verwenden. Er startet einen Download und verliert nach der ersten Nutzung seine Gültigkeit.

Bevor ein OTL erzeugt wird, wird ein zufälliger Marker wie eine GUID gespeichert, zum Beispiel in einer Datenbanktabelle oder einem gemeinsamen Cache. Beim ersten Klick prüft der Service, ob der Marker noch existiert. Falls ja, wird er gelöscht und die Datei ausgeliefert. Falls nicht, bekommt die Person eine Fehlermeldung.

Setze beim Lesen des Markers eine Sperre. Sonst können parallele Anfragen dazu führen, dass dieselbe Datei zweimal heruntergeladen wird.

Kontext eines Einmal-Links mit gespeichertem Marker

Frag dich vorher: Verlangen deine Anforderungen wirklich, dass eine Datei nur ein einziges Mal über einen Link abrufbar ist? Zugangsdaten oder Zertifikatsdateien müssen unter Umständen genau einmal erzeugt und heruntergeladen werden. In den meisten anderen Fällen reicht es, wenn der Link etwas später nicht mehr funktioniert.

In der Praxis werden auch Links, die nur kurze Zeit gültig sind, als Einmal-Links bezeichnet. Wir nennen sie hier Pseudo-OTLs.

Anders als OTLs brauchen Pseudo-OTLs keinen gespeicherten Marker. Stattdessen enthält der Link ein Ablaufdatum und eine Signatur. Das Ablaufdatum ergibt sich aus der aktuellen Zeit plus der Gültigkeitsdauer des Links (TTL, Time to Live). Die Signatur wird mit einem gemeinsamen Geheimnis (einem Pre-Shared Key oder einem Zertifikat) erzeugt und geprüft. Sie stellt sicher, dass niemand das Ablaufdatum manipuliert hat.

Mit einer kurzen TTL lässt sich die Datei nur in einem sehr begrenzten Zeitfenster herunterladen. Innerhalb dieses Fensters kann der Link technisch aber weiterhin mehrfach geklickt und weitergegeben werden.

In AWS S3 und MinIO gibt es Pseudo-OTLs als Presigned URLs, in Azure Blob Storage erreichst du dasselbe mit SAS-Tokens. Setzt du sie selbst um, etwa weil die Dateien lokal liegen, sieht der Ablauf so aus:

Sequenzdiagramm für das Erzeugen und Prüfen eines signierten Download-Links

Als Pseudocode:

// `keyStore` ist eine Fassade für deinen Schlüssel- oder Zertifikatsspeicher, z. B. Vault

createSignedUrl(fileId, expiresAt):
    key = keyStore.newestActiveKey()
    url = "/files/" + fileId + "?expires_at=" + expiresAt.toIso8601()
    return url + "&key=" + key.id + "&signature=" + sign(url, key)

sign(value, key):
    // HMAC-SHA256 mit Pre-Shared Key oder RSA/ECDSA mit Zertifikat
    return hmacSha256(value, key.secret)

isValid(request):
    expiresAt = request.param("expires_at")
    signature = request.param("signature")
    key = keyStore.findActive(request.param("key"))

    if expiresAt fehlt or signature fehlt or key fehlt:
        return false
    // nach dem Ablaufdatum darf der Link nicht mehr funktionieren
    if now() > parseIso8601(expiresAt):
        return false

    url = "/files/" + request.pathSegment + "?expires_at=" + expiresAt
    // in konstanter Zeit vergleichen, um Timing-Angriffe zu vermeiden
    return constantTimeEquals(sign(url, key), signature)

Was du beachten solltest

Zeitzonen

Achte darauf, dass alle Server dieselbe Zeitzone verwenden oder sauber mit Zeitzonen umgehen. Wird der Link in Zeitzone A erzeugt, in Zeitzone B (die A voraus ist) geprüft und enthält das Ablaufdatum keine Zeitzoneninformation, schlägt die Prüfung fehl. Übertrage deshalb immer die Zeitzone, am besten als ISO-8601-Zeitstempel in UTC, oder konfiguriere alle Umgebungen identisch.

Gemeinsame Geheimnisse und Schlüsselrotation

Sowohl der Service, der Links erzeugt, als auch der Service, der Dateien ausliefert, müssen das gemeinsame Geheimnis oder Zertifikat kennen oder dieselbe Signaturkomponente nutzen.

Werden Geheimnisse regelmäßig rotiert (REQ#7), musst du das von Anfang an berücksichtigen: Halte während einer Übergangszeit zwei Schlüssel gleichzeitig gültig. Neue Links werden mit dem neuesten Schlüssel signiert, die Prüfung akzeptiert zusätzlich den vorherigen. Ist die Übergangszeit vorbei, deaktivierst du den alten Schlüssel. Die Übergangszeit muss länger sein als die Gültigkeit eines Links.

Deshalb schickt der Pseudocode oben eine Schlüssel-ID (key) im Link mit. Bei Zertifikaten erfüllt der Fingerprint denselben Zweck. So lädt der prüfende Service direkt den richtigen Schlüssel, statt alle durchzuprobieren.

Was solltest du wählen?

Pseudo-OTLs sind oft die bessere Wahl: Du brauchst keine zusätzliche Persistenz, und eine spätere Migration auf einen Object Storage wie S3, Azure Blob Storage oder ein selbst betriebenes MinIO ist einfacher. Echte OTLs lohnen den Mehraufwand, wenn eine Datei wirklich nur ein einziges Mal abgerufen werden darf, etwa bei Zugangsdaten oder Zertifikaten.

Am Ende hängt es wie immer von deinen konkreten Anforderungen ab. Wenn du eine zweite Meinung zu deiner Download-Architektur willst, frag uns im Advisory.

Ursprünglich veröffentlicht am 9. September 2025.

Lass uns über dein Projekt sprechen.

Schreib uns kurz, wo es gerade hakt. Du bekommst eine ehrliche Antwort von einem echten Menschen, keinen Chatbot und keinen Vertriebsanruf.

Du bekommst innerhalb eines Werktags eine Antwort. Das Erstgespräch ist kostenlos und unverbindlich.