← Wszystkie artykuły

Jak zabezpieczyć REST API: praktyczna checklista

Burncode Team 4 minuty czytania

API to często najbardziej wystawiona na zewnątrz część nowoczesnej aplikacji – z definicji ma przyjmować żądania ze świata zewnętrznego, a więc jest też najkrótszą drogą atakującego do waszych danych i logiki biznesowej. Porządne zabezpieczenie API to nie jedna funkcja, tylko lista odrębnych zagadnień, z których każde warto świadomie przejść.

Uwierzytelnianie: kto wysyła żądanie

Każde żądanie do chronionego endpointu musi dać się wiarygodnie przypisać konkretnemu nadawcy. Sprawdzone podejścia to m.in. klucze API w komunikacji między usługami oraz uwierzytelnianie oparte na tokenach (np. OAuth 2.0 lub JWT) w aplikacjach dla użytkowników. Sam mechanizm ma mniejsze znaczenie niż dopilnowanie podstaw: tokeny powinny wygasać, być przesyłane wyłącznie szyfrowanymi połączeniami i nigdy nie pojawiać się w adresie URL, bo stamtąd znacznie łatwiej trafiają do jakichś niezabezpieczonych logów.

Autoryzacja: co wolno temu, kto pyta

Uwierzytelnianie odpowiada na pytanie „kim jesteś?”. Autoryzacja – na pytanie „co wolno ci zrobić?”. To osobna kontrola, która musi się odbywać przy każdym żądaniu, a nie tylko raz, przy logowaniu. Bardzo częsty i kosztowny błąd: API poprawnie sprawdza, czy żądanie ma ważny token, ale nigdy nie weryfikuje, czy żądany zasób faktycznie należy do tego użytkownika. Właśnie w ten sposób jeden użytkownik może oglądać lub edytować dane innego, zmieniając jedynie identyfikator w żądaniu. To odmiana błędnej kontroli dostępu (broken access control) – jednego z najczęstszych problemów wykrywanych w rzeczywistych audytach bezpieczeństwa.

Limity żądań: ochrona przed nadużyciami i przeciążeniem

Bez limitowania liczby żądań (rate limiting) pojedynczy klient – złośliwy albo po prostu źle skonfigurowany – może zasypać wasze API żądaniami, czy to po to, by metodą brute force złamać np. endpoint logowania, czy po prostu przeciążyć infrastrukturę. W praktyce oznacza to rozsądne limity na użytkownika lub klucz API, czytelną odpowiedź, gdy klient przekroczy limit, oraz ostrzejsze limity dla wrażliwych endpointów, takich jak logowanie i reset hasła, niż dla zwykłych żądań odczytu.

Walidacja danych wejściowych: nie ufajcie niczemu, co przychodzi

Każde pole w każdym żądaniu powinno zostać sprawdzone pod kątem tego, czego faktycznie się spodziewacie – typu, długości, formatu, dopuszczalnego zakresu – zanim zostanie użyte gdziekolwiek w logice aplikacji. To ta sama zasada, która chroni przed SQL injection, tyle że ma znacznie szersze zastosowanie: błędne lub nieoczekiwane dane wejściowe stoją za dużą częścią rzeczywistych podatności aplikacji, i to daleko poza samymi zapytaniami do bazy danych.

Bezpieczeństwo transmisji: szyfrujcie wszystko, bez wyjątków

Każde żądanie i każda odpowiedź powinny przechodzić przez HTTPS, bez żadnej nieszyfrowanej alternatywy – nawet w przypadku endpointów, które wydają się mało ryzykowne. Nowoczesne narzędzia (np. Let's Encrypt) sprawiają, że poprawna konfiguracja jest niemal darmowa, więc rzadko istnieje dobre usprawiedliwienie, by gdziekolwiek w API z tego zrezygnować.

Rozsądne komunikaty o błędach

Szczegółowe komunikaty o błędach są naprawdę pomocne w trakcie developmentu i naprawdę niebezpieczne na produkcji. Błąd, który ujawnia wewnętrzne ścieżki plików, wersję bazy danych czy pełny stack trace, daje atakującemu fory w szukaniu prawdziwej słabości. Odpowiedzi o błędach na produkcji powinny być na tyle informacyjne, by dało się z nich korzystać – i ani trochę bardziej.

Logowanie i monitoring

Potrzebujecie rzetelnego zapisu, kto, do czego i kiedy miał dostęp – nie po to, by cokolwiek spowalniać, ale po to, by w razie problemu mieć realny ślad do przeanalizowania, a nie bezradne wzruszenie ramion. Wychwytywanie nietypowych wzorców, na przykład nagłego, wyjątkowo dużego wolumenu żądań z jednego konta, pozwala wcześnie wykryć trwający atak, zanim przerodzi się w poważny incydent.

Checklista, przez którą warto przepuścić własne API

  • Czy każdy endpoint wymaga uwierzytelnienia – poza tymi, które celowo mają być publiczne?
  • Czy każde żądanie sprawdza, że użytkownik ma uprawnienia do tego konkretnego zasobu, a nie tylko, że jest zalogowany?
  • Czy działają limity żądań, zwłaszcza dla logowania, resetu hasła i innych wrażliwych endpointów?
  • Czy wszystkie dane wejściowe są walidowane przed użyciem, a nie tylko te, które wydawały się oczywiście ryzykowne?
  • Czy HTTPS jest wymuszony wszędzie, bez wyjątków?
  • Czy odpowiedzi o błędach na produkcji nie ujawniają szczegółów wewnętrznej implementacji?
  • Czy logów jest wystarczająco dużo, by po fakcie faktycznie zbadać incydent?

Staranne przejście przez tę listę – endpoint po endpoincie, a nie tylko w teorii – to właśnie praktyczny przegląd bezpieczeństwa aplikacji, który Burncode przeprowadza dla klientów, obok utwardzania infrastruktury i przygotowania do prawdziwego audytu zgodności.