Основи безпеки
Відкритий у фронтенді ключ AWS це не те саме, що ключ OpenAI
Ключ доступу AWS, відкритий у вашому фронтенді, читає і пише ваше сховище. Рішення зазвичай presigned URL, а не новий ключ.

Коротко
- Ключ доступу AWS, відкритий у вашому фронтенді, це інша проблема, ніж ключ, який уміє лише витрачати гроші. До чого він дотягнеться, вирішують його дозволи.
- Запит до AWS підписують два рядки: ідентифікатор, що починається з `AKIA`, і таємна половина. Один без одної не підписує нічого.
- Новий ключ, вставлений на те саме місце, це та сама знахідка з іншим значенням. Рішення це presigned URL, щоб браузер не тримав жодних облікових даних.
- Ми знайшли такий у 9 з 31 056 просканованих застосунків, де ця перевірка дійшла до кінця.
Хтось відкриває ваш застосунок у браузері, натискає F12 і знаходить рядок, що
починається з AKIA, просто у вашому коді фронтенду. Або GitHub пише вам, що
коміт, який ви відправили в березні, несе облікові дані AWS. Порада, яка
приходить разом з обома випадками, завжди однакова: ротуйте ключ. Для
більшості ключів це майже вся відповідь.
Ось та частина, яку путівник за путівником розуміє неправильно. Ключ доступу AWS, відкритий у вашому фронтенді, це не ключ, який витрачає гроші. Це ключ, який відчиняє речі, і ці двоє ламаються в різні боки. Ключ, який тільки витрачає, це корпоративна картка: хтось набирає рахунок, ви блокуєте картку, а збиток це число, яке можна прочитати у виписці. Ключ, який відчиняє речі, це в’язка від складу. До чого він дотягнеться, залежить від того, що написали на ньому під час виготовлення, і це читається на одному екрані вашої консолі AWS.
Що означає AKIA на початку ключа?
Це позначка довготривалого ключа доступу, який належить або користувачеві у
вашому акаунті, або кореневому входу акаунта. AWS записує цей префікс у
власному довіднику ідентифікаторів: AKIA для ключів доступу і ASIA для
тимчасових, які видає сервіс токенів. Тобто перші чотири символи кажуть вам,
з яким різновидом ви маєте справу, і AKIA це різновид без терміну дії. Він
працює, доки хтось його не вимкне.
Облікові дані AWS це два рядки, і запит потребує обох, щоб бути підписаним.
Перший це ідентифікатор ключа доступу, та частина, що починається з AKIA.
Другий це таємний ключ доступу, довший рядок без жодного префікса спереду.
Сам ідентифікатор не підписує нічого.
Це варто перевірити, перш ніж вирішувати, наскільки поганий цей ранок, бо воно
змінює відповідь. Якщо ваш бандл несе рядок AKIA і нічого схожого на його
таємну половину, відвідувач, який прочитав вашу сторінку, забрав ім’я ключа, а
не ключ. На практиці ці двоє подорожують разом, бо те, що поклало в браузер
один, поклало обидва: пара змінних середовища з іменами AWS_ACCESS_KEY_ID і
AWS_SECRET_ACCESS_KEY, прочитана кодом, який мав працювати на сервері.
Що хтось може зробити з моїм ключем доступу AWS?
Те, що дозволяють його дозволи, і нічого понад те. Тож відповідей три.
Що він може прочитати? Кожен бакет S3, який перелічує політика, і кожен об’єкт усередині, зокрема ті, на які ви ніколи нізвідки не посилалися. Бакет, про який нічого у вашому застосунку не згадує, не схований від облікових даних, які можуть його перелічити.
Що він може записати? Ті самі місця, і це та половина, про яку забувають. Ключ, який уміє писати, уміє також перезаписувати і видаляти, а файл, замінений на місці, виглядає точно як той, що ви завантажили, доки хтось його не відкриє.
Що він може запустити? Ось це з лічильником. Політика, достатньо широка, щоб підняти обчислення, піднімає обчислення, а воно рахує погодинно, доки працює. Ніщо в браузерній копії ключа не обмежує, якої частини вашого акаунта він сягає; політика це єдина межа, яка існує.
Найгірша версія цього це ключ, виготовлений для кореневого входу акаунта. AWS
пише у власних настановах про кореневого користувача, що той має необмежений
доступ до всіх сервісів AWS, ресурсів і даних про рахунки, і радить не
створювати йому ключів доступу взагалі. Якщо ключ на вашій сторінці
починається з AKIA і належить кореневому користувачеві, відкритим є весь
акаунт, а не один бакет.
Тож не вгадуйте нічого з цього. Відкрийте IAM, знайдіть користувача, якому належить ключ, і прочитайте прив’язані до нього політики. Це один екран, і він відповідає на всі три питання вище.
Чи досить просто ротувати його?
Деактивуйте відкритий ключ сьогодні і не ставте заміну на те саме місце.
Деактивація це правильний перший крок, і вона м’якша, ніж звучить. AWS дозволяє користувачеві тримати до двох активних ключів доступу одночасно, і це існує саме для того, щоб заміна піднялася до того, як старий опуститься. Деактивація лишає ключ на місці вимкненим, і його можна ввімкнути назад; видалення незворотне, а таємну половину видаленого ключа не відновити. Тож деактивуйте, подивіться, що зламається, і видаляйте потім.
Чого це не завершує, так це створити новий ключ і вставити його туди, де був
старий. Витік ніколи не був насправді про те конкретне значення. Він був про
браузер, який тримає облікові дані без терміну дії, і все, що завантажує ваша
сторінка, завантажує кожен відвідувач. Свіжий рядок AKIA у тому самому
бандлі повертається як та сама знахідка при наступному скануванні.
AWS каже це прямо у власному посібнику з аудиту безпеки, там про мобільні застосунки: вони ніколи не повинні містити вбудовані ключі доступу, навіть зашифровані. Бандл браузера читається легше за бінарник застосунку, тож та сама відповідь діє і тут, і коштує чужій людині менше роботи.
Якщо ви вже знайшли ключ у публічному місці, порядок роботи має значення, і що робити, коли ключ API витік, викладає цей порядок для ключів будь-якого ґатунку.
Що натомість робить presigned URL
Він дозволяє браузеру зробити одну дію з одним файлом, не тримаючи жодних облікових даних.
Ваш власний сервер лишає ключ доступу собі, там, де відвідувач не може його прочитати. Коли вашій сторінці треба покласти файл у S3 або дістати звідти один, вона просить ваш сервер, і ваш сервер підписує адресу саме для цього об’єкта і саме для цієї дії та віддає її назад. Браузер користується адресою і не отримує з нею нічого більше. AWS описує presigned URL як тимчасовий доступ до об’єктів S3 без облікових даних AWS, і той самий механізм покриває і завантаження вниз, і вивантаження вгору.
Повернімося до складу. Presigned URL це зустріти кур’єра на порозі саме з тією коробкою, по яку він приїхав, замість віддати йому в’язку і сподіватися, що він її знайде. Те, що кур’єр забирає, перестає працювати, коли його годинник добігає кінця.
Для випадку, коли кожна авторизована людина дістається до власних файлів, AWS
знову вказує в інший бік: його настанови про захист ключів доступу кажуть, що
мобільні застосунки мають використовувати Amazon Cognito для керування
особами, а не вбудовувати ключі доступу. Те, що Cognito дає браузеру, це
тимчасові облікові дані, різновид ASIA з початку цієї статті, які за якийсь
час перестають працювати самі. Копія, зіскоблена з вашої сторінки у вівторок,
уже мертва в середу, і це єдина властивість, якої ключ AKIA не має.
Як перевірити, чи мій застосунок віддає ключ AWS?
Шукайте в тому, що завантажив браузер, а не в тому, що лежить у проєкті. Це два різні файли, і важить той, який отримують ваші відвідувачі.
У браузері. Відкрийте опублікований сайт, натисніть F12 і пошукайте AKIA
у завантаженому JavaScript. Chrome і Edge шукають одразу в усіх завантажених
файлах із панелі Sources.
У проєкті. Пошукайте AKIA, AWS_ACCESS_KEY_ID і
AWS_SECRET_ACCESS_KEY. Потім пошукайте два префікси, які кладуть значення у
бандл навмисно, VITE_ і NEXT_PUBLIC_, і прочитайте кожне значення за ними.
Чому ці два префікси публікують усе, що називають,
це механіка за більшістю таких випадків, і це правило збірки, якого ніхто не
набирав помилково.
Ззовні. Наше безкоштовне сканування читає ваш опублікований сайт так, як це зробила б чужа людина, і повідомляє, які облікові дані воно бачить у тому, що ви віддали, зокрема й цей. Воно триває близько 20 секунд і не потребує акаунта: просканувати застосунок безкоштовно.
Серед усіх застосунків, які ми сканували, це рідкісна знахідка: ключ доступу AWS трапився в 9 з 31 056 застосунків, де ця перевірка дійшла до кінця. Значно частіше трапляються ключі Google, які зазвичай нормальні, і ключі OpenAI, які зазвичай ні. Що насправді витікає із застосунків, зроблених так, ставить їх усі поруч із числами.
Що ключ робив, поки був назовні
Відкрийте історію подій CloudTrail і відфільтруйте її за ідентифікатором ключа доступу.
Історія подій увімкнена в кожному акаунті AWS без жодних налаштувань, вона тримає останні 90 днів і не коштує нічого додатково. Кожен запис несе ідентифікатор ключа, який зробив виклик, тож ви можете перечитати, що робив ваш. Це відповідає на питання про конфігурацію: створений бакет, змінена політика, доданий користувач.
Далі йде та частина, яку варто знати, перш ніж іти дивитися. Історія тримає події management. Прочитати об’єкт із S3 це подія data, і AWS прямо каже, що trails не журналюють їх за замовчуванням і що події data взагалі не з’являються в історії. Увімкнення записує від того моменту вперед.
Тож чесне прочитання таке. Якщо ключем змінювали ваш акаунт, журнал вам покаже. Якщо ним завантажували вміст бакета, журнал, найімовірніше, не покаже, і ви вирішуєте, що казати клієнтам, розуміючи, що це могло статися.
Як утримати ключ поза наступною збіркою
Облікові дані вирушають у браузер під час збірки, тож пильнувати треба наступне розгортання. Ключ, який ви прибираєте сьогодні, повертається того дня, коли хтось додає функцію з S3 і просить агента її підключити.
Reeve Monitor перечитує ваш опублікований сайт за вас:
- усі дев’ять перевірок щогодини, для до трьох застосунків
- повідомлення, коли результат змінюється, щоб ключ, який з’явився у вівторок, не чекав, доки ви заглянете
- чи застосунок відповідає, кожні 60 секунд
- щомісячний звіт про побачене
Якщо ваш застосунок тримає дані у проєкті Supabase, Reeve Care зберігає копію і цього:
- зашифрована копія вашої бази Supabase щоночі, складена там, куди ваш проєкт не дістає
- кожна копія перевірена, перш ніж її зарахувати, підрахунком рядків у кожній таблиці
- відновлення в один клік, коли воно знадобиться
- а також ваші завантажені файли, щойно ви під’єднаєте облікові дані Storage
- усе, що робить Monitor
Кожна з тих дев’яти перевірок описує, до чого може дотягнутися чужа людина. Копія бази за вчорашню ніч відповідає на інше питання, на те, що саме хтось уже змінив, поки ключ був назовні.
Що зробити цього тижня
Що робити
- Відкрийте опублікований сайт, натисніть F12 і пошукайте
AKIAу завантаженому JavaScript. Це той файл, який мають ваші відвідувачі, і лише він важить. - Якщо знайшли, деактивуйте його в IAM сьогодні. Деактивація оборотна і діє одразу; видалення ні, і таємну половину не відновити.
- Прочитайте політики, прив’язані до користувача ключа, перш ніж вирішувати, наскільки це серйозно. Що він читає, що пише і що запускає це три окремі відповіді.
- Замініть схему, а не значення. Ваш сервер тримає ключ і підписує presigned URL для одного об’єкта, або Amazon Cognito дає браузеру тимчасові облікові дані, які спливають самі.
- Відфільтруйте історію подій CloudTrail за ключем за останні 90 днів. Вона покаже, що ключ налаштував, і не покаже, які файли він читав, якщо події data не були ввімкнені заздалегідь.
Почніть із пошуку через F12, бо він за хвилину вирішує, чи є у вас проблема взагалі. Якщо щось знайдеться, десятихвилинний чеклист безпеки покриває решту того, що щойно запущений застосунок зазвичай лишає відчиненим, а перенесення секрету в edge function це схема для кожного ключа, якому ніколи не слід було бути на сторінці.
Поширені запитання
Чи буває безпечно класти ключі AWS у код фронтенду?
Ні. AWS каже це у власному посібнику з аудиту безпеки, говорячи про мобільні застосунки: застосунок ніколи не повинен містити вбудовані ключі доступу, навіть зашифровані. Бандл браузера читається легше за бінарник застосунку, тож та сама відповідь діє і тут, і коштує чужій людині менше роботи. Якщо ваша сторінка справді має дістатися до S3, передбачені шляхи це presigned URL, підписаний вашим власним сервером, або тимчасові облікові дані від Amazon Cognito, які спливають самі.
Що хтось може зробити з моїм ключем доступу AWS?
Рівно те, що дозволяють його дозволи, і саме тому єдиної відповіді немає. Ключ, прив’язаний до користувача з доступом на читання одного бакета, читає цей бакет. Ключ, прив’язаний до адміністратора, робить усе, що робить адміністратор, зокрема запускає машини з погодинною оплатою. Ключ кореневого користувача акаунта це найгірший випадок, бо AWS пише, що кореневий користувач має необмежений доступ до всіх сервісів, ресурсів і даних про рахунки. Відкрийте IAM і прочитайте політики, прив’язані до ключа, перш ніж вирішувати, наскільки хвилюватися.
Що таке presigned URL?
Довга URL-адреса, яка дозволяє браузеру зробити одну дію з одним файлом у S3 протягом визначеної кількості секунд, не тримаючи жодних облікових даних AWS. Ваш власний сервер тримає ключ і підписує цю адресу на запит. AWS описує presigned URL як тимчасовий доступ до об’єктів S3 без облікових даних AWS, і вони працюють і для завантаження вниз, і для вивантаження вгору.
Як перевірити, чи мій застосунок віддає ключ AWS?
Шукайте в тому, що завантажив ваш браузер, а не в тому, що лежить у проєкті. Відкрийте опублікований сайт, натисніть F12 і пошукайте AKIA у завантаженому JavaScript. Потім пошукайте у проєкті AKIA, AWS_ACCESS_KEY_ID і AWS_SECRET_ACCESS_KEY, а також будь-яке ім’я змінної, що починається на VITE_ або NEXT_PUBLIC_ і містить таке значення, бо саме ці префікси й кладуть значення у бандл.
Мій ключ AWS на GitHub. Що тепер?
Спершу деактивуйте його в IAM, це оборотно і діє одразу, а потім створіть заміну для сервера, якому він був потрібен. Прибрати ключ із коду не закриває нічого, бо старе значення лишається в історії комітів і в кожному клоні, який хтось зробив. Після цього відкрийте історію подій CloudTrail і відфільтруйте за ключем, щоб побачити, що він робив.