Članak

S3 presigned URL-ovi: što su, kako rade, ograničenja isteka i primjeri koda

Što je S3 presigned URL, što znači svaki X-Amz parametar, ograničenje isteka od 7 dana, kod za prijenos i preuzimanje (CLI, boto3, JS) i česte greške.

S3 presigned URL je privremena poveznica na jedan objekt u privatnom bucketu. U svom query stringu nosi potpis, pa tko god ga ima, može preuzeti (ili prenijeti) taj objekt bez AWS vjerodajnica dok poveznica ne istekne, a bucket nikad ne postaje javan. Izrađuješ ga vlastitim ključevima, u svom kodu ili iz AWS CLI-ja, a može trajati od 1 sekunde do 7 dana. Ovaj vodič objašnjava kako radi, što znači svaki parametar X-Amz-*, koliko dugo može trajati, kod za preuzimanja i prijenose te greške na koje ćeš najvjerojatnije naići. Ograničenja su preuzeta iz AWS i Cloudflare dokumentacije, stanje u listopadu 2026.

S3 presigned URL-ovi ukratko

PitanjeOdgovor
Što omogućuje?Jednu operaciju (GET, PUT, HEAD, DELETE…) na jednom objektu
Najdulji istek7 dana (604.800 sekundi) uz SigV4 i ključeve IAM korisnika
Istek uz privremene ključeveZavršava kad završi sesija uloge ili STS vjerodajnice, što god nastupi prije
Raspon u S3 konzoliOd 1 minute do 12 sati
Zadani istek3.600 s u AWS CLI-ju i boto3, 900 s u JavaScript v3 presigneru
Može li se koristiti više puta?Da, koliko god puta bilo tko želi dok ne istekne
Može li se opozvati jedan URL?Ne, samo opozivom vjerodajnica za potpisivanje ili odbijanjem u politici
Poziva li izrada URL-a S3?Ne, potpis se izračunava lokalno

Kako radi presigned URL

  1. Tvoj kod (ili CLI) uzima bucket, ključ objekta, HTTP metodu i vrijeme isteka.
  2. SDK potpisuje te vrijednosti tvojim tajnim pristupnim ključem pomoću AWS Signature Version 4. U tom trenutku ništa se ne šalje u S3.
  3. Dobiveni URL daješ nekome: pregledniku, kolegi, mobilnoj aplikaciji.
  4. Kad ga upotrijebe, S3 ponovno izračunava potpis tajnom koja pripada pristupnom ključu u URL-u. Ako se podudara, URL nije istekao i potpisnik smije izvesti tu operaciju, zahtjev prolazi.

URL nosi dopuštenja onoga tko ga je potpisao. AWS je oko toga izričit: ako IAM korisnik ili uloga koja je generirala URL ne može čitati objekt, URL vraća 403 koliko god potpis bio valjan.

Što znače X-Amz parametri

SigV4 presigned URL izgleda ovako (prijelomi redaka dodani):

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
ParametarZnačenje
X-Amz-AlgorithmAlgoritam potpisivanja: AWS4-HMAC-SHA256 za SigV4
X-Amz-CredentialID pristupnog ključa plus opseg: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request
X-Amz-DateTrenutak potpisivanja URL-a, u UTC-u, yyyyMMddTHHmmssZ
X-Amz-ExpiresKoliko je sekundi URL valjan nakon X-Amz-Date, od 1 do 604800
X-Amz-SignedHeadersZaglavlja obuhvaćena potpisom, uvijek barem host
X-Amz-SignaturePotpis, 64 heksadecimalna znaka
X-Amz-Security-TokenPrisutan samo kad je URL potpisan privremenim vjerodajnicama (STS, uloge, EC2, ECS, SSO)

Promijeni bilo koji potpisani dio (ključ, metodu, istek ili potpisano zaglavlje) i potpis se više ne podudara. Obrati pozornost i na to što URL otkriva kao običan tekst: naziv bucketa, puni ključ objekta i ID tvog pristupnog ključa. Tajni ključ nikad nije u URL-u.

Koliko dugo traje presigned URL

Ograničenje ovisi o vjerodajnicama koje ga potpisuju:

Potpisano sNajdulja valjanost
Pristupni ključevi IAM korisnika (SigV4)7 dana, jer je i sam SigV4 ključ za potpisivanje valjan 7 dana
Sesija IAM uloge (STS AssumeRole)Dok sesija ne završi, zadano 1 sat
Profil EC2 instanceDok se vjerodajnice uloge ne zamijene, najviše oko 6 sati
ECS task roleDok se vjerodajnice zadatka ne zamijene, obično svakih 1 do 6 sati
Bilo koje opozvane ili izbrisane vjerodajnicePrestaje odmah, bez obzira na to što kaže X-Amz-Expires
S3 konzolaBiraš između 1 minute i 12 sati

To objašnjava najčešće iznenađenje: tražiš 7 dana iz Lambda funkcije ili EC2 instance, a poveznica prestane raditi nakon sat ili nekoliko sati. URL živi samo onoliko koliko i vjerodajnice iza njega. Ako trebaš dugotrajne poveznice, potpisuj namjenskim IAM korisnikom koji ima pristup za čitanje samo tom bucketu.

S3 provjerava istek kad zahtjev započne. Veliko preuzimanje koje počne sekundu prije roka završava normalno, ali ponovni pokušaj nakon roka ne uspijeva s AccessDenied i porukom “Request has expired”. Traženje više od 604.800 sekundi odmah se odbija.

Kako generirati presigned URL

AWS CLI

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

Naredba potpisuje URL za preuzimanje (GET). Zadano je 3.600 sekundi, a najviše 604.800. Novije verzije CLI-ja uvijek koriste SigV4, pa provjeri je li regija konfigurirana. Za URL-ove za prijenos treba ti 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,
)

Izričito postavi signature_version='s3v4'. Referenca boto3 upozorava da u suprotnom, radi kompatibilnosti unatrag, može potpisivati starijim Signature Version 2 u regijama koje ga još prihvaćaju, čime tiho ispušta neke parametre i zaglavlja kao što je Range. ResponseContentDisposition je opcionalan: tjera preglednik da spremi datoteku s čistim nazivom umjesto da je otvori u kartici.

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

Ako izostaviš expiresIn, JavaScript presigner koristi 900 sekundi (15 minuta).

Presigned URL-ovi za prijenos (PUT)

Ista ideja radi i u suprotnom smjeru. Potpišeš PutObject za jedan ključ i tko god ima URL, može zapisati taj objekt. Datoteka ide izravno s njihovog uređaja u bucket, a tvoj server nikad ne obrađuje bajtove. Ako objekt s tim ključem već postoji, bit će zamijenjen.

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

Dodavanje content-type u signableHeaders veže URL uz tu vrstu, pa se prijenos s drugačijim Content-Type odbija. U boto3 ekvivalent je generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), a klijent mora poslati isto zaglavlje.

Tri stvari koje treba provjeriti prije prijenosa iz preglednika:

  • CORS. Bucket treba CORS pravilo koje dopušta tvoje ishodište i metodu PUT. Za multipart prijenose mora izlagati i zaglavlje ETag, jer ga preglednik mora pročitati iz svakog dijela.
  • Fiksni ključ. Generiraj jedinstveni ključ na serveru (na primjer s UUID prefiksom) kako posjetitelj ne bi mogao prepisati tuđu datoteku.
  • Kontrolni zbrojevi. Trenutni AWS SDK-ovi prijenosima zadano dodaju CRC kontrolni zbroj. Ako presigned prijenosi prema S3 kompatibilnom pružatelju ne uspijevaju zbog grešaka potpisa ili kontrolnog zbroja, na klijentu postavi requestChecksumCalculation: 'WHEN_REQUIRED'.

Presigned POST je zaseban mehanizam za obične HTML obrasce, s politikom koja može ograničiti veličinu i vrstu sadržaja. Ne podržava ga svaki S3 kompatibilni pružatelj (R2 ga ne podržava), pa je presigned PUT prenosiviji izbor.

Velike datoteke: presigned multipart prijenosi

Pojedinačni PUT u S3 ograničen je na 5 GB, a AWS preporučuje multipart od otprilike 100 MB. Multipart dijeli datoteku na do 10.000 dijelova, svaki od 5 MiB do 5 GiB osim posljednjeg, koji se prenose neovisno, paralelno i s ponovnim pokušajima po dijelu. Potpisivanje radi po dijelu: server započinje prijenos, potpisuje jedan UploadPart URL po dijelu, preglednik šalje svaki komad i vraća njegov ETag, a server dovršava prijenos.

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

Dodaj pravilo životnog ciklusa koje nakon nekoliko dana prekida nedovršene multipart prijenose, inače napušteni dijelovi i dalje zauzimaju naplativu pohranu.

Presigned URL-ovi na R2, B2, Spaces i Wasabiju

Pružatelji koji implementiraju S3 API sa SigV4 prihvaćaju isti kod: mijenjaš samo endpoint, regiju i ključeve. Pojedinosti se razlikuju, pa provjeri dokumentaciju pružatelja:

  • Cloudflare R2 podržava presigned GET, HEAD, PUT i DELETE, s istekom od 1 sekunde do 7 dana. Ne podržava presigned POST, a presigned URL-ovi rade samo na domeni S3 API-ja (<ACCOUNT_ID>.r2.cloudflarestorage.com), ne na prilagođenim domenama. Koristi region: 'auto'.
  • Backblaze B2 navodi da njegov S3 kompatibilni API podržava presigned URL-ove generirane AWS CLI-jem ili SDK-ovima.
  • DigitalOcean Spaces i Wasabi rade s istim SDK pozivima usmjerenima na njihove endpointe.

Za cijene kod svakog pružatelja pogledaj usporedbu S3, R2, Spaces, Wasabija i B2.

Česte greške presigned URL-ova i kako ih riješiti

GreškaUobičajeni uzrokRješenje
SignatureDoesNotMatchMetoda, zaglavlja ili query razlikuju se od potpisanih; neusklađen satPošalji isti Content-Type i zaglavlja; uskladi sat preko NTP-a
AccessDenied “Request has expired”URL je prošao X-Amz-Date + X-Amz-ExpiresGeneriraj novi URL; skrati razmak između potpisivanja i upotrebe
URL istječe ranije od traženogPotpisan privremenim vjerodajnicama (uloga, EC2, ECS, Lambda)Potpisuj vjerodajnicama koje traju koliko mora trajati i poveznica
ExpiredTokenSTS sesija iza X-Amz-Security-Token je završilaOsvježi vjerodajnice prije potpisivanja
403 AccessDenied na novom URL-uPotpisniku nedostaje s3:GetObject ili s3:PutObject ili ga politika odbijaDodijeli dopuštenje potpisniku; provjeri bucket politike
AuthorizationQueryParametersErrorIstek iznad 604.800 sekundi ili neispravan opseg vjerodajniceDrži X-Amz-Expires na 7 dana ili manje; potpisuj u regiji bucketa
Preglednik blokiran zbog CORS-aNa bucketu nema CORS pravila za tvoje ishodište i metoduDodaj CORS pravilo s tvojim ishodištem, GET/PUT i izloženim ETag
AccessDenied s HeadersNotSignedRange je potpisan, ali If-Range je poslan nepotpisanDodaj If-Range u potpisana zaglavlja

Korporativni proxyji koji prepisuju zaglavlja ili query stringove također kvare potpise. Ako URL radi iz jedne mreže, a iz druge ne, testiraj bez proxyja.

Najbolje sigurnosne prakse

AWS presigned URL-ove naziva bearer tokenima i preporučuje njihovu zaštitu. U praksi:

  • Neka budu kratki. Minute za prijenose i osjetljive datoteke, sati za obična preuzimanja. Generiraj novi kad nekome datoteka ponovno zatreba.
  • Potpisuj uskim identitetom. Namjenski IAM korisnik ili uloga koja može samo čitati (ili samo pisati) dotični prefiks ograničava štetu ako poveznica procuri.
  • Dodaj zaštitne ograde u bucket politiku. Uvjet s3:signatureAge odbija potpise starije od zadane starosti, a aws:SourceIp ograničava iz kojih se mreža mogu koristiti.
  • Nemoj ih zapisivati u logove. Puni presigned URL-ovi u logovima aplikacije, analitici ili povijesti chata funkcionalne su vjerodajnice dok ne isteknu.
  • Planiraj za ono što im nedostaje. Nema lozinke, brojača preuzimanja ni opoziva po poveznici, pa ispred stavi aplikaciju kad ti to treba.

Za detaljniji pogled na dijeljenje, s opcijama koje dodaju te kontrole, pogledaj kako dijeliti S3 datoteke bez da bucket učiniš javnim.

Kako Nubbo koristi presigned URL-ove

Nubbo je izgrađen na ovom obrascu. Kad prenosiš u pregledniku datoteka, server potpisuje PUT (ili, od 100 MB, multipart prijenos s tri paralelna dijela), a tvoj preglednik šalje bajtove izravno u tvoj bucket. Preuzimanja pojedinačnih datoteka koriste presigned GET URL-ove valjane jedan sat. Tvoji se pristupni ključevi spremaju šifrirani algoritmom AES-256-GCM i koriste se samo na serveru za potpisivanje.

Poveznice za dijeljenje dodaju ono što običnim presigned URL-ovima nedostaje: opcionalnu lozinku, datum isteka i ograničenje preuzimanja koje Nubbo provjerava prije nego što izda kratkotrajni URL, a poveznicu možeš deaktivirati u bilo kojem trenutku. ZIP preuzimanja više datoteka sastavljaju se u tvom pregledniku, koji svaku datoteku preuzima izravno iz tvog bucketa: Nubbo nikad ne vidi sadržaj. Jedna iskrena iznimka: minijature se zapisuju u tvoj vlastiti bucket pod .nubbo-thumbs/. Radi jednako na Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabiju, Backblaze B2 i javnim S3 kompatibilnim endpointima.

Česta pitanja

Što je presigned URL u S3?

To je obična HTTPS poveznica na jedan objekt u privatnom bucketu s potpisom dodanim u query string. Tko god ima poveznicu, može izvesti jednu operaciju za koju je potpisana, obično preuzimanje (GET) ili prijenos (PUT), sve dok ne istekne. Bucket ostaje privatan, a osobi koja koristi poveznicu ne trebaju AWS vjerodajnice.

Koliki je najdulji istek S3 presigned URL-a?

Sedam dana (604.800 sekundi) kad potpisuješ sa Signature Version 4 i dugotrajnim ključevima IAM korisnika. URL potpisan privremenim vjerodajnicama, kao što su preuzeta uloga ili profil EC2 instance, prestaje raditi kad te vjerodajnice isteknu, čak i ako si tražio dulje. U S3 konzoli možeš birati između 1 minute i 12 sati.

Što znače X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders i X-Amz-Signature?

To su SigV4 parametri autentifikacije. Algorithm je metoda potpisivanja (AWS4-HMAC-SHA256), Credential je ID tvog pristupnog ključa plus opseg datuma, regije i usluge, Date je trenutak potpisivanja URL-a, Expires je koliko sekundi ostaje valjan, SignedHeaders navodi zaglavlja obuhvaćena potpisom, a Signature je sam potpis. X-Amz-Security-Token pojavljuje se samo kad je URL potpisan privremenim vjerodajnicama.

Mogu li opozvati S3 presigned URL prije isteka?

Ne pojedinačno. Presigned URL prestaje raditi ranije samo kad se vjerodajnice koje su ga potpisale opozovu, izbrišu ili deaktiviraju ili kad bucket politika odbije zahtjev. Ako trebaš poništavati pojedine poveznice, stavi ispred aplikaciju koja izdaje kratkotrajne URL-ove tek nakon vlastitih provjera.

Jesu li S3 presigned URL-ovi sigurni?

Potpis se ne može krivotvoriti ni izmijeniti, a bucket ostaje privatan. No AWS presigned URL-ove opisuje kao bearer tokene: tko god dobije poveznicu, može je koristiti, koliko god puta želi, dok ne istekne. Drži vrijeme isteka kratkim, koristi HTTPS i izbjegavaj objavljivanje poveznica ondje gdje se mogu kopirati.

Rade li presigned URL-ovi s Cloudflare R2, Backblaze B2 ili Wasabijem?

Pružatelji koji implementiraju S3 API sa Signature Version 4 općenito ih podržavaju, a koristiš iste SDK pozive s endpointom pružatelja. Cloudflare R2, na primjer, podržava presigned GET, HEAD, PUT i DELETE s istekom od 1 sekunde do 7 dana, ali ne i prijenose putem POST obrasca ni prilagođene domene.

Zašto moj presigned URL vraća SignatureDoesNotMatch?

AWS navodi tri česta uzroka: neusklađen sat računala, proxy koji mijenja zaglavlja ili query string i zahtjev čija se metoda, zaglavlja ili parametri razlikuju od potpisanih. Kod prijenosa je uobičajeni krivac slanje drugačijeg Content-Typea od onoga korištenog pri generiranju URL-a.

Izvori

Cijene i ograničenja potječu sa službenih stranica u nastavku. Pružatelji ih mijenjaju, pa ih provjeri prije nego što se odlučiš.