Автентифікація та авторизація – це два наріжні камені безпеки сучасних вебзастосунків, однак існує безліч способів зробити в них помилки. У статті йде мова про те, як виявляти ці недоліки безпеки та уникати вразливостей, які можуть дозволити зловмисникам отримати доступ до конфіденційних даних та функцій, оминаючи автентифікацію, авторизацію або і те, й інше одночасно.
В чому різниця між автентифікацією та авторизацією?
Автентифікація й авторизація не тільки звучать і виглядають подібно, а й тісно пов’язані між собою. Нижче наведено їх визначення:
- Автентифікація – це підтвердження особи (ідентичності). Це може бути введення імені користувача та пароля, використання системи єдиного входу або надання унікального ключа доступу.
- Авторизація – це перевірка прав доступу. Після автентифікації застосунок має переконатися, що користувач має дозвіл на доступ до певного ресурсу чи операції, зазвичай на основі його ролі.
Оскільки обидва процеси зазвичай виконуються разом, їх часто узагальнюють терміном “auth”. Оскільки сучасні корпоративні вебзастосунки дуже залежать від правильного забезпечення контролю доступу для захисту конфіденційних даних, вразливості та атаки, пов’язані з автентифікацією та авторизацією, є особливо значущими для веббезпеки.
Поширені типи вразливостей
Впровадження ефективного контролю доступу є непростим завданням через безліч чинників. Часто безпека залишається на другому плані у процесі розробки програмного забезпечення, і контроль доступу не є винятком. Щоб прискорити розробку, застосунок можуть побудувати взагалі без обмежень доступу, куди додають форму входу лише наприкінці, що створює значні ризики.
Розподілені архітектури програмного забезпечення ускладнюють це ще більше: запити часто проходять через декілька сервісів та інтерфейсів. Забезпечити належний контроль доступу в такому середовищі дуже важко, особливо коли різні модулі створюються окремими командами. Проблеми з передачею auth-даних через API, формати даних, домени та фізичні системи тільки підвищують ймовірність помилок. Ось кілька типових прикладів:
Небезпечні порівняння значень
Однією з проблем є небезпечні порівняння значень, яких ще називають “type juggling” вразливостями. Дві з найпопулярніших мов програмування, а саме JavaScript та PHP, мають нестрогу (слабку) типізацію. Це означає, що вони за замовчуванням дуже поблажливі щодо типів даних, які приймають. Кожна з них також має свої особливості в порівнянні значень, тому без належної перевірки вхідних даних зловмисники можуть ввести спеціальне значення, яке завжди приймається в певному контексті.
Приклад: форма входу, де значення імені користувача та пароля надсилаються безпосередньо до вразливого скрипту на основі PHP, який використовує типові нестрогі порівняння з оператором ==. Порівняння будь-якого рядка з TRUE або 0 за допомогою нього (за замовчуванням) дасть результат TRUE. Тож достатньо просто включити в запит на вхід у форматі JSON логічне значення (boolean) TRUE, щоб обійти автентифікацію.
Використання суворих порівнянь з оператором === або (ще краще) спеціальної функції порівняння зазвичай достатньо, щоб уникнути цього класу вразливостей. Але у великих програмних проєктах навіть такі, здавалося б, тривіальні помилки іноді можуть потрапити у продакшн.
Підводні камені контролю через каталоги
Ще однією поганою практикою, яка може призвести до атак обходу автентифікації та авторизації, є впровадження контролю доступу шляхом перевірки каталогу. Наприклад, програма може перевірити, чи має користувач право доступу до панелі адміністратора, просто порівнюючи каталог, запитуваний користувачем, з тим, що веде до панелі адміністратора. Без очищення вхідних даних можливо обійти автентифікацію та авторизацію, вставивши рядки (strings) обходу каталогу, щоб запросити той, що виглядає інакше (тобто не блокується), але зрештою веде до тієї ж URL-адреси панелі адміністратора.
Покладаючись на порівняння каталогів, можна отримати аналогічні вразливості через невідповідності в обробці URL на різних серверах. Наприклад, проксі-сервер може бути налаштований на обмеження доступу до певного каталогу, повертаючи код помилки для неавтентифікованих користувачів. Якщо зловмисник успішно виконує його обхід, проксі-сервер може бути обдурений, дозволивши доступ до каталогу, який виглядає інакше, але насправді веде до того ж самого ресурсу.
Невиправдана довіра до джерел авторизації та автентифікації
У складних архітектурах, розгортаннях та потоках даних рішення, пов’язані з автентифікацією та авторизацією, часто відходять на другий план. Це особливо актуально, наприклад, під час обробки запитів, отриманих через API, а не безпосередньо від користувачів. У додатках, зібраних із сотень мікросервісів, автентифікація та авторизація часто здійснюються лише через API у фронтенді, тому служби бекенду не мають уявлення, від кого цей запит. Якщо фронтенд має вразливість обходу каталогу, то бекенд виконає запит, потенційно розкриваючи конфіденційні дані.
Рішення, кому і чому код повинен довіряти, може мати далекосяжні наслідки. Один реальний недолік (давно виправлений) походить з 2017 року, коли вебсайт Uber виявився вразливим до викрадення облікового запису через захоплення піддомену. Дослідник безпеки Arne Swinnen помітив, що один із субдоменів Uber насправді вказував на інший домен, який він зміг зайняти. Процес автентифікації включав встановлення токена сесії, дійсного для всіх піддоменів Uber, включаючи той, на який претендував спеціаліст. Перенаправляючи користувачів на цей домен, він міг би зчитувати токени сесії та перехоплювати облікові записи. І все це завдяки довірі до автентифікації на рівні домену.
Відсутність контролю доступу на рівні функцій
Цей клас охоплює збої у перевірці того, чи користувач має право використовувати певну функцію. У кейсі вразливості в Maian Support Helpdesk, юзери могли викликати деякі API-інтерфейси, які не були видимі в інтерфейсі користувача, але все ще були доступні, включаючи деякі операції адміністратора. Без систематичного контролю доступу на рівні функцій такі упущення можуть легко дозволити зловмисникам отримати несанкціонований доступ.
Реалізація контролю доступу може бути особливо складною для GraphQL API, де існує багато способів доступу до одних і тих самих даних через різні запити. В ідеалі, кожен запит повинен повертати лише ті дані, до яких поточний користувач має право доступу. Будь-яка помилка на цьому етапі може дозволити зловмисникам отримати конфіденційну інформацію. Це особливо актуально, наприклад, під час додавання шару GraphQL до наявного REST API.
Неналежне управління токенами
На рівні HTTP-запитів контроль доступу залежить від безпечного створення правильних токенів доступу та їх надсилання до системи у потрібний час. Щоразу, коли зловмисникам вдається отримати дійсний токен доступу (наприклад, cookie сесії), є ризик перехоплення сесії. Загроза крадіжки токенів на стороні клієнта особливо висока у складних процесах систем єдиного входу (SSO), де неправильні конфігурації можуть дозволити зловмисникам перехоплювати токени доступу через перенаправлення або зчитувати їх із журналів сервера.
Токени скидання пароля – це ще один критичний механізм безпеки, схильний до неправильного управління та зловживань. Наприклад, програма може розкрити API-інтерфейс для створення токенів скидання пароля. Будь-яка вразливість, яка дозволяє зловмисникам викликати цей API, також може дозволити їм скидати паролі для відомих облікових записів користувачів, що призведе до захоплення акаунту. Такі недоліки можуть бути спричинені плутаниною щодо авторизації у вторинних контекстах або просто припущенням, що оскільки API-інтерфейс є приватним, його не можуть викликати неавторизовані користувачі.
Найкращі практики для впровадження автентифікації та авторизації
В OWASP Top 10 за 2021 рік порушення контролю доступу займає перше місце серед проблем безпеки вебзастосунків. Забезпечення надійного доступу вимагає ретельного планування, правильного написання коду та постійної перевірки.
Рекомендації:
- Включати питання щодо авторизації та автентифікації вже на етапах планування та дизайну ПЗ.
- Реалізовувати контроль доступу на рівні застосунку, а не тільки сервера.
- Дотримуватися практик написання безпечного коду, регулярно проводити його перевірку.
- Коли можливо, використовувати перевірені бібліотеки для автентифікації та авторизації замість створення власних рішень.
- Перевіряти контроль доступу на всіх етапах розробки, включаючи продакшн.
- Контролювати сторонню інфраструктуру, яка може бути використана для обходу механізмів автентифікації та авторизації.







