Articol

URL-uri presemnate S3: ce sunt, cum funcționează, limite de expirare și exemple de cod

Ce este un URL presemnat S3, ce înseamnă fiecare parametru X-Amz, limita de 7 zile, cod de încărcare și descărcare (CLI, boto3, JS) și erori frecvente.

Un URL presemnat S3 este un link temporar către un obiect dintr-un bucket privat. Are o semnătură în query string, așa că oricine îl deține poate descărca (sau încărca) acel obiect fără date de autentificare AWS până când linkul expiră, iar bucketul nu devine niciodată public. Îl creezi cu propriile chei, în codul tău sau din AWS CLI, și poate dura de la 1 secundă până la 7 zile. Acest ghid explică cum funcționează, ce înseamnă fiecare parametru X-Amz-*, cât poate dura, cod pentru descărcări și încărcări și erorile pe care le vei întâlni cel mai probabil. Limitele sunt preluate din documentația AWS și Cloudflare, în octombrie 2026.

URL-urile presemnate S3 pe scurt

ÎntrebareRăspuns
Ce permite?O singură operație (GET, PUT, HEAD, DELETE…) pe un singur obiect
Expirare maximă7 zile (604.800 de secunde) cu SigV4 și chei de utilizator IAM
Expirare cu chei temporareSe termină când se încheie sesiunea rolului sau datele STS, oricare survine prima
Interval în consola S31 minut până la 12 ore
Expirare implicită3.600 s în AWS CLI și boto3, 900 s în presignerul JavaScript v3
Poate fi folosit de mai multe ori?Da, de câte ori vrea oricine, până expiră
Poate fi revocat un singur URL?Nu, doar prin revocarea datelor de semnare sau prin respingere într-o politică
Crearea lui apelează S3?Nu, semnătura se calculează local

Cum funcționează un URL presemnat

  1. Codul tău (sau CLI-ul) primește bucketul, cheia obiectului, metoda HTTP și durata de expirare.
  2. SDK-ul semnează aceste valori cu cheia ta secretă de acces folosind AWS Signature Version 4. În acest moment nu se trimite nimic la S3.
  3. Dai URL-ul rezultat cuiva: unui browser, unui coleg, unei aplicații mobile.
  4. Când îl folosește, S3 recalculează semnătura cu secretul care aparține cheii de acces din URL. Dacă se potrivește, URL-ul nu a expirat și semnatarul are voie să efectueze acea operație, cererea trece.

URL-ul poartă permisiunile celui care l-a semnat. AWS spune clar acest lucru: dacă utilizatorul sau rolul IAM care a generat URL-ul nu poate citi obiectul, URL-ul returnează 403, oricât de validă ar fi semnătura.

Ce înseamnă parametrii X-Amz

Un URL presemnat SigV4 arată așa (cu rânduri noi adăugate):

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
ParametruSemnificație
X-Amz-AlgorithmAlgoritmul de semnare: AWS4-HMAC-SHA256 pentru SigV4
X-Amz-CredentialID-ul cheii de acces plus scopul: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request
X-Amz-DateMomentul semnării URL-ului, în UTC, yyyyMMddTHHmmssZ
X-Amz-ExpiresCâte secunde este valid URL-ul după X-Amz-Date, de la 1 la 604800
X-Amz-SignedHeadersAnteturile acoperite de semnătură, întotdeauna cel puțin host
X-Amz-SignatureSemnătura, 64 de caractere hexazecimale
X-Amz-Security-TokenPrezent doar când URL-ul a fost semnat cu date de autentificare temporare (STS, roluri, EC2, ECS, SSO)

Dacă modifici orice parte semnată (cheia, metoda, expirarea sau un antet semnat), semnătura nu se mai potrivește. Observă și ce dezvăluie URL-ul în clar: numele bucketului, cheia completă a obiectului și ID-ul cheii tale de acces. Cheia secretă nu apare niciodată în URL.

Cât durează un URL presemnat

Limita depinde de datele de autentificare care îl semnează:

Semnat cuValabilitate maximă
Chei de acces ale unui utilizator IAM (SigV4)7 zile, pentru că însăși cheia de semnare SigV4 este valabilă 7 zile
Sesiune de rol IAM (STS AssumeRole)Până se încheie sesiunea, implicit 1 oră
Profil de instanță EC2Până se rotesc datele rolului, cel mult circa 6 ore
Rol de task ECSPână se rotesc datele taskului, de obicei la fiecare 1 până la 6 ore
Orice date de autentificare revocate sau șterseSe oprește imediat, indiferent ce spune X-Amz-Expires
Consola S3Alegi între 1 minut și 12 ore

Asta explică cea mai frecventă surpriză: ceri 7 zile dintr-o funcție Lambda sau de pe o instanță EC2, iar linkul moare după o oră sau după câteva ore. URL-ul trăiește doar cât datele de autentificare din spatele lui. Dacă ai nevoie de linkuri lungi, semnează cu un utilizator IAM dedicat care are acces de citire doar la acel bucket.

S3 verifică expirarea când începe o cerere. O descărcare mare care începe cu o secundă înainte de termen se termină normal, dar o reîncercare după termen eșuează cu AccessDenied și mesajul „Request has expired”. O cerere de peste 604.800 de secunde este respinsă direct.

Cum generezi un URL presemnat

AWS CLI

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

Comanda semnează un URL de descărcare (GET). Valoarea implicită este 3.600 de secunde, iar maximul 604.800. Versiunile recente ale CLI-ului folosesc mereu SigV4, așa că asigură-te că ai o regiune configurată. Pentru URL-uri de încărcare ai nevoie de un 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,
)

Setează explicit signature_version='s3v4'. Referința boto3 avertizează că, pentru compatibilitate cu versiunile vechi, altfel poate semna cu vechiul Signature Version 2 în regiunile care încă îl acceptă, ceea ce elimină în tăcere unii parametri și anteturi, precum Range. ResponseContentDisposition este opțional: face ca browserul să salveze fișierul cu un nume curat, în loc să-l deschidă direct.

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 }
)

Dacă omiți expiresIn, presignerul JavaScript folosește 900 de secunde (15 minute).

URL-uri presemnate pentru încărcare (PUT)

Aceeași idee funcționează și în sens invers. Semnezi un PutObject pentru o cheie, iar cine are URL-ul poate scrie acel obiect. Fișierul pleacă direct de pe dispozitivul lui în bucket, iar serverul tău nu atinge niciodată bytes. Dacă există deja un obiect cu acea cheie, este înlocuit.

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,
})

Adăugarea content-type în signableHeaders leagă URL-ul de acel tip, așa că o încărcare cu alt Content-Type este respinsă. În boto3, echivalentul este generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), iar clientul trebuie să trimită același antet.

Trei lucruri de verificat înainte să încarci din browser:

  • CORS. Bucketul are nevoie de o regulă CORS care permite originea ta și metoda PUT. Pentru încărcările multipart trebuie să expună și antetul ETag, pentru că browserul trebuie să-l citească din fiecare parte.
  • Cheie fixă. Generează o cheie unică pe server (de exemplu cu un prefix UUID), ca un vizitator să nu poată suprascrie fișierul altcuiva.
  • Sume de control. SDK-urile AWS actuale adaugă implicit o sumă de control CRC la încărcări. Dacă încărcările presemnate eșuează la un furnizor compatibil S3 cu erori de semnătură sau de sumă de control, setează requestChecksumCalculation: 'WHEN_REQUIRED' pe client.

Presigned POST este un mecanism separat pentru formulare HTML simple, cu o politică ce poate limita dimensiunea și tipul de conținut. Nu toți furnizorii compatibili S3 îl acceptă (R2 nu), așa că PUT presemnat este alegerea mai portabilă.

Fișiere mari: încărcări multipart presemnate

Un singur PUT în S3 este limitat la 5 GB, iar AWS sugerează multipart de la circa 100 MB. Multipart împarte fișierul în până la 10.000 de părți, fiecare între 5 MiB și 5 GiB, cu excepția ultimei, care se încarcă independent, în paralel și cu reîncercări pe fiecare parte. Presemnarea funcționează per parte: serverul pornește încărcarea, semnează câte un URL UploadPart pentru fiecare parte, browserul trimite fiecare bucată și raportează ETag-ul ei, iar serverul finalizează încărcarea.

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 }] },
  })
)

Adaugă o regulă de ciclu de viață care anulează încărcările multipart neterminate după câteva zile, altfel părțile abandonate continuă să ocupe stocare facturabilă.

URL-uri presemnate în R2, B2, Spaces și Wasabi

Furnizorii care implementează API-ul S3 cu SigV4 acceptă același cod: schimbi doar endpointul, regiunea și cheile. Detaliile diferă, așa că verifică documentația furnizorului:

  • Cloudflare R2 acceptă GET, HEAD, PUT și DELETE presemnate, cu expirare de la 1 secundă la 7 zile. Nu acceptă POST presemnat, iar URL-urile presemnate funcționează doar pe domeniul API-ului S3 (<ACCOUNT_ID>.r2.cloudflarestorage.com), nu pe domenii personalizate. Folosește region: 'auto'.
  • Backblaze B2 afirmă că API-ul său compatibil S3 acceptă URL-uri presemnate generate cu AWS CLI sau cu SDK-urile.
  • DigitalOcean Spaces și Wasabi funcționează cu aceleași apeluri SDK îndreptate spre endpointurile lor.

Pentru prețurile fiecărui furnizor, vezi comparația dintre S3, R2, Spaces, Wasabi și B2.

Erori frecvente cu URL-uri presemnate și cum le rezolvi

EroareCauza obișnuităSoluție
SignatureDoesNotMatchMetoda, anteturile sau query-ul diferă de cele semnate; ceas desincronizatTrimite același Content-Type și aceleași anteturi; sincronizează ceasul cu NTP
AccessDenied „Request has expired”URL-ul a depășit X-Amz-Date + X-Amz-ExpiresGenerează un URL nou; scurtează intervalul dintre semnare și folosire
URL-ul expiră mai devreme decât ai cerutSemnat cu date de autentificare temporare (rol, EC2, ECS, Lambda)Semnează cu date de autentificare care trăiesc cât trebuie să trăiască linkul
ExpiredTokenSesiunea STS din spatele X-Amz-Security-Token s-a încheiatReîmprospătează datele de autentificare înainte de semnare
403 AccessDenied pe un URL proaspătSemnatarul nu are s3:GetObject sau s3:PutObject ori o politică îl respingeAcordă permisiunea principalului care semnează; verifică bucket policies
AuthorizationQueryParametersErrorExpirare de peste 604.800 de secunde sau scop de credențiale malformatȚine X-Amz-Expires la 7 zile sau mai puțin; semnează în regiunea bucketului
Browserul este blocat de CORSNicio regulă CORS pentru originea și metoda ta pe bucketAdaugă o regulă CORS cu originea ta, GET/PUT și ETag expus
AccessDenied cu HeadersNotSignedRange a fost semnat, dar If-Range a fost trimis nesemnatAdaugă If-Range la anteturile semnate

Și proxy-urile corporative care rescriu anteturile sau query string-urile strică semnăturile. Dacă un URL funcționează dintr-o rețea și din alta nu, testează fără proxy.

Bune practici de securitate

AWS numește URL-urile presemnate bearer tokens și recomandă protejarea lor. În practică:

  • Ține-le scurte. Minute pentru încărcări și fișiere sensibile, ore pentru descărcări obișnuite. Generează unul nou când cineva are din nou nevoie de fișier.
  • Semnează cu o identitate restrânsă. Un utilizator sau rol IAM dedicat, care poate doar citi (sau doar scrie) prefixul respectiv, limitează pagubele dacă un link ajunge unde nu trebuie.
  • Adaugă limite în bucket policy. Condiția s3:signatureAge respinge semnăturile mai vechi decât o anumită vârstă, iar aws:SourceIp restrânge rețelele care le pot folosi.
  • Nu le înregistra în loguri. URL-urile presemnate complete din logurile aplicației, din analytics sau din istoricul de chat sunt date de autentificare funcționale până la expirare.
  • Ține cont de ce le lipsește. Nu există parolă, contor de descărcări sau revocare per link, așa că pune o aplicație în față când ai nevoie de acestea.

Pentru partea de partajare în detaliu, cu opțiuni care adaugă aceste controale, vezi cum partajezi fișiere S3 fără să faci bucketul public.

Cum folosește Nubbo URL-urile presemnate

Nubbo este construit pe acest model. Când încarci în explorator, serverul semnează un PUT (sau, de la 100 MB, o încărcare multipart cu trei părți în paralel), iar browserul tău trimite bytes direct în bucketul tău. Descărcările de fișiere individuale folosesc URL-uri GET presemnate, valabile o oră. Cheile tale de acces sunt păstrate criptate cu AES-256-GCM și sunt folosite doar pe server, pentru semnare.

Linkurile de partajare adaugă ce le lipsește URL-urilor presemnate simple: o parolă, o dată de expirare și o limită de descărcări opționale, pe care Nubbo le verifică înainte să emită un URL de scurtă durată, iar tu poți dezactiva un link oricând. Descărcările ZIP cu mai multe fișiere sunt asamblate în browserul tău, care descarcă fiecare fișier direct din bucket: Nubbo nu vede niciodată conținutul. O singură excepție, spusă sincer: miniaturile se scriu în propriul tău bucket, în .nubbo-thumbs/. Funcționează la fel în Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 și pe endpointuri publice compatibile S3.

Întrebări frecvente

Ce este un URL presemnat în S3?

Este un link HTTPS obișnuit către un obiect dintr-un bucket privat, cu o semnătură adăugată în query string. Cine are linkul poate efectua singura operație pentru care a fost semnat, de obicei o descărcare (GET) sau o încărcare (PUT), până când expiră. Bucketul rămâne privat, iar persoana care folosește linkul nu are nevoie de date de autentificare AWS.

Care este expirarea maximă a unui URL presemnat S3?

Șapte zile (604.800 de secunde) când semnezi cu Signature Version 4 și chei pe termen lung ale unui utilizator IAM. Un URL semnat cu date de autentificare temporare, de exemplu un rol asumat sau un profil de instanță EC2, nu mai funcționează când acestea expiră, chiar dacă ai cerut mai mult. În consola S3 poți alege între 1 minut și 12 ore.

Ce înseamnă X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders și X-Amz-Signature?

Sunt parametrii de autentificare SigV4. Algorithm este metoda de semnare (AWS4-HMAC-SHA256), Credential este ID-ul cheii de acces plus scopul cu data, regiunea și serviciul, Date este momentul semnării URL-ului, Expires este numărul de secunde în care rămâne valid, SignedHeaders enumeră anteturile acoperite de semnătură, iar Signature este semnătura propriu-zisă. X-Amz-Security-Token apare doar când URL-ul a fost semnat cu date de autentificare temporare.

Pot revoca un URL presemnat S3 înainte să expire?

Nu unul câte unul. Un URL presemnat nu mai funcționează mai devreme doar când datele de autentificare care l-au semnat sunt revocate, șterse sau dezactivate ori când o bucket policy respinge cererea. Dacă ai nevoie să anulezi linkuri individuale, pune în față o aplicație care emite URL-uri de scurtă durată doar după propriile verificări.

URL-urile presemnate S3 sunt sigure?

Semnătura nu poate fi falsificată sau modificată, iar bucketul rămâne privat. Dar AWS descrie URL-urile presemnate ca bearer tokens: oricine primește linkul îl poate folosi, de câte ori vrea, până expiră. Păstrează duratele de expirare scurte, folosește HTTPS și evită să publici linkurile unde pot fi copiate.

URL-urile presemnate funcționează cu Cloudflare R2, Backblaze B2 sau Wasabi?

Furnizorii care implementează API-ul S3 cu Signature Version 4 le acceptă în general, iar tu folosești aceleași apeluri SDK cu endpointul furnizorului. Cloudflare R2, de exemplu, acceptă GET, HEAD, PUT și DELETE presemnate, cu expirare între 1 secundă și 7 zile, dar nu și încărcări prin formulare POST și nici domenii personalizate.

De ce URL-ul meu presemnat returnează SignatureDoesNotMatch?

AWS enumeră trei cauze frecvente: ceasul computerului desincronizat, un proxy care modifică anteturile sau query string-ul și o cerere a cărei metodă, anteturi sau parametri diferă de cele semnate. La încărcări, vinovatul obișnuit este trimiterea unui Content-Type diferit de cel folosit la generarea URL-ului.

Surse

Prețurile și limitele provin din paginile oficiale de mai jos. Furnizorii le schimbă, așa că verifică-le înainte să te decizi.