Presigned URL v S3 je dočasný odkaz na jeden objekt v soukromém bucketu. V query stringu nese podpis, takže kdo ji má, může daný objekt stáhnout (nebo nahrát) bez přihlašovacích údajů AWS, dokud odkaz nevyprší, a bucket se nikdy nestane veřejným. Vytvoříte ji svými vlastními klíči, ve svém kódu nebo z AWS CLI, a může platit od 1 sekundy do 7 dní. Tento návod vysvětluje, jak funguje, co znamená každý parametr X-Amz-*, jak dlouho může platit, kód pro stahování a nahrávání a chyby, na které nejspíš narazíte. Limity vycházejí z dokumentace AWS a Cloudflare k říjnu 2026.
Presigned URL v S3 v kostce
| Otázka | Odpověď |
|---|---|
| Co umožňuje? | Jednu operaci (GET, PUT, HEAD, DELETE…) na jednom objektu |
| Maximální platnost | 7 dní (604 800 sekund) se SigV4 a klíči uživatele IAM |
| Platnost s dočasnými klíči | Končí s koncem relace role nebo údajů STS, podle toho, co nastane dřív |
| Rozsah v konzoli S3 | 1 minuta až 12 hodin |
| Výchozí platnost | 3 600 s v AWS CLI a boto3, 900 s v presigneru JavaScript v3 |
| Lze ji použít víckrát? | Ano, kolikrát kdo chce, dokud nevyprší |
| Lze jednu URL zneplatnit? | Ne, jen odvoláním podepisujících údajů nebo zamítnutím v zásadě |
| Volá její vytvoření S3? | Ne, podpis se počítá lokálně |
Jak presigned URL funguje
- Váš kód (nebo CLI) vezme bucket, klíč objektu, metodu HTTP a dobu platnosti.
- SDK tyto hodnoty podepíše vaším tajným přístupovým klíčem pomocí AWS Signature Version 4. V tuto chvíli se do S3 nic neposílá.
- Výslednou URL předáte někomu dalšímu: prohlížeči, kolegovi, mobilní aplikaci.
- Když ji použije, S3 přepočítá podpis se secretem, který patří k přístupovému klíči v URL. Pokud se shoduje, URL nevypršela a podepisující má oprávnění tuto operaci provést, požadavek projde.
URL nese oprávnění toho, kdo ji podepsal. AWS je v tom jasné: pokud uživatel IAM nebo role, která URL vygenerovala, nemůže objekt číst, URL vrátí 403, ať je podpis jakkoli platný.
Co znamenají parametry X-Amz
Presigned URL se SigV4 vypadá takto (zalomení řádků přidána):
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
| Parametr | Význam |
|---|---|
X-Amz-Algorithm | Algoritmus podpisu: AWS4-HMAC-SHA256 pro SigV4 |
X-Amz-Credential | ID přístupového klíče plus rozsah: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request |
X-Amz-Date | Kdy byla URL podepsána, v UTC, yyyyMMddTHHmmssZ |
X-Amz-Expires | Kolik sekund je URL platná po X-Amz-Date, od 1 do 604800 |
X-Amz-SignedHeaders | Hlavičky pokryté podpisem, vždy alespoň host |
X-Amz-Signature | Podpis, 64 hexadecimálních znaků |
X-Amz-Security-Token | Jen pokud byla URL podepsána dočasnými přihlašovacími údaji (STS, role, EC2, ECS, SSO) |
Změňte jakoukoli podepsanou část (klíč, metodu, platnost nebo podepsanou hlavičku) a podpis přestane sedět. Všimněte si také, co URL prozrazuje v čitelné podobě: název bucketu, celý klíč objektu a ID vašeho přístupového klíče. Tajný klíč v URL nikdy není.
Jak dlouho presigned URL platí
Limit závisí na přihlašovacích údajích, které ji podepisují:
| Podepsáno pomocí | Maximální platnost |
|---|---|
| Přístupové klíče uživatele IAM (SigV4) | 7 dní, protože samotný podpisový klíč SigV4 platí 7 dní |
| Relace role IAM (STS AssumeRole) | Do konce relace, ve výchozím stavu 1 hodina |
| Profil instance EC2 | Do rotace údajů role, nejvýše zhruba 6 hodin |
| Role úlohy ECS | Do rotace údajů úlohy, obvykle každých 1 až 6 hodin |
| Jakékoli odvolané nebo smazané údaje | Přestane okamžitě, bez ohledu na X-Amz-Expires |
| Konzole S3 | Volíte mezi 1 minutou a 12 hodinami |
To vysvětluje nejčastější překvapení: z funkce Lambda nebo instance EC2 požádáte o 7 dní a odkaz zemře po hodině nebo pár hodinách. URL žije jen tak dlouho jako přihlašovací údaje za ní. Pokud potřebujete dlouhé odkazy, podepisujte vyhrazeným uživatelem IAM, který má přístup ke čtení jen k tomuto bucketu.
S3 kontroluje platnost při zahájení požadavku. Velké stahování, které začne sekundu před termínem, normálně doběhne, ale opakovaný pokus po termínu selže s AccessDenied a zprávou „Request has expired“. Žádost o víc než 604 800 sekund je rovnou odmítnuta.
Jak vygenerovat presigned URL
AWS CLI
aws s3 presign s3://my-bucket/reports/q3.pdf --expires-in 3600
Příkaz podepíše URL pro stažení (GET). Výchozí hodnota je 3 600 sekund a maximum 604 800. Novější verze CLI vždy používají SigV4, takže mějte nastavený region. Pro URL pro nahrávání potřebujete 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,
)
Nastavte signature_version='s3v4' výslovně. Reference boto3 upozorňuje, že kvůli zpětné kompatibilitě jinak může v regionech, které ho stále přijímají, podepisovat starší Signature Version 2, která potichu zahodí některé parametry a hlavičky, například Range. ResponseContentDisposition je volitelné: prohlížeč pak soubor uloží s čistým názvem, místo aby ho otevřel přímo.
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 }
)
Pokud expiresIn vynecháte, presigner JavaScript použije 900 sekund (15 minut).
Presigned URL pro nahrávání (PUT)
Stejný princip funguje i opačným směrem. Podepíšete PutObject pro jeden klíč a kdo má URL, může tento objekt zapsat. Soubor jde přímo z jeho zařízení do bucketu a váš server se bajtů vůbec nedotkne. Pokud objekt s tímto klíčem už existuje, bude nahrazen.
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,
})
Přidání content-type do signableHeaders váže URL na tento typ, takže nahrání s jiným Content-Type bude odmítnuto. V boto3 je ekvivalentem generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}) a klient musí poslat stejnou hlavičku.
Tři věci, které před nahráváním z prohlížeče zkontrolovat:
- CORS. Bucket potřebuje pravidlo CORS, které povoluje váš origin a metodu
PUT. Pro nahrávání po částech musí také zpřístupnit hlavičkuETag, protože ji prohlížeč musí z každé části přečíst. - Pevný klíč. Klíč generujte na serveru jako jedinečný (například s prefixem UUID), aby návštěvník nemohl přepsat cizí soubor.
- Kontrolní součty. Současné SDK od AWS ve výchozím stavu přidávají k nahrávání kontrolní součet CRC. Pokud presigned nahrávání u poskytovatele kompatibilního s S3 selhává s chybami podpisu nebo kontrolního součtu, nastavte na klientovi
requestChecksumCalculation: 'WHEN_REQUIRED'.
Presigned POST je samostatný mechanismus pro obyčejné HTML formuláře, se zásadou, která může omezit velikost a typ obsahu. Ne každý poskytovatel kompatibilní s S3 ho podporuje (R2 ne), proto je presigned PUT přenositelnější volbou.
Velké soubory: presigned nahrávání po částech
Jeden PUT do S3 je omezen na 5 GB a AWS doporučuje nahrávání po částech zhruba od 100 MB. Nahrávání po částech rozdělí soubor až na 10 000 částí, každou od 5 MiB do 5 GiB kromě poslední, které se nahrávají nezávisle, paralelně a s opakováním po jednotlivých částech. Podepisování funguje po částech: server zahájí nahrávání, podepíše jednu URL UploadPart pro každou část, prohlížeč pošle každý kus a vrátí jeho ETag a server nahrávání dokončí.
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 }] },
})
)
Přidejte pravidlo životního cyklu, které nedokončená nahrávání po částech po několika dnech zruší, jinak opuštěné části dál zabírají účtované úložiště.
Presigned URL v R2, B2, Spaces a Wasabi
Poskytovatelé, kteří implementují S3 API se SigV4, přijmou stejný kód: změníte jen endpoint, region a klíče. Podrobnosti se liší, proto si ověřte dokumentaci poskytovatele:
- Cloudflare R2 podporuje presigned
GET,HEAD,PUTaDELETEs platností od 1 sekundy do 7 dní. Nepodporuje presignedPOSTa presigned URL fungují jen na doméně S3 API (<ACCOUNT_ID>.r2.cloudflarestorage.com), ne na vlastních doménách. Použijteregion: 'auto'. - Backblaze B2 uvádí, že jeho API kompatibilní s S3 podporuje presigned URL generované přes AWS CLI nebo SDK.
- DigitalOcean Spaces a Wasabi fungují se stejnými voláními SDK nasměrovanými na jejich endpointy.
Ceny u jednotlivých poskytovatelů najdete ve srovnání S3, R2, Spaces, Wasabi a B2.
Časté chyby presigned URL a jak je opravit
| Chyba | Obvyklá příčina | Oprava |
|---|---|---|
SignatureDoesNotMatch | Metoda, hlavičky nebo query se liší od podepsaných; nesynchronizované hodiny | Pošlete stejný Content-Type a hlavičky; synchronizujte hodiny přes NTP |
AccessDenied “Request has expired” | URL je za X-Amz-Date + X-Amz-Expires | Vygenerujte novou URL; zkraťte dobu mezi podpisem a použitím |
| URL vyprší dřív, než jste požadovali | Podepsáno dočasnými údaji (role, EC2, ECS, Lambda) | Podepisujte údaji, které žijí tak dlouho, jako má žít odkaz |
ExpiredToken | Relace STS za X-Amz-Security-Token skončila | Před podpisem obnovte přihlašovací údaje |
403 AccessDenied u čerstvé URL | Podepisující nemá s3:GetObject nebo s3:PutObject, nebo ho zamítá zásada | Udělte oprávnění podepisujícímu principálu; zkontrolujte zásady bucketu |
AuthorizationQueryParametersError | Platnost nad 604 800 sekund nebo chybný rozsah údajů | Držte X-Amz-Expires na 7 dnech nebo méně; podepisujte v regionu bucketu |
| Prohlížeč blokován kvůli CORS | Bucket nemá pravidlo CORS pro váš origin a metodu | Přidejte pravidlo CORS s vaším originem, GET/PUT a zpřístupněným ETag |
AccessDenied s HeadersNotSigned | Range byl podepsán, ale If-Range byl odeslán nepodepsaný | Přidejte If-Range do podepsaných hlaviček |
Podpisy rozbíjejí i firemní proxy, které přepisují hlavičky nebo query stringy. Pokud URL funguje z jedné sítě a z jiné ne, vyzkoušejte to bez proxy.
Osvědčené postupy pro bezpečnost
AWS označuje presigned URL za bearer tokeny a doporučuje je chránit. V praxi:
- Držte je krátké. Minuty pro nahrávání a citlivé soubory, hodiny pro běžná stahování. Když někdo soubor potřebuje znovu, vygenerujte novou.
- Podepisujte úzce vymezenou identitou. Vyhrazený uživatel nebo role IAM, která může daný prefix jen číst (nebo jen zapisovat), omezí škody, pokud odkaz unikne.
- Přidejte pojistky do zásady bucketu. Podmínka
s3:signatureAgeodmítá podpisy starší než nastavený věk aaws:SourceIpomezuje, ze kterých sítí je lze použít. - Nelogujte je. Celé presigned URL v aplikačních logech, analytice nebo historii chatu jsou funkční přihlašovací údaje, dokud nevyprší.
- Počítejte s tím, co jim chybí. Nemají heslo, počítadlo stažení ani zneplatnění jednotlivých odkazů, takže když to potřebujete, postavte před bucket aplikaci.
Sdílení do hloubky, s možnostmi, které tyto kontroly přidávají, najdete v článku jak sdílet soubory S3, aniž byste bucket zveřejnili.
Jak Nubbo používá presigned URL
Nubbo je postavené právě na tomto principu. Když nahráváte v průzkumníku, server podepíše PUT (nebo, od 100 MB, nahrávání po částech se třemi částmi paralelně) a váš prohlížeč pošle bajty přímo do vašeho bucketu. Stahování jednotlivých souborů používá presigned URL GET s platností jedna hodina. Vaše přístupové klíče se ukládají zašifrované pomocí AES-256-GCM a na serveru se používají jen k podpisu.
Odkazy ke sdílení přidávají to, co holým presigned URL chybí: volitelné heslo, datum vypršení a limit stažení, které Nubbo zkontroluje dřív, než vydá krátkodobou URL, a odkaz můžete kdykoli deaktivovat. ZIP archivy s více soubory sestavuje váš prohlížeč, který stahuje každý soubor přímo z vašeho bucketu: Nubbo obsah nevidí. Jedna poctivá výjimka: náhledy se zapisují do vašeho vlastního bucketu pod .nubbo-thumbs/. Funguje to stejně v Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 a na veřejných endpointech kompatibilních s S3.
Časté dotazy
Co je presigned URL v S3?
Je to běžný odkaz HTTPS na jeden objekt v soukromém bucketu s podpisem přidaným do query stringu. Kdo odkaz má, může provést jedinou operaci, pro kterou byl podepsán, obvykle stažení (GET) nebo nahrání (PUT), dokud nevyprší. Bucket zůstává soukromý a ten, kdo odkaz používá, nepotřebuje přihlašovací údaje AWS.
Jaká je maximální platnost presigned URL v S3?
Sedm dní (604 800 sekund) při podpisu přes Signature Version 4 s dlouhodobými klíči uživatele IAM. URL podepsaná dočasnými přihlašovacími údaji, například převzatou rolí nebo profilem instance EC2, přestane fungovat, když tyto údaje vyprší, i když jste žádali o delší dobu. V konzoli S3 můžete zvolit 1 minutu až 12 hodin.
Co znamenají X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders a X-Amz-Signature?
Jsou to autentizační parametry SigV4. Algorithm je metoda podpisu (AWS4-HMAC-SHA256), Credential je ID vašeho přístupového klíče spolu s datem, regionem a rozsahem služby, Date je okamžik podpisu URL, Expires je počet sekund platnosti, SignedHeaders vypisuje hlavičky pokryté podpisem a Signature je samotný podpis. X-Amz-Security-Token se objeví jen tehdy, když byla URL podepsána dočasnými přihlašovacími údaji.
Mohu presigned URL v S3 zneplatnit před vypršením?
Ne jednotlivě. Presigned URL přestane fungovat dřív jen tehdy, když jsou přihlašovací údaje, které ji podepsaly, odvolány, smazány nebo deaktivovány, nebo když požadavek zamítne zásada bucketu. Pokud potřebujete rušit jednotlivé odkazy, postavte před bucket aplikaci, která vydává krátkodobé URL až po vlastních kontrolách.
Jsou presigned URL v S3 bezpečné?
Podpis nelze padělat ani změnit a bucket zůstává soukromý. AWS ale presigned URL popisuje jako bearer tokeny: kdokoli odkaz získá, může ho použít, kolikrát chce, dokud nevyprší. Držte dobu platnosti krátkou, používejte HTTPS a nezveřejňujte odkazy tam, kde je lze zkopírovat.
Fungují presigned URL s Cloudflare R2, Backblaze B2 nebo Wasabi?
Poskytovatelé, kteří implementují S3 API se Signature Version 4, je obecně podporují a používáte stejná volání SDK s endpointem poskytovatele. Cloudflare R2 například podporuje presigned GET, HEAD, PUT a DELETE s platností od 1 sekundy do 7 dní, ale ne nahrávání formulářem POST a ne vlastní domény.
Proč moje presigned URL vrací SignatureDoesNotMatch?
AWS uvádí tři časté příčiny: nesynchronizované hodiny počítače, proxy, která mění hlavičky nebo query string, a požadavek, jehož metoda, hlavičky nebo parametry se liší od podepsaných. U nahrávání bývá viníkem odeslání jiného Content-Type, než jaký byl použit při generování URL.
Zdroje
Ceny a limity pocházejí z níže uvedených oficiálních stránek. Poskytovatelé je mění, proto si je před rozhodnutím ověřte.
- Amazon S3: Stahování a nahrávání objektů přes presigned URL
- AWS IAM: Metody autentizace (parametry SigV4 v query stringu)
- Amazon S3 API: Autentizace požadavků parametry v query stringu (SigV4)
- Reference AWS CLI: s3 presign
- Reference Boto3: generate_presigned_url
- AWS SDK for JavaScript v3: @aws-sdk/s3-request-presigner
- Amazon S3: Limity nahrávání po částech
- AWS SDKs and Tools: Ochrana integrity dat pro Amazon S3
- Cloudflare R2: Presigned URL
- Backblaze: Podporuje B2 S3 Compatible API presigned URL?