Разделы портала

Онлайн-тренинги

.
Тестирование безопасности API – Некорректная авторизация на уровне объекта
15.08.2024 00:00

Автор: Баз Дейкстра (Bas Dijkstra)
Оригинал статьи
Перевод: Ольга Алифанова

В этой серии статей я обращусь к уязвимостям из списка топ-10 OWASP, посвященного безопасности API. В каждой статье я покажу вам, как экспериментировать с API, тестируя уязвимость, и обсужу свои выводы.

В качестве подопытных я буду использовать разные API. Все они демонстрационные – в реальной жизни и публичных приложениях они не используются. Следовательно, все обсуждаемые уязвимости абсолютно безвредны, если вообще не внедрены специально.

Вот весь список топ-10:

  1. Некорректная авторизация на уровне объекта (эта статья).
  2. Некорректная аутентификация.
  3. Авторизация на уровне свойств неработающего объекта.
  4. Неограниченное потребление ресурсов.
  5. Ошибка авторизации на уровне функций.
  6. Подделка запросов на стороне сервера.
  7. Неправильная конфигурация безопасности.
  8. Отсутствие защиты от автоматизированных угроз.
  9. Неправильное управление запасами.
  10. Небезопасное использование API.

Что такое «некорректная авторизация на уровне объекта»?

API подвержен некорректной авторизации на уровне объекта (вкратце BOLA), если пользователь может получить доступ к ресурсам, доступа к которым у него быть не должно.

Представим сценарий, при котором пользователь онлайн-банка может получить список своих счетов через некий безопасный раздел сайта. Скорее всего, когда пользователь запрашивает счета, сайт вызовет API для получения информации о счетах от бэкэнда, используя запрос вроде GET /customers/123/accounts, где 123 – ваш уникальный ID пользователя. Этот API-запрос, скорее всего, будет содержать токен, куки или нечто иное, уникально идентифицирующее и верифицирующее вас.

Один из примеров нарушения BOLA – это когда тот же пользователь с теми же авторизационными данными может получить данные других пользователей.

Тестирование на BOLA-уязвимость

Возьмем API для демо-приложения ParaBank. Допустим, я получил валидный токен авторизации для пользователя с IR 12212. Это большое допущение – в этом API токены даже не используются – но замнем это для ясности.

После авторизации мы можем получить список пользовательских счетов, используя HTTP GET к /customers/12212/accounts. Запрос вернет список счетов и информацию о них, выглядеть это будет как-то так:

[
    {
       "id": 12345,
       "customerId": 12212,
        "type": "CHECKING",
       "balance": -2300.00
    },
    {
        "id": 12456,
        "customerId": 12212,
        "type": "CHECKING",
        "balance": 10.45
    },
    {
        "id": 12567,
        "customerId": 12212,
        "type": "CHECKING",
        "balance": 100.00
    }
]

Помимо баланса счета 12345, тут все в порядке. Но ID пользователя выглядит довольно предсказуемо – как будто это просто число, увеличивающееся на 1 для каждого нового пользователя.

Что произойдет, если мы попробуем запросить список счетов для других пользовательских ID в примерно таком же диапазоне – скажем, от 10000 до 20000?

В первый раз, пробуя увеличить ID на 1 и выполнить HTTP GET к /customers/12213/accounts, мы получим ошибку HTTP 400 с сообщением «Невозможно найти пользователя #12213».

Вместо того, чтобы сообщить, что у меня нет прав на получение данных для пользователя 12213 (помните, наш токен валиден для пользователя 12212), мне говорят, что для пользователя 12213 нет данных. Это хорошо – не произойдет утечки потенциально уязвимой информации; скажем, о том, что пользователь 12213 вообще существует.

Однако выбор кода статуса 400 немного странен – я бы ожидал тут 404: с запросом-то все в порядке.

Но что произойдет, если мы наткнемся на ID, который действительно существует? В этом API есть еще один пользователь с ID 12323. Я знаю об этом наверняка, но даже если бы не знал, это легко выяснить – можно просто создать скрипт, выполняющий HTTP GET и перебирающий все значения от 10000 до 20000 в качестве ID.

Если выполнить запрос HTTP GET к /customers/12323/accounts с токеном для пользователя 12212, то ответ будет таким:

[
    {
        "id": 13455,
        "customerId": 12323,
        "type": "CHECKING",
        "balance": 2014.76
     }
]

Это яркий пример уязвимости BOLA: мы смогли узнать информацию о счетах пользователя 12323, даже будучи авторизованными как 12212. Много времени это не отняло!

Это не очень хорошо для всего API в целом: если мы можем увидеть чужие данные, то, скорее всего, сможем навредить и посерьезнее – например, перевести чужие деньги на свой счет.

И это действительно возможно! Хотите узнать, как – прочитайте статью Эдварда Лихтнера об изучении и взломе API ParaBank.

Что теперь?

BOLA не просто так идет в списке под номером 1: потенциальный ущерб тут огромен. Злоумышленники могут легко воспользоваться BOLA-уязвимостью и получить доступ к секретным данным.

Чтобы снизить риск BOLA-уязвимости, можно предпринять контрмеры:

  • Тестируйте! Как можно видеть, тестирование BOLA-нарушений не требует особых знаний, достаточно активной пользовательской сессии и креативного подхода.
  • Внедряйте правильные механизмы авторизации, привязанные к ролям или пользователям, а затем используйте их для проверки, авторизован ли пользователь для доступа к ресурсу каждый раз, когда он пробует его открыть.

Еще один слой безопасности – это внедрения ограничений скорости, чтобы люди не могли сканировать данные при помощи скриптов, или чтобы это было очень трудозатратно. Поговорим об этом позднее.

Как и другие меры предосторожности, ни одна из этих сама по себе не гарантирует защиту от дыр в безопасности, но использование нескольких одновременно снижает риск уязвимости. Этот подход называется «метод швейцарского сыра».

Примеры

Другие примеры BOLA-уязвимостей можно найти на странице OWASP: Broken Object Level Authorization.

Также множество примеров есть в разделах API Security Fundamentals и OWASP API Security Top 10 and Beyond API Sec University.

Обсудить в форуме