# Zabezpieczanie API REST w PHP

> Zabezpieczanie API REST w PHP: uwierzytelnianie, kontrola dla każdego obiektu, JWT, limity rozmiaru i typu, komunikaty o błędach i ograniczanie liczby żądań.

Źródło: https://phpsos.de/pl/blog/rest-api-php-absichern/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Dla bezpieczeństwa API w PHP liczy się przede wszystkim pięć punktów: tylko HTTPS, uwierzytelnianie na każdym niepublicznym punkcie końcowym, kontrola uprawnień dla każdego pojedynczego obiektu, ścisłe granice dla metody, typu zawartości i rozmiaru żądania oraz zwięzłe komunikaty o błędach bez szczegółów wewnętrznych. Dochodzą ograniczanie liczby żądań i dziennik zdarzeń istotnych dla bezpieczeństwa. Przeciw lukom w samym interpreterze PHP, takim jak PHP2Shell, to nie pomaga; potrzebna jest do tego aktualizacja PHP.

## Interfejs za stroną internetową

Wiele firm sprawdziło swoje strony w tygodniu po 21.10.2026. Interfejsy za nimi rzadziej znajdowały się na liście. A właśnie tam przebiegają wrażliwe procesy: aplikacja portalu klienta pobiera faktury, system zarządzania towarem zapisuje stany magazynowe w sklepie, partner zgłasza zlecenia przez webhook. Często te API budowano szybko, do jednego celu, a potem nigdy więcej na nie nie patrzono.

API nie ma interfejsu, który uwidacznia błędy. Brakująca kontrola uprawnień nie rzuca się nikomu w oczy na co dzień, dopóki wszyscy klienci pytają tylko o to, o co powinni. Atakujący próbuje natomiast dokładnie tego, co nie jest przewidziane.

Pierwszym krokiem jest więc inwentaryzacja. Jakie punkty końcowe w ogóle istnieją? Często znajdują się stare wersje, takie jak `/api/v1/`, które po przejściu na `/v2/` nigdy nie zostały wyłączone, punkty testowe z etapu programowania albo publicznie dostępny opis interfejsu, wymieniający funkcje wewnętrzne. Każdy punkt końcowy, który nie jest już potrzebny, należy wyłączyć. Każdy, który zostaje, potrzebuje osoby odpowiedzialnej.

## Bezpieczeństwo API w PHP: zasady podstawowe

Ściągawka OWASP REST Security podsumowuje sprawdzone zasady. Dla projektów PHP można je przełożyć na krótką listę:

1. **Tylko HTTPS.** Tokeny i dane dostępowe nigdy nie mogą być przesyłane bez szyfrowania.
2. **Każdy punkt końcowy sprawdza sam.** Uwierzytelnianie może odbywać się centralnie, decyzja o dostępie zapada w punkcie końcowym.
3. **Uprawnienie dla każdego obiektu.** Nie tylko „jest zalogowany”, lecz „może dokładnie ten rekord”.
4. **Ustalić dozwolone metody.** Co nie jest wyraźnie dozwolone, jest odrzucane kodem 405.
5. **Sprawdzać typ zawartości i rozmiar.** Błędny typ daje 415, zbyt duże żądania 413.
6. **Walidować dane wejściowe.** Typ, długość, format i zakres wartości, po stronie serwera.
7. **Żadnych sekretów w adresach URL.** Tokeny i klucze należą do nagłówka, a nie do query stringu.
8. **Zwięzłe błędy.** Żadnych stack trace, ścieżek ani komunikatów SQL dla klienta.
9. **Ograniczanie liczby żądań.** Na zbyt wiele żądań odpowiada się kodem 429.
10. **Odgrodzić punkty administracyjne.** Niedostępne publicznie lub tylko z silnym logowaniem.

## Uprawnienie do obiektu: najczęstszy błąd

Przykład sprawia, że problem staje się namacalny. Punkt końcowy wydaje faktury pod adresem `/api/rechnungen/{id}`. Sprawdzane jest, czy istnieje ważny token. Nie jest sprawdzane, czy faktura należy do klienta posiadającego token. Kto zwiększy własny numer faktury o jeden, widzi fakturę sąsiada.

Rozwiązanie jest proste i mimo to musi zostać wdrożone w każdym miejscu: samo zapytanie ogranicza się do uprawnionego zakresu.

```php
<?php
// Dopuścić tylko metodę GET
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
    http_response_code(405);
    header('Allow: GET');
    exit;
}

$kundeId = $auth->kundeId();          // ze sprawdzonego tokenu
$id = filter_var($routeId, FILTER_VALIDATE_INT);
if ($id === false) {
    http_response_code(400);
    exit;
}

// Uprawnienie tkwi w zapytaniu: tylko własne faktury
$stmt = $pdo->prepare('SELECT nummer, betrag, datum FROM rechnungen WHERE id = ? AND kunde_id = ?');
$stmt->execute([$id, $kundeId]);
$rechnung = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$rechnung) {
    http_response_code(404);           // nie zdradzać, czy dany identyfikator istnieje
    exit;
}

header('Content-Type: application/json');
echo json_encode($rechnung, JSON_THROW_ON_ERROR);
```

Zapytanie z placeholderami chroni jednocześnie przed SQL injection, zob. [Zapobieganie SQL injection w PHP](https://phpsos.de/pl/ratgeber/sql-injection-php/). Jak PHP udostępnia dane żądania, takie jak metoda, nagłówki i ciało, wyjaśnia artykuł [Superglobals: $_GET, $_POST, $_FILES i inne](https://phpsos.de/pl/php/superglobals/).

## Prawidłowe sprawdzanie tokenów

Wiele API pracuje z JSON Web Tokens. Ściągawka OWASP podaje dla nich jasne zasady: tokeny muszą być podpisane, niepodpisane tokeny są odrzucane, a algorytm sprawdzania ustala się na serwerze, a nie przejmuje z tokenu. Wystawca, odbiorca i czas wygaśnięcia również należą do kontroli. Użyj do tego utrzymywanej biblioteki zamiast własnych implementacji.

Własne tokeny, na przykład dla webhooków lub linków jednorazowych, muszą pochodzić z kryptograficznie bezpiecznego generatora liczb losowych i być porównywane w stałym czasie. Jak to zrobić w PHP, pokazuje artykuł [Bezpieczne liczby losowe i tokeny w PHP](https://phpsos.de/pl/blog/sichere-tokens-php/).

> **Wskazówka:**
> Daj każdemu klientowi i każdemu partnerowi własny klucz z dokładnie takimi uprawnieniami, jakich potrzebuje. Wtedy wyciekły klucz można zablokować pojedynczo, nie przerywając wszystkich pozostałych połączeń.

## Ustalać granice: rozmiar, typ i tempo

API powinno przyjmować tylko to, czego oczekuje. Zaczyna się to od typu zawartości: punkt końcowy, który przetwarza JSON, odrzuca wszystko inne. Maksymalny rozmiar żądania ograniczasz na kilku poziomach, w serwerze WWW i w PHP przez `post_max_size`. Ta granica należy także do środków przejściowych, które php.net podał w sprawie PHP2Shell. Jak ją sensownie dobrać, opisuje artykuł [Rozsądne ograniczanie post_max_size i upload_max_filesize](https://phpsos.de/pl/blog/post-max-size-upload-limits/).

Ograniczanie liczby żądań chroni przed zgadywaniem identyfikatorów i przed przeciążeniem. Można je wdrożyć w serwerze WWW, w przedniej warstwie proxy lub w aplikacji. Ważne, aby granice obowiązywały dla każdego klucza lub użytkownika, a nie tylko dla każdego adresu IP.

W przypadku API wywoływanych bezpośrednio z przeglądarki dochodzi CORS, czyli reguły określające, które obce strony mogą wysyłać żądania. Ustawiaj te nagłówki tylko wtedy, gdy takie wywołania są naprawdę przewidziane, i wymieniaj dozwolone źródła pojedynczo, zamiast dopuszczać każde pochodzenie. Wieloznacznik dopuszczający wszystkie strony jest przy punktach końcowych z logowaniem prawie zawsze błędem.

Na koniec dziennik: nieudane logowania, odrzucone tokeny i odmowy dostępu należą do logu, same tokeny nie. Bez tych wpisów atak na API pozostaje niewidoczny.

## Jak konkretnie pomaga PHP SOS?

- Spisujemy wszystkie interfejsy Państwa systemów PHP, także zapomniane i wewnętrzne, i sprawdzamy, które są publicznie dostępne.
- Czytamy logikę uprawnień i celowo testujemy, czy cudze rekordy można pobrać.
- Ustalamy granice rozmiaru, typu i tempa w serwerze WWW i w PHP oraz uzgadniamy je z Państwa klientami.
- Dla kompleksowej kontroli z zewnątrz łączymy to z [audytem bezpieczeństwa i testem penetracyjnym](https://phpsos.de/pl/leistungen/sicherheitsaudit-penetrationstest/).

**Podsumowanie:** API jest tak bezpieczne jak jego najbardziej niedbały punkt końcowy. Kto sprawdza uprawnienia dla każdego obiektu, ustala jasne granice i utrzymuje błędy zwięzłe, zamyka najczęstsze luki na długo, zanim ktoś zacznie ich celowo szukać.


## Częste pytania

**Czy klucz API wystarczy jako ochrona?**  
Dla wrażliwych danych nie. Klucz API identyfikuje zwykle aplikację, a nie użytkownika, i łatwo go przekazać dalej. Ściągawka OWASP REST Security radzi, aby nie stosować kluczy API jako jedynej ochrony wrażliwych zasobów.

**Czym jest uprawnienie do obiektu i dlaczego tak często go brakuje?**  
Chodzi o kontrolę, czy zalogowany użytkownik może zobaczyć lub zmienić dokładnie ten rekord. Często jej brakuje, ponieważ programiści sprawdzają tylko, czy ktokolwiek jest zalogowany. Wtedy wystarczy zmienić identyfikator w adresie URL, aby pobrać cudze dane.

**Czy dobrze zabezpieczone API chroni przed PHP2Shell?**  
Nie. PHP2Shell tkwi w interpreterze PHP i działa w dotkniętych trybach pracy, zanim Państwa kod w ogóle się uruchomi. Pomaga na to wyłącznie aktualizacja PHP z restartem. Limity rozmiaru żądań są mimo to sensowne i należą także do środków przejściowych podanych przez php.net.

**Jakie kody statusu powinno zwracać API przy błędach bezpieczeństwa?**  
Typowe są 401 bez ważnego logowania, 403 przy braku uprawnień, 405 przy niedozwolonej metodzie, 413 przy zbyt dużym żądaniu, 415 przy błędnym typie zawartości i 429 przy zbyt wielu żądaniach. Sama odpowiedź pozostaje przy tym zwięzła i bez szczegółów wewnętrznych.

## Źródła

- [OWASP: REST Security Cheat Sheet (ściągawka o bezpieczeństwie REST)](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Podręcznik PHP](https://www.php.net/manual/de/)
- [php.net: komunikaty bezpieczeństwa](https://www.php.net/)
