0% прочитано

Чому посилання на завантаження і читання мають різний строк дії

Підписані URL для запису і читання можуть використовувати той самий S3-механізм, але вони дають різні права і мають різний ризик. Тому я не використовую для них один спільний строк дії.

11 жовтня 2026 р. 9 хв читанняLaradock

У двох попередніх сценаріях я використовую короткоживучі підписані URL, але для різних операцій.

Перший сценарій - це тимчасове посилання для читання приватного файла. Другий - пряме завантаження файла у S3-сумісне сховище.

На рівні сховища обидва рішення можуть виглядати схоже: застосунок створює підписану адресу з моментом завершення дії.

Але з погляду безпеки це різні права. Одне дозволяє прочитати вже існуючі дані. Інше дозволяє записати нові.

Саме тому я не використовую для них один спільний строк дії лише заради зручності конфігурації.

Строк дії підписаного URL є частиною дозволу. Він має відповідати конкретній операції, а не бути випадковим глобальним числом.

Одна технологія не означає однаковий ризик

Обидва URL тимчасові, але дозволяють різні дії
Read URL existing object    |    vtemporary permission    |    vGET object  Upload URL future object path    |    v

Підписаний URL не є просто "посиланням на файл".

У ньому закладено конкретну операцію, конкретний об’єкт або шлях, параметри запиту і строк дії.

Тому однаковий механізм підпису не робить читання і запис однаковими з точки зору ризику.

URL для завантаження дає право створити або записати об’єкт

Коли застосунок видає URL для прямого завантаження, він фактично дозволяє клієнту записати дані у визначений ключ сховища.

Навіть якщо ключ створив сервер і право дуже вузьке, це все одно операція запису.

Чим довше такий дозвіл залишається дійсним, тим довше існує можливість ним скористатися після моменту, для якого він був створений.

Тому для завантаження я прагну мати коротке вікно, достатнє для нормального початку операції, але не довше без потреби.

URL для читання має інший користувацький сценарій

Користувач може відкрити документ, дивитися відео, завантажувати файл або повернутися до вже відкритої сторінки через певний час.

Надто коротке вікно читання може створити зайві помилки навіть у нормальному сценарії.

Тому строк дії для читання може бути довшим за строк дії дозволу на запис, якщо це відповідає продукту і рівню чутливості файла.

Я визначаю відносне правило, а не універсальні цифри

Різні операції отримують різні часові межі
Upload permission shorter window    |    venough to startthe intended write  Read permission longer window    |    venough forthe intended viewing

Я не вважаю, що існує одна правильна кількість хвилин для всіх систем.

Розмір файла, швидкість мережі, спосіб використання, чутливість даних і можливість повторно запросити URL відрізняються між продуктами.

Натомість правило можна сформулювати стабільніше: дозвіл на запис має бути настільки коротким, наскільки дозволяє нормальний сценарій, а дозвіл на читання може враховувати реальну тривалість споживання файла.

Я не використовую одну змінну для обох сценаріїв

Одна політика приховує різницю між читанням і записом
$expiresAt = now()->addMinutes(    config('files.signed_url_minutes'),); $readUrl = Storage::disk('s3')    ->temporaryUrl(        $readPath,        $expiresAt,    ); $upload = Storage::disk('s3')    ->temporaryUploadUrl(        $uploadPath,        $expiresAt,    );

Такий код технічно простий, але він створює небажаний зв’язок.

Якщо строк треба збільшити для довгого читання відео, автоматично збільшується і вікно запису.

Якщо строк скоротити через ризик завантаження, можна випадково погіршити нормальне читання великих файлів.

Це дві різні політики, тому я хочу бачити їх окремо.

У коді різниця має бути видимою

Окремі строки для окремих дозволів
$uploadExpiresAt = now()->addMinutes(    (int) config(        'files.upload_url_minutes',    ),); $readExpiresAt = now()->addMinutes(    (int) config(        'files.read_url_minutes',    ),); $upload = Storage::disk('s3')    ->temporaryUploadUrl(        $uploadPath,        $uploadExpiresAt,

Тут навіть без знання конкретних значень видно, що система свідомо розрізняє два типи дозволу.

Це важливіше за саме число у конфігурації.

Наступний розробник не повинен здогадуватися, чи однаковий строк був випадковістю, історичною спадщиною або реальною вимогою.

Строк дії визначає сервер, а не клієнт

Клієнт не повинен сам обирати строк дозволу
// Avoid this shape. $expiresIn = $request->integer(    'expiresIn',); $url = Storage::disk('s3')    ->temporaryUrl(        $path,        now()->addSeconds(            $expiresIn,        ),    );

Браузер може повідомити, що хоче виконати певну операцію, але політика безпеки має залишатися на сервері.

Я не дозволяю клієнту довільно збільшувати строк підписаного URL.

Застосунок сам знає, який тип дозволу створює і яка політика до нього застосовується.

Короткий строк не виправляє неправильну перевірку прав

Дуже короткий URL усе одно небезпечний, якщо його видали не тому користувачу або не для того об’єкта.

Строк дії лише обмежує часовий інтервал уже виданого дозволу.

До створення URL застосунок все одно має перевірити право на читання або запис.

Строк дії також не є повноцінним механізмом відкликання

Після видачі підписаного URL сховище перевіряє його підпис і часові умови.

Якщо право користувача змінилося вже після видачі URL, старий URL не обов’язково дізнається про це миттєво.

Саме тому коротші вікна для більш ризикованих операцій корисні, але їх не варто плутати з повноцінним відкликанням доступу.

Прострочений URL для завантаження не потрібно продовжувати

Новий дозвіл проходить через застосунок
upload URL expired        |        vclient asks application again        |        vauthorization again        |        vnew upload permission

Якщо коротке вікно закрилося до початку завантаження, клієнт може запросити новий URL.

Для мене це кращий сценарій, ніж одразу видавати надто довгий дозвіл "про запас".

Новий запит знову проходить через застосунок, де можна повторно перевірити право і поточний стан ресурсу.

Для читання теж створюю новий URL після повторної перевірки

Постійно оновлювати стару підписану адресу на клієнті не потрібно.

Коли URL для читання більше не дійсний, клієнт звертається до застосунку по новий.

Це дає Laravel можливість ще раз перевірити, чи користувач досі має право на файл.

Навіть усередині читання може бути більше однієї політики

Не всі приватні файли однакові.

Відео, яке користувач дивиться в інтерфейсі, і короткий приватний документ можуть мати різний нормальний час використання.

Тому окрема політика для читання не обов’язково означає одне значення для кожного типу файла.

Головне, щоб відмінність випливала з реального сценарію і була визначена на сервері.

У журналах не варто зберігати повні підписані URL без потреби

Підписана адреса на час своєї дії є обліковими даними доступу.

Тому я не хочу без потреби записувати повний URL у прикладні журнали, повідомлення про помилки або аналітику.

Для діагностики зазвичай достатньо знати тип операції, шлях або внутрішній ідентифікатор, момент видачі та результат.

Я тестую політики окремо

Окремі перевірки для запису і читання
Upload URL - authorized request receives URL- URL targets expected object key- expiration follows upload policy- expired permission is rejected- new permission requires application request  Read URL - authorized request receives URL- URL targets expected object- expiration follows read policy- expired URL is rejected- fresh URL requires authorization again

Мій список перевірки для строку дії підписаного URL

Я перевіряю:

  • Яку саме операцію дозволяє URL: читання чи запис?
  • Чи строки для читання і запису визначені окремо?
  • Чи дозвіл на запис не живе довше, ніж потребує нормальний сценарій?
  • Чи читання має достатній час для реального використання файла?
  • Чи строк визначає сервер, а не клієнт?
  • Чи право перевіряється до створення URL?
  • Чи новий URL після завершення строку вимагає нового звернення до застосунку?
  • Чи повні підписані URL не потрапляють у журнали без потреби?
  • Чи політики можна змінювати незалежно одна від одної?

Строк дії є частиною межі дозволу

Для мене різний строк дії URL для запису і читання не є дрібною оптимізацією.

Це спосіб явно показати, що система видає два різні дозволи з різним ризиком і різним нормальним часом використання.

URL для завантаження дає можливість записати дані, тому я тримаю його вікно коротшим. URL для читання може жити довше, якщо користувачу потрібен час, щоб нормально переглянути або завантажити файл.

При цьому жоден строк не замінює авторизацію і не перетворює підписаний URL на повноцінний механізм відкликання.

Час дії дозволу має відповідати дії, яку цей дозвіл відкриває.

Однаковий механізм підпису не означає однакову політику доступу. Читання і запис мають різний ризик, тому їхні часові межі теж можуть бути різними.