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
| Întrebare | Ră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 temporare | Se termină când se încheie sesiunea rolului sau datele STS, oricare survine prima |
| Interval în consola S3 | 1 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
- Codul tău (sau CLI-ul) primește bucketul, cheia obiectului, metoda HTTP și durata de expirare.
- 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.
- Dai URL-ul rezultat cuiva: unui browser, unui coleg, unei aplicații mobile.
- 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
| Parametru | Semnificație |
|---|---|
X-Amz-Algorithm | Algoritmul de semnare: AWS4-HMAC-SHA256 pentru SigV4 |
X-Amz-Credential | ID-ul cheii de acces plus scopul: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request |
X-Amz-Date | Momentul semnării URL-ului, în UTC, yyyyMMddTHHmmssZ |
X-Amz-Expires | Câte secunde este valid URL-ul după X-Amz-Date, de la 1 la 604800 |
X-Amz-SignedHeaders | Anteturile acoperite de semnătură, întotdeauna cel puțin host |
X-Amz-Signature | Semnătura, 64 de caractere hexazecimale |
X-Amz-Security-Token | Prezent 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 cu | Valabilitate 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ță EC2 | Până se rotesc datele rolului, cel mult circa 6 ore |
| Rol de task ECS | Până se rotesc datele taskului, de obicei la fiecare 1 până la 6 ore |
| Orice date de autentificare revocate sau șterse | Se oprește imediat, indiferent ce spune X-Amz-Expires |
| Consola S3 | Alegi î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 antetulETag, 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șiDELETEpresemnate, cu expirare de la 1 secundă la 7 zile. Nu acceptăPOSTpresemnat, iar URL-urile presemnate funcționează doar pe domeniul API-ului S3 (<ACCOUNT_ID>.r2.cloudflarestorage.com), nu pe domenii personalizate. Foloseșteregion: '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
| Eroare | Cauza obișnuită | Soluție |
|---|---|---|
SignatureDoesNotMatch | Metoda, anteturile sau query-ul diferă de cele semnate; ceas desincronizat | Trimite 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-Expires | Generează un URL nou; scurtează intervalul dintre semnare și folosire |
| URL-ul expiră mai devreme decât ai cerut | Semnat cu date de autentificare temporare (rol, EC2, ECS, Lambda) | Semnează cu date de autentificare care trăiesc cât trebuie să trăiască linkul |
ExpiredToken | Sesiunea STS din spatele X-Amz-Security-Token s-a încheiat | Reîmprospătează datele de autentificare înainte de semnare |
403 AccessDenied pe un URL proaspăt | Semnatarul nu are s3:GetObject sau s3:PutObject ori o politică îl respinge | Acordă permisiunea principalului care semnează; verifică bucket policies |
AuthorizationQueryParametersError | Expirare 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 CORS | Nicio regulă CORS pentru originea și metoda ta pe bucket | Adaugă o regulă CORS cu originea ta, GET/PUT și ETag expus |
AccessDenied cu HeadersNotSigned | Range a fost semnat, dar If-Range a fost trimis nesemnat | Adaugă 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:signatureAgerespinge semnăturile mai vechi decât o anumită vârstă, iaraws:SourceIprestrâ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.
- Amazon S3: descărcarea și încărcarea obiectelor cu URL-uri presemnate
- AWS IAM: metode de autentificare (parametrii de query SigV4)
- API-ul Amazon S3: autentificarea cererilor cu parametri de query (SigV4)
- Referința AWS CLI: s3 presign
- Referința Boto3: generate_presigned_url
- AWS SDK for JavaScript v3: @aws-sdk/s3-request-presigner
- Amazon S3: limitele încărcării multipart
- AWS SDKs and Tools: protecții de integritate a datelor pentru Amazon S3
- Cloudflare R2: URL-uri presemnate
- Backblaze: API-ul B2 compatibil S3 acceptă URL-uri presemnate?