REST API — podmiana metody HTTP i co z tego wynika
REST API opiera się na prostej konwencji — metoda HTTP mówi co robimy z zasobem. GET czyta, POST tworzy, PUT nadpisuje, DELETE usuwa. Problem zaczyna się, gdy atakujący podmieni metodę w locie i zamieni odczyt w usunięcie.
Jak podmienić metodę?
Nagłówek X-HTTP-Method-Override
Wysyłasz POST, ale nagłówek mówi serwerowi, żeby traktował request jako inną metodę:
curl -X POST https://api.example.com/users/42 \
-H "X-HTTP-Method-Override: DELETE"
Serwer dostaje POST, ale aplikacja interpretuje to jako DELETE. Użytkownik 42 znika.
Warianty nagłówka — różne serwery czytają różne nazwy:
X-Method-Override: PUT
X-HTTP-Method: PATCH
Mechanizm powstał z praktycznych powodów — starsze przeglądarki i firewalle przepuszczały tylko GET i POST. Żeby wysłać DELETE z formularza HTML, trzeba było opakować go w POST z dodatkowym nagłówkiem.
Parametr w query stringu
POST /users/42?_method=DELETE
POST /users/42?method=PUT
Pole w formularzu HTML
<form method="POST" action="/users/42">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Usuń</button>
</form>
Bezpośrednia podmiana — proxy
Burp Suite, mitmproxy, Zap — przechwytują request i pozwalają zmienić metodę przed wysłaniem do serwera:
GET /api/users/42 HTTP/1.1
Zmiana na:
DELETE /api/users/42 HTTP/1.1
Skrypt mitmproxy do automatycznej podmiany:
from mitmproxy import http
def request(flow: http.HTTPFlow):
if flow.request.path.startswith("/api/users"):
flow.request.method = "DELETE"
Konsekwencje
Ominięcie WAF
Typowy scenariusz — WAF filtruje requesty po metodzie HTTP:
# Reguła WAF: blokuj DELETE na /api/users/*
if method == "DELETE" and path matches "/api/users/*":
block()
Atakujący wysyła:
curl -X POST https://api.example.com/api/users/42 \
-H "X-HTTP-Method-Override: DELETE"
WAF widzi POST — przepuszcza. Aplikacja widzi DELETE — usuwa użytkownika.
Ominięcie CORS
Przeglądarka wysyła preflight (OPTIONS) tylko dla metod PUT, DELETE, PATCH. GET i POST przechodzą bez preflightu przy prostych nagłówkach.
POST z X-HTTP-Method-Override: DELETE — przeglądarka nie wyśle preflightu, bo POST jest “bezpieczny”. Serwer wykona DELETE.
Obejście rate limitingu
Rate limiter liczy requesty per metoda:
GET /api/data — limit 100/min
POST /api/data — limit 10/min
GET z X-HTTP-Method-Override: POST — rate limiter widzi GET (wysoki limit), aplikacja przetwarza POST.
Cache poisoning
Reverse proxy (Varnish, CDN) cache’uje odpowiedzi na GET. Atakujący wysyła:
curl -X GET https://api.example.com/users/42 \
-H "X-HTTP-Method-Override: DELETE"
Proxy cache’uje to jako GET, backend wykonuje DELETE. Kolejni użytkownicy dostają cache’owaną odpowiedź na request, który usunął zasób.
Zmiana GET w POST
curl -X GET "https://api.example.com/admin/reset-db" \
-H "X-HTTP-Method-Override: POST"
Jeśli /admin/reset-db reaguje na POST — GET z override wykona tę akcję.
Jak się bronić?
Najprościej — wyłączyć method override. Nowoczesne przeglądarki i klienty HTTP obsługują wszystkie metody, więc obejście przez POST nie jest już potrzebne.
Jeśli override musi zostać — dwie zasady:
- pozwalaj na override tylko z POST (nigdy z GET — GET nie powinien mieć side effectów)
- nie polegaj na metodzie HTTP w kontroli dostępu — sprawdzaj uprawnienia per akcja, nie per metoda
Na reverse proxy warto usuwać nagłówki override zanim trafią do backendu:
proxy_set_header X-HTTP-Method-Override "";
proxy_set_header X-Method-Override "";
proxy_set_header X-HTTP-Method "";