Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що таке BOLA (IDOR) і чому це найпоширеніша вразливість API?

BOLA (Broken Object Level Authorization, раніше IDOR - Insecure Direct Object Reference) - API перевіряє, що користувач автентифікований, але не перевіряє, чи має він доступ саме до цього об'єкта.

// вразливо: будь-який автентифікований користувач отримає будь-яке замовлення
Route::get('/api/orders/{order}', fn (Order $order) => new OrderResource($order))
    ->middleware('auth:sanctum');

Зловмисник змінює /api/orders/1041 на /api/orders/1040 - і бачить чуже замовлення. Ідентифікатори в API на виду, перебрати їх - справа скрипта.

Чому це вразливість №1 у OWASP API Top 10:

  • у кожному ендпойнті з ідентифікатором треба окремо не забути перевірку;
  • автоматичні сканери її погано знаходять - технічно запит коректний;
  • тести зазвичай перевіряють «власник бачить своє», а не «чужий не бачить».

Захист у Laravel:

1. Політики:

public function show(Order $order): OrderResource
{
    $this->authorize('view', $order);   // OrderPolicy::view
    return new OrderResource($order);
}

// або на маршруті
->can('view', 'order');

2. Пошук через власника - чужий запис просто не знайдеться:

$order = $request->user()->orders()->findOrFail($id);

3. Вкладені маршрути з обмеженням: scopeBindings() - дочірній запис має належати батьківському.

4. Списки - теж об'єкти: GET /api/orders?user_id=5 не повинен повертати замовлення іншого користувача. Фільтр за власником - на сервері, а не з параметра.

Чого не робити:

  • покладатися на непередбачувані ID (UUID замість автоінкременту). UUID ускладнює перебір, але не замінює перевірку: ідентифікатор може потрапити в URL, лог, лист;
  • перевіряти лише в інтерфейсі (прихована кнопка) - API викликають напряму;
  • довіряти ідентифікатору з тіла запиту ("owner_id": 5) - власника визначають з автентифікації.

Тест на кожен ендпойнт з ідентифікатором:

it('forbids viewing another user\'s order', function () {
    $order = Order::factory()->create();
    Sanctum::actingAs(User::factory()->create());

    $this->getJson("/api/orders/{$order->id}")->assertForbidden();
});

Відповідь 403 чи 404: 404 не підтверджує, що об'єкт існує, - для чутливих даних це краще.

Докладніше в документації: OWASP API1:2023 - BOLA

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання