Artykuł

Presigned URL w S3: czym są, jak działają, limity ważności i przykłady kodu

Czym jest presigned URL w S3, co oznacza każdy parametr X-Amz, limit 7 dni, kod do przesyłania i pobierania (CLI, boto3, JS) i typowe błędy.

Presigned URL w S3, czyli podpisany adres URL, to tymczasowy link do jednego obiektu w prywatnym buckecie. W query stringu ma podpis, więc każdy, kto go posiada, może pobrać (lub przesłać) ten obiekt bez danych uwierzytelniających AWS, dopóki link nie wygaśnie, a bucket nigdy nie staje się publiczny. Tworzysz go własnymi kluczami, w kodzie lub z AWS CLI, i może być ważny od 1 sekundy do 7 dni. Ten poradnik wyjaśnia, jak to działa, co oznacza każdy parametr X-Amz-*, jak długo link może być ważny, pokazuje kod do pobierania i przesyłania oraz błędy, na które najczęściej się trafia. Limity pochodzą z dokumentacji AWS i Cloudflare według stanu na październik 2026.

Presigned URL w S3 w skrócie

PytanieOdpowiedź
Na co pozwala?Jedna operacja (GET, PUT, HEAD, DELETE…) na jednym obiekcie
Maksymalna ważność7 dni (604 800 sekund) z SigV4 i kluczami użytkownika IAM
Ważność z kluczami tymczasowymiKończy się wraz z sesją roli lub danymi STS, zależnie od tego, co nastąpi pierwsze
Zakres w konsoli S3Od 1 minuty do 12 godzin
Domyślna ważność3600 s w AWS CLI i boto3, 900 s w presignerze JavaScript v3
Czy można go użyć kilka razy?Tak, dowolnie często aż do wygaśnięcia
Czy można unieważnić jeden URL?Nie, tylko przez unieważnienie danych, którymi podpisano, lub odmowę w polityce
Czy utworzenie go wywołuje S3?Nie, podpis jest obliczany lokalnie

Jak działa presigned URL

  1. Twój kod (lub CLI) przyjmuje bucket, klucz obiektu, metodę HTTP i czas ważności.
  2. SDK podpisuje te wartości twoim secret access key za pomocą AWS Signature Version 4. Na tym etapie nic nie jest wysyłane do S3.
  3. Przekazujesz wynikowy URL komuś: przeglądarce, współpracownikowi, aplikacji mobilnej.
  4. Gdy ktoś go użyje, S3 ponownie oblicza podpis za pomocą secret należącego do klucza dostępu zawartego w URL. Jeśli podpis się zgadza, URL nie wygasł, a podpisujący ma uprawnienia do tej operacji, żądanie zostaje wykonane.

URL niesie uprawnienia tego, kto go podpisał. AWS mówi o tym wprost: jeśli użytkownik lub rola IAM, która wygenerowała URL, nie może odczytać obiektu, URL zwraca 403 bez względu na to, jak poprawny jest podpis.

Co oznaczają parametry X-Amz

Presigned URL w SigV4 wygląda tak (z dodanymi podziałami wierszy):

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
ParametrZnaczenie
X-Amz-AlgorithmAlgorytm podpisu: AWS4-HMAC-SHA256 dla SigV4
X-Amz-CredentialIdentyfikator klucza dostępu wraz z zakresem: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request
X-Amz-DateMoment podpisania URL, w UTC, yyyyMMddTHHmmssZ
X-Amz-ExpiresLiczba sekund ważności URL od X-Amz-Date, od 1 do 604800
X-Amz-SignedHeadersNagłówki objęte podpisem, zawsze co najmniej host
X-Amz-SignaturePodpis, 64 znaki szesnastkowe
X-Amz-Security-TokenObecny tylko wtedy, gdy URL podpisano tymczasowymi danymi uwierzytelniającymi (STS, role, EC2, ECS, SSO)

Zmień dowolną podpisaną część (klucz, metodę, ważność lub podpisany nagłówek), a podpis przestanie się zgadzać. Zwróć też uwagę, co URL ujawnia otwartym tekstem: nazwę bucketu, pełny klucz obiektu i identyfikator twojego klucza dostępu. Klucz tajny nigdy nie trafia do URL.

Jak długo ważny jest presigned URL

Limit zależy od danych uwierzytelniających, którymi go podpisano:

Podpisany za pomocąMaksymalna ważność
Kluczy dostępu użytkownika IAM (SigV4)7 dni, bo sam klucz podpisu SigV4 jest ważny przez 7 dni
Sesji roli IAM (STS AssumeRole)Do końca sesji, domyślnie 1 godzina
Profilu instancji EC2Do rotacji danych roli, najwyżej około 6 godzin
Roli zadania ECSDo rotacji danych zadania, zwykle co 1 do 6 godzin
Dowolnych danych unieważnionych lub usuniętychPrzestaje działać natychmiast, bez względu na X-Amz-Expires
Konsoli S3Wybierasz od 1 minuty do 12 godzin

To wyjaśnia najczęstsze zaskoczenie: prosisz o 7 dni z funkcji Lambda lub instancji EC2, a link przestaje działać po godzinie lub kilku godzinach. URL żyje tylko tak długo jak dane uwierzytelniające, które za nim stoją. Jeśli potrzebujesz długich linków, podpisuj je osobnym użytkownikiem IAM z dostępem do odczytu tylko tego bucketu.

S3 sprawdza ważność w chwili rozpoczęcia żądania. Duże pobieranie, które zaczyna się sekundę przed terminem, kończy się normalnie, ale ponowna próba po terminie kończy się błędem AccessDenied z komunikatem „Request has expired”. Prośba o więcej niż 604 800 sekund jest od razu odrzucana.

Jak wygenerować presigned URL

AWS CLI

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

Polecenie podpisuje URL do pobierania (GET). Domyślnie to 3600 sekund, a maksymalnie 604 800. Nowsze wersje CLI zawsze używają SigV4, więc upewnij się, że masz skonfigurowany region. Do URL przesyłania potrzebujesz 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,
)

Ustaw jawnie signature_version='s3v4'. Dokumentacja boto3 ostrzega, że ze względu na zgodność wsteczną w przeciwnym razie może podpisywać starszą Signature Version 2 w regionach, które ją jeszcze akceptują, co po cichu pomija niektóre parametry i nagłówki, takie jak Range. ResponseContentDisposition jest opcjonalny: sprawia, że przeglądarka zapisuje plik pod czystą nazwą, zamiast otwierać go w oknie.

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

Jeśli pominiesz expiresIn, presigner JavaScript użyje 900 sekund (15 minut).

Presigned URL do przesyłania (PUT)

Ten sam pomysł działa w drugą stronę. Podpisujesz PutObject dla jednego klucza, a każdy, kto ma URL, może zapisać ten obiekt. Plik trafia prosto z jego urządzenia do bucketu, a twój serwer nigdy nie obsługuje tych bajtów. Jeśli obiekt o tym kluczu już istnieje, zostaje zastąpiony.

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

Dodanie content-type do signableHeaders wiąże URL z tym typem, więc przesłanie z innym Content-Type zostanie odrzucone. W boto3 odpowiednikiem jest generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), a przesyłający musi wysłać ten sam nagłówek.

Trzy rzeczy do sprawdzenia przed przesyłaniem z przeglądarki:

  • CORS. Bucket potrzebuje reguły CORS, która dopuszcza twój origin i metodę PUT. Przy przesyłaniu multipart musi też udostępniać nagłówek ETag, bo przeglądarka musi go odczytać z każdej części.
  • Stały klucz. Generuj unikalny klucz na serwerze (na przykład z prefiksem UUID), aby odwiedzający nie mógł nadpisać cudzego pliku.
  • Sumy kontrolne. Aktualne SDK AWS domyślnie dodają do przesyłanych plików sumę kontrolną CRC. Jeśli przesyłanie przez presigned URL do dostawcy zgodnego z S3 kończy się błędami podpisu lub sumy kontrolnej, ustaw w kliencie SDK requestChecksumCalculation: 'WHEN_REQUIRED'.

Presigned POST to osobny mechanizm dla zwykłych formularzy HTML, z polityką, która może ograniczać rozmiar i typ zawartości. Nie każdy dostawca zgodny z S3 go obsługuje (R2 nie), więc presigned PUT jest wyborem bardziej przenośnym.

Duże pliki: przesyłanie multipart przez presigned URL

Pojedynczy PUT do S3 jest ograniczony do 5 GB, a AWS zaleca multipart od około 100 MB. Multipart dzieli plik na maksymalnie 10 000 części, każdą od 5 MiB do 5 GiB z wyjątkiem ostatniej, które są przesyłane niezależnie, równolegle i z ponawianiem dla każdej części. Podpisywanie działa dla każdej części osobno: serwer rozpoczyna przesyłanie, podpisuje po jednym URL UploadPart na część, przeglądarka wysyła każdy fragment i odsyła jego ETag, a serwer kończy przesyłanie.

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 regułę cyklu życia, która przerywa niedokończone przesyłania multipart po kilku dniach, w przeciwnym razie porzucone części nadal zajmują płatną pamięć.

Presigned URL w R2, B2, Spaces i Wasabi

Dostawcy implementujący S3 API z SigV4 akceptują ten sam kod: zmieniasz tylko endpoint, region i klucze. Szczegóły się różnią, więc sprawdź dokumentację dostawcy:

  • Cloudflare R2 obsługuje podpisane GET, HEAD, PUT i DELETE z ważnością od 1 sekundy do 7 dni. Nie obsługuje podpisanego POST, a presigned URL działają tylko w domenie S3 API (<ACCOUNT_ID>.r2.cloudflarestorage.com), a nie we własnych domenach. Użyj region: 'auto'.
  • Backblaze B2 podaje, że jego API zgodne z S3 obsługuje presigned URL generowane za pomocą AWS CLI lub SDK.
  • DigitalOcean Spaces i Wasabi działają z tymi samymi wywołaniami SDK skierowanymi na ich endpointy.

Ceny u każdego dostawcy znajdziesz w porównaniu S3, R2, Spaces, Wasabi i B2.

Typowe błędy presigned URL i jak je naprawić

BłądZwykła przyczynaRozwiązanie
SignatureDoesNotMatchMetoda, nagłówki lub query różnią się od podpisanych; niezsynchronizowany zegarWysyłaj ten sam Content-Type i nagłówki; zsynchronizuj zegar przez NTP
AccessDenied „Request has expired”URL przekroczył X-Amz-Date + X-Amz-ExpiresWygeneruj nowy URL; skróć czas między podpisaniem a użyciem
URL wygasa wcześniej, niż żądanoPodpisany tymczasowymi danymi (rola, EC2, ECS, Lambda)Podpisuj danymi, które żyją tak długo, jak ma działać link
ExpiredTokenSesja STS za X-Amz-Security-Token się skończyłaOdśwież dane uwierzytelniające przed podpisaniem
403 AccessDenied przy świeżym URLPodpisujący nie ma s3:GetObject lub s3:PutObject albo polityka tego zabraniaNadaj uprawnienie podmiotowi, który podpisuje; sprawdź polityki bucketu
AuthorizationQueryParametersErrorWażność powyżej 604 800 sekund lub błędny zakres danych uwierzytelniającychTrzymaj X-Amz-Expires na 7 dniach lub mniej; podpisuj w regionie bucketu
Przeglądarka zablokowana przez CORSBrak w buckecie reguły CORS dla twojego originu i metodyDodaj regułę CORS z twoim originem, GET/PUT i udostępnionym ETag
AccessDenied z HeadersNotSignedRange został podpisany, ale If-Range wysłano bez podpisuDodaj If-Range do podpisanych nagłówków

Firmowe proxy, które przepisują nagłówki lub query stringi, również psują podpisy. Jeśli URL działa w jednej sieci, a w innej nie, przetestuj go bez proxy.

Dobre praktyki bezpieczeństwa

AWS nazywa presigned URL tokenami na okaziciela i zaleca ich ochronę. W praktyce:

  • Ustawiaj krótką ważność. Minuty dla przesyłania i wrażliwych plików, godziny dla zwykłych pobrań. Generuj nowy, gdy ktoś znów potrzebuje pliku.
  • Podpisuj tożsamością o wąskich uprawnieniach. Osobny użytkownik lub rola IAM, która może tylko odczytywać (lub tylko zapisywać) dany prefiks, ogranicza szkody, jeśli link wycieknie.
  • Dodaj zabezpieczenia w polityce bucketu. Warunek s3:signatureAge odrzuca podpisy starsze niż ustalony wiek, a aws:SourceIp ogranicza, z jakich sieci można ich używać.
  • Nie zapisuj ich w logach. Pełne presigned URL w logach aplikacji, analityce lub historii czatu są działającymi danymi dostępowymi aż do wygaśnięcia.
  • Zaplanuj to, czego im brakuje. Nie mają hasła, licznika pobrań ani unieważniania pojedynczych linków, więc gdy tego potrzebujesz, postaw przed bucketem aplikację.

Więcej o udostępnianiu, z opcjami, które dodają te kontrole, przeczytasz w artykule jak udostępniać pliki S3 bez upubliczniania bucketu.

Jak Nubbo korzysta z presigned URL

Nubbo jest zbudowane na tym wzorcu. Gdy przesyłasz plik w eksploratorze, serwer podpisuje PUT (lub, od 100 MB, przesyłanie multipart z trzema częściami równolegle), a twoja przeglądarka wysyła bajty bezpośrednio do twojego bucketu. Pobieranie pojedynczych plików korzysta z podpisanych URL GET ważnych przez godzinę. Twoje klucze dostępu są przechowywane w postaci zaszyfrowanej algorytmem AES-256-GCM i są używane wyłącznie na serwerze do podpisywania.

Linki udostępniające dodają to, czego brakuje surowym presigned URL: opcjonalne hasło, datę wygaśnięcia i limit pobrań, które Nubbo sprawdza przed wydaniem krótkotrwałego URL, a link możesz w każdej chwili dezaktywować. Pobrania ZIP z wieloma plikami są składane w twojej przeglądarce, która pobiera każdy plik prosto z twojego bucketu: Nubbo nigdy nie widzi zawartości. Jeden uczciwy wyjątek: miniatury są zapisywane w twoim własnym buckecie w .nubbo-thumbs/. Wszystko działa tak samo w Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 i publicznych endpointach zgodnych z S3.

Najczęściej zadawane pytania

Czym jest presigned URL w S3?

To zwykły link HTTPS do jednego obiektu w prywatnym buckecie z podpisem dodanym do query stringu. Każdy, kto ma link, może wykonać jedną operację, dla której został podpisany, zwykle pobranie (GET) lub przesłanie (PUT), aż do jego wygaśnięcia. Bucket pozostaje prywatny, a osoba korzystająca z linku nie potrzebuje danych uwierzytelniających AWS.

Jaka jest maksymalna ważność presigned URL w S3?

Siedem dni (604 800 sekund), gdy podpisujesz za pomocą Signature Version 4 i długoterminowych kluczy użytkownika IAM. URL podpisany tymczasowymi danymi uwierzytelniającymi, na przykład przejętą rolą lub profilem instancji EC2, przestaje działać, gdy te dane wygasną, nawet jeśli poprosisz o dłuższy czas. W konsoli S3 możesz wybrać od 1 minuty do 12 godzin.

Co oznaczają X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders i X-Amz-Signature?

To parametry uwierzytelniania SigV4. Algorithm to metoda podpisu (AWS4-HMAC-SHA256), Credential to identyfikator klucza dostępu wraz z zakresem daty, regionu i usługi, Date to moment podpisania URL, Expires to liczba sekund ważności, SignedHeaders wymienia nagłówki objęte podpisem, a Signature to sam podpis. X-Amz-Security-Token pojawia się tylko wtedy, gdy URL został podpisany tymczasowymi danymi uwierzytelniającymi.

Czy mogę unieważnić presigned URL w S3 przed jego wygaśnięciem?

Nie pojedynczo. Presigned URL przestaje działać wcześniej tylko wtedy, gdy dane uwierzytelniające, którymi go podpisano, zostaną unieważnione, usunięte lub dezaktywowane albo gdy polityka bucketu odrzuci żądanie. Jeśli musisz anulować pojedyncze linki, postaw przed bucketem aplikację, która wydaje krótkotrwałe URL dopiero po własnych kontrolach.

Czy presigned URL w S3 są bezpieczne?

Podpisu nie da się podrobić ani zmienić, a bucket pozostaje prywatny. AWS opisuje jednak presigned URL jako tokeny na okaziciela (bearer tokens): każdy, kto zdobędzie link, może go używać dowolnie wiele razy aż do wygaśnięcia. Ustawiaj krótki czas ważności, używaj HTTPS i nie publikuj linków tam, gdzie można je skopiować.

Czy presigned URL działają z Cloudflare R2, Backblaze B2 lub Wasabi?

Dostawcy, którzy implementują S3 API z Signature Version 4, zazwyczaj je obsługują, a ty używasz tych samych wywołań SDK z endpointem dostawcy. Cloudflare R2 na przykład obsługuje podpisane GET, HEAD, PUT i DELETE z ważnością od 1 sekundy do 7 dni, ale nie obsługuje przesyłania formularzem POST ani własnych domen.

Dlaczego mój presigned URL zwraca SignatureDoesNotMatch?

AWS wymienia trzy częste przyczyny: niezsynchronizowany zegar komputera, proxy zmieniające nagłówki lub query string oraz żądanie, którego metoda, nagłówki lub parametry różnią się od podpisanych. Przy przesyłaniu zwykle winny jest inny Content-Type niż ten użyty przy generowaniu URL.

Źródła

Ceny i limity pochodzą z poniższych oficjalnych stron. Dostawcy je zmieniają, więc sprawdź je, zanim się zdecydujesz.