Presigned URL в S3 е временна връзка към един обект в частен bucket. Тя носи подпис в query низа си, така че който я притежава, може да изтегли (или качи) този обект без идентификационни данни за AWS, докато връзката не изтече, а bucket-ът никога не става публичен. Създавате я със собствените си ключове, в кода си или от AWS CLI, и може да е валидна от 1 секунда до 7 дни. Това ръководство обяснява как работи, какво означава всеки параметър X-Amz-*, колко дълго може да е валидна, код за изтегляния и качвания и грешките, които най-вероятно ще срещнете. Ограниченията са взети от документацията на AWS и Cloudflare към октомври 2026.
Presigned URL адресите в S3 накратко
| Въпрос | Отговор |
|---|---|
| Какво позволява? | Една операция (GET, PUT, HEAD, DELETE…) върху един обект |
| Максимален срок | 7 дни (604 800 секунди) със SigV4 и ключове на IAM потребител |
| Срок с временни ключове | Изтича, когато свърши сесията на ролята или STS данните, което настъпи първо |
| Диапазон в конзолата на S3 | От 1 минута до 12 часа |
| Срок по подразбиране | 3600 s в AWS CLI и boto3, 900 s в presigner-а на JavaScript v3 |
| Може ли да се използва няколко пъти? | Да, колкото пъти иска всеки, докато не изтече |
| Може ли да се отмени един URL адрес? | Не, само чрез отнемане на подписващите данни или отказ в политика |
| Създаването му извиква ли S3? | Не, подписът се изчислява локално |
Как работи presigned URL
- Вашият код (или CLI) взема bucket-а, ключа на обекта, HTTP метода и срок на валидност.
- SDK подписва тези стойности с вашия secret access key чрез AWS Signature Version 4. В този момент нищо не се изпраща към S3.
- Давате получения URL адрес на някого: браузър, колега, мобилно приложение.
- Когато го използват, S3 изчислява отново подписа със secret, който принадлежи на access key в URL адреса. Ако съвпада, URL адресът не е изтекъл и подписалият има право да извърши тази операция, заявката минава.
URL адресът носи правата на този, който го е подписал. AWS е категоричен по този въпрос: ако IAM потребителят или ролята, генерирали URL адреса, не могат да четат обекта, URL адресът връща 403, колкото и валиден да е подписът.
Какво означават параметрите X-Amz
Presigned URL със SigV4 изглежда така (с добавени нови редове):
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
| Параметър | Значение |
|---|---|
X-Amz-Algorithm | Алгоритъмът на подписване: AWS4-HMAC-SHA256 за SigV4 |
X-Amz-Credential | Access key ID плюс обхват: <key-id>/<YYYYMMDD>/<region>/s3/aws4_request |
X-Amz-Date | Кога е подписан URL адресът, в UTC, yyyyMMddTHHmmssZ |
X-Amz-Expires | Колко секунди е валиден URL адресът след X-Amz-Date, от 1 до 604800 |
X-Amz-SignedHeaders | Заглавките, обхванати от подписа, винаги поне host |
X-Amz-Signature | Подписът, 64 шестнадесетични знака |
X-Amz-Security-Token | Присъства само когато URL адресът е подписан с временни данни (STS, роли, EC2, ECS, SSO) |
Ако промените която и да е подписана част (ключа, метода, срока или подписана заглавка), подписът вече не съвпада. Обърнете внимание и какво разкрива URL адресът като обикновен текст: името на bucket-а, пълния ключ на обекта и вашия access key ID. Secret key никога не е в URL адреса.
Колко дълго е валиден presigned URL
Ограничението зависи от идентификационните данни, които го подписват:
| Подписан с | Максимална валидност |
|---|---|
| Ключове за достъп на IAM потребител (SigV4) | 7 дни, защото самият ключ за подписване на SigV4 е валиден 7 дни |
| Сесия на IAM роля (STS AssumeRole) | До края на сесията, по подразбиране 1 час |
| Профил на EC2 инстанция | До ротацията на данните на ролята, най-много около 6 часа |
| Роля на ECS задача | До ротацията на данните на задачата, обикновено на всеки 1 до 6 часа |
| Отнети или изтрити данни | Спира веднага, каквото и да пише в X-Amz-Expires |
| Конзолата на S3 | Избирате между 1 минута и 12 часа |
Това обяснява най-честата изненада: поискате 7 дни от Lambda функция или EC2 инстанция, а връзката спира да работи след час или няколко часа. URL адресът живее само толкова, колкото данните зад него. Ако ви трябват дълготрайни връзки, подписвайте със специален IAM потребител, който има достъп за четене само до този bucket.
S3 проверява срока, когато заявката започне. Голямо изтегляне, което започне секунда преди крайния срок, завършва нормално, но повторен опит след срока се проваля с AccessDenied и съобщението „Request has expired“. Искане за повече от 604 800 секунди се отхвърля направо.
Как да генерирате presigned URL
AWS CLI
aws s3 presign s3://my-bucket/reports/q3.pdf --expires-in 3600
Командата подписва URL адрес за изтегляне (GET). По подразбиране срокът е 3600 секунди, а максимумът е 604 800. Последните версии на CLI винаги използват SigV4, затова се уверете, че е конфигуриран регион. За URL адреси за качване ви трябва 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,
)
Задайте изрично signature_version='s3v4'. Справочникът на boto3 предупреждава, че заради обратна съвместимост иначе може да подпише с по-старата Signature Version 2 в регионите, които все още я приемат, което мълчаливо изпуска някои параметри и заглавки, като Range. ResponseContentDisposition е по избор: кара браузъра да запази файла с чисто име, вместо да го отвори директно.
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 }
)
Ако пропуснете expiresIn, presigner-ът на JavaScript използва 900 секунди (15 минути).
Presigned URL адреси за качване (PUT)
Същата идея работи и в обратната посока. Подписвате PutObject за един ключ и който има URL адреса, може да запише този обект. Файлът отива директно от устройството му в bucket-а и вашият сървър никога не обработва байтовете. Ако вече съществува обект с този ключ, той се заменя.
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,
})
Добавянето на content-type към signableHeaders обвързва URL адреса с този тип, така че качване с различен Content-Type се отхвърля. В boto3 еквивалентът е generate_presigned_url('put_object', Params={'Bucket': ..., 'Key': ..., 'ContentType': 'application/pdf'}), а клиентът трябва да изпрати същата заглавка.
Три неща, които да проверите, преди да качвате от браузър:
- CORS. Bucket-ът се нуждае от CORS правило, което разрешава вашия произход и метода
PUT. За multipart качвания то трябва и да прави видима заглавкатаETag, защото браузърът трябва да я прочете от всяка част. - Фиксиран ключ. Генерирайте уникален ключ на сървъра (например с UUID префикс), за да не може посетител да презапише чужд файл.
- Контролни суми. Текущите AWS SDK добавят CRC контролна сума към качванията по подразбиране. Ако presigned качванията към S3-съвместим доставчик се провалят с грешки за подпис или контролна сума, задайте
requestChecksumCalculation: 'WHEN_REQUIRED'в клиента.
Presigned POST е отделен механизъм за обикновени HTML формуляри, с политика, която може да ограничи размера и типа на съдържанието. Не всеки S3-съвместим доставчик го поддържа (R2 не го поддържа), затова presigned PUT е по-преносимият избор.
Големи файлове: presigned multipart качвания
Единичен PUT към S3 е ограничен до 5 GB, а AWS препоръчва multipart от около 100 MB. Multipart разделя файла на до 10 000 части, всяка от 5 MiB до 5 GiB с изключение на последната, които се качват независимо, паралелно и с повторни опити за всяка част. Подписването работи на част: сървърът стартира качването, подписва по един URL адрес UploadPart за всяка част, браузърът изпраща всяко парче и връща неговия ETag, а сървърът завършва качването.
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 }] },
})
)
Добавете правило за жизнения цикъл, което прекратява незавършените multipart качвания след няколко дни, иначе изоставените части продължават да заемат таксувано пространство.
Presigned URL адреси в R2, B2, Spaces и Wasabi
Доставчиците, които реализират S3 API със SigV4, приемат същия код: променяте само endpoint-а, региона и ключовете. Детайлите се различават, затова проверете документацията на доставчика:
- Cloudflare R2 поддържа presigned
GET,HEAD,PUTиDELETEсъс срок от 1 секунда до 7 дни. Не поддържа presignedPOST, а presigned URL адресите работят само на домейна на S3 API (<ACCOUNT_ID>.r2.cloudflarestorage.com), не и на собствени домейни. Използвайтеregion: 'auto'. - Backblaze B2 посочва, че неговият S3-съвместим API поддържа presigned URL адреси, генерирани с AWS CLI или SDK.
- DigitalOcean Spaces и Wasabi работят със същите извиквания на SDK, насочени към техните endpoint-и.
За цените при всеки доставчик вижте сравнението на S3, R2, Spaces, Wasabi и B2.
Чести грешки с presigned URL и как да ги поправите
| Грешка | Обичайна причина | Решение |
|---|---|---|
SignatureDoesNotMatch | Методът, заглавките или query низът се различават от подписаните; несинхронизиран часовник | Изпращайте същите Content-Type и заглавки; синхронизирайте часовника с NTP |
AccessDenied „Request has expired“ | URL адресът е след X-Amz-Date + X-Amz-Expires | Генерирайте нов URL адрес; съкратете времето между подписването и използването |
| URL адресът изтича по-рано от поискания срок | Подписан с временни данни (роля, EC2, ECS, Lambda) | Подписвайте с данни, които живеят толкова, колкото трябва да живее връзката |
ExpiredToken | STS сесията зад X-Amz-Security-Token е приключила | Опреснете данните преди подписване |
403 AccessDenied при нов URL адрес | Подписващият няма s3:GetObject или s3:PutObject, или политика го отказва | Дайте правото на подписващия субект; проверете bucket policies |
AuthorizationQueryParametersError | Срок над 604 800 секунди или неправилен обхват на данните | Дръжте X-Amz-Expires до 7 дни; подписвайте в региона на bucket-а |
| Браузърът е блокиран от CORS | Няма CORS правило за вашия произход и метод в bucket-а | Добавете CORS правило с вашия произход, GET/PUT и видим ETag |
AccessDenied с HeadersNotSigned | Range е подписан, но If-Range е изпратен неподписан | Добавете If-Range към подписаните заглавки |
Корпоративните проксита, които пренаписват заглавки или query низове, също развалят подписите. Ако URL адрес работи от една мрежа, а от друга не, тествайте без проксито.
Добри практики за сигурност
AWS нарича presigned URL адресите bearer токени и препоръчва да ги защитавате. На практика:
- Дръжте ги кратки. Минути за качвания и чувствителни файлове, часове за обикновени изтегляния. Генерирайте нов, когато някой отново има нужда от файла.
- Подписвайте с тясна идентичност. Специален IAM потребител или роля, които могат само да четат (или само да записват) въпросния префикс, ограничават щетите, ако връзка изтече навън.
- Добавете предпазни мерки в bucket policy. Условието
s3:signatureAgeотхвърля подписи, по-стари от зададена възраст, аaws:SourceIpограничава от кои мрежи могат да се използват. - Не ги записвайте в логове. Пълните presigned URL адреси в логовете на приложения, в аналитиката или в историята на чатове са работещи идентификационни данни, докато не изтекат.
- Планирайте за това, което им липсва. Няма парола, брояч на изтеглянията и отмяна на отделна връзка, затова поставете отпред приложение, когато ви трябват тези неща.
За задълбочен поглед към споделянето, с варианти, които добавят тези контроли, вижте как да споделяте S3 файлове, без да правите bucket-а публичен.
Как Nubbo използва presigned URL адреси
Nubbo е изграден върху този модел. Когато качвате във файловия мениджър, сървърът подписва PUT (или, от 100 MB нагоре, multipart качване с три паралелни части) и браузърът ви изпраща байтовете директно към вашия bucket. Изтеглянията на отделни файлове използват presigned GET URL адреси, валидни един час. Ключовете ви за достъп се съхраняват криптирани с AES-256-GCM и се използват само на сървъра за подписване.
Връзките за споделяне добавят това, което липсва на обикновените presigned URL адреси: парола, срок на валидност и лимит на изтеглянията по избор, които Nubbo проверява, преди да издаде краткотраен URL адрес, а можете да деактивирате връзка по всяко време. ZIP изтеглянията на няколко файла се сглобяват в браузъра ви, който изтегля всеки файл директно от вашия bucket: Nubbo не вижда съдържанието. Едно честно изключение: миниатюрите се записват във вашия bucket в .nubbo-thumbs/. Работи по един и същ начин с Amazon S3, Cloudflare R2, DigitalOcean Spaces, Wasabi, Backblaze B2 и публични S3-съвместими endpoint-и.
Често задавани въпроси
Какво е presigned URL в S3?
Това е обикновена HTTPS връзка към един обект в частен bucket с добавен подпис в query низа. Който има връзката, може да извърши единствената операция, за която е подписана, обикновено изтегляне (GET) или качване (PUT), докато не изтече. Bucket-ът остава частен, а човекът, който използва връзката, няма нужда от идентификационни данни за AWS.
Какъв е максималният срок на валидност на presigned URL в S3?
Седем дни (604 800 секунди), когато подписвате със Signature Version 4 и дълготрайни ключове на IAM потребител. URL адрес, подписан с временни идентификационни данни, например поета роля или профил на EC2 инстанция, спира да работи, когато тези данни изтекат, дори да сте поискали по-дълъг срок. В конзолата на S3 можете да изберете между 1 минута и 12 часа.
Какво означават X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-SignedHeaders и X-Amz-Signature?
Това са параметрите за удостоверяване на SigV4. Algorithm е методът на подписване (AWS4-HMAC-SHA256), Credential е вашият access key ID плюс обхвата от дата, регион и услуга, Date е моментът на подписване на URL адреса, Expires е колко секунди остава валиден, SignedHeaders изброява заглавките, обхванати от подписа, а Signature е самият подпис. X-Amz-Security-Token се появява само когато URL адресът е подписан с временни идентификационни данни.
Мога ли да отменя presigned URL в S3, преди да изтече?
Не поотделно. Presigned URL спира да работи по-рано само когато идентификационните данни, които са го подписали, бъдат отнети, изтрити или деактивирани, или когато bucket policy откаже заявката. Ако трябва да отменяте отделни връзки, поставете отпред приложение, което раздава краткотрайни URL адреси само след собствените си проверки.
Сигурни ли са presigned URL адресите в S3?
Подписът не може да бъде подправен или променен, а bucket-ът остава частен. Но AWS описва presigned URL адресите като bearer токени: всеки, който получи връзката, може да я използва колкото пъти иска, докато не изтече. Задавайте кратки срокове, използвайте HTTPS и не публикувайте връзките там, откъдето могат да бъдат копирани.
Работят ли presigned URL адресите с Cloudflare R2, Backblaze B2 или Wasabi?
Доставчиците, които реализират S3 API със Signature Version 4, обикновено ги поддържат, като използвате същите извиквания на SDK с endpoint-а на доставчика. Cloudflare R2 например поддържа presigned GET, HEAD, PUT и DELETE със срок от 1 секунда до 7 дни, но не и качвания чрез POST формуляри и не и собствени домейни.
Защо моят presigned URL връща SignatureDoesNotMatch?
AWS посочва три чести причини: часовник на компютъра, който не е синхронизиран, прокси, което променя заглавките или query низа, и заявка, чиито метод, заглавки или параметри се различават от подписаните. При качванията обичайният виновник е изпращането на Content-Type, различен от използвания при генерирането на URL адреса.
Източници
Цените и ограниченията са взети от официалните страници по-долу. Доставчиците ги променят, затова проверете, преди да се обвържете.
- Amazon S3: изтегляне и качване на обекти с presigned URL адреси
- AWS IAM: методи за удостоверяване (query параметри на SigV4)
- Amazon S3 API: удостоверяване на заявки с query параметри (SigV4)
- Справочник на AWS CLI: s3 presign
- Справочник на Boto3: generate_presigned_url
- AWS SDK for JavaScript v3: @aws-sdk/s3-request-presigner
- Amazon S3: ограничения на multipart качванията
- AWS SDKs and Tools: защита на целостта на данните за Amazon S3
- Cloudflare R2: presigned URL адреси
- Backblaze: поддържа ли S3-съвместимият API на B2 presigned URL адреси?