Bezpieczeństwo strony internetowej: 6 warstw ochrony (2026)
Kluczowy wniosek
Bezpieczeństwo strony internetowej buduje się warstwami: zabezpiecz domenę i DNS (registrar lock, DNSSEC, CAA), wymuś nowoczesne TLS z HSTS, wysyłaj restrykcyjny zestaw nagłówków bezpieczeństwa HTTP, hashuj hasła algorytmem Argon2id i chroń logowanie za pomocą MFA oraz limitów żądań, waliduj dane wejściowe i egzekwuj kontrolę dostępu po stronie serwera, przypinaj wersje zależności i regularnie je audytuj, zamknij każdy port, na którym niczego nie udostępniasz, i zbieraj logi wystarczające do wykrycia włamania. Każda praktyka poniżej zawiera dokładną konfigurację i darmowy sposób sprawdzenia, czy naprawdę działa — bo zabezpieczenie, którego nie przetestowano, to zabezpieczenie, którego nie masz.
Sprawdź teraz

Zacznij czytać
- Czym właściwie jest bezpieczeństwo strony internetowej
- Stos bezpieczeństwa strony: sześć warstw do ochrony
- Warstwa 1: zabezpiecz domenę i DNS
- Warstwa 2: HTTPS i TLS skonfigurowane porządnie
- Warstwa 3: nagłówki bezpieczeństwa HTTP
- Warstwa 4: uwierzytelnianie odporne na credential stuffing
- Sesje, ciasteczka i CSRF
- Injection i XSS: waliduj dane wejściowe, koduj dane wyjściowe
- Broken Access Control: ryzyko numer jeden
- Warstwa 5: zależności i łańcuch dostaw oprogramowania
- Warstwa 6: hardening serwera (porty, poprawki, sekrety, kopie zapasowe)
- Uwierzytelnianie poczty: SPF, DKIM i DMARC
- Loguj, monitoruj i planuj na wypadek włamania
- Testuj: skanery, testy penetracyjne i ciągła weryfikacja
- Lista kontrolna bezpieczeństwa strony internetowej
- Jak to się ma do OWASP Top 10:2025
- Bezpieczeństwo strony internetowej — najczęstsze pytania
Czym właściwie jest bezpieczeństwo strony internetowej
Bezpieczeństwo strony internetowej to w praktyce zestaw zabezpieczeń, które chronią stronę lub aplikację webową przed przejęciem, podmianą treści, wykorzystaniem jej do atakowania własnych użytkowników albo cichym wyciekiem danych. Nie jest to jeden produkt ani jedno ustawienie. To cały stos decyzji, który zaczyna się u rejestratora domeny, a dalej obejmuje DNS, TLS, nagłówki HTTP wysyłane przez serwer, kod obsługujący logowanie i dane wejściowe, zewnętrzne pakiety, na których budujesz aplikację, sam serwer, a na końcu logi, które powiedzą Ci, że coś poszło nie tak.
Warto myśleć warstwami, bo tak myślą atakujący. Według raportu Verizon 2026 Data Breach Investigations Report, obejmującego ponad 22 000 naruszeń od listopada 2024 do października 2025, 31% naruszeń zaczęło się od wykorzystanej luki w oprogramowaniu; rok wcześniej było to 20%, a po raz pierwszy wyprzedziło to skradzione dane logowania (13%), przy niezmiennym udziale phishingu na poziomie 16%. Ransomware pojawił się w 48% naruszeń, wobec 44% rok wcześniej. Wystarczy jedna brakująca łatka, wyciekły klucz API albo panel admina bez limitu żądań. Żadna z zasad w tym przewodniku nie jest egzotyczna; włamania dotykają zwykle tych stron, które pominęły podstawy na jednej warstwie, szlifując inną.
Przewodnik jest ułożony od zewnątrz do środka. Przy każdej zasadzie dowiesz się, dlaczego jest ważna, co dokładnie skonfigurować i jak to sprawdzić poleceniem albo darmowym narzędziem, takim jak Checker nagłówków HTTP czy Sprawdzanie Certyfikatu SSL, bo ustawienie, które według ciebie działa, a którego nigdy nie sprawdziłeś, niczego nie chroni.
Sprawdź nagłówki bezpieczeństwa strony
Stos bezpieczeństwa strony: sześć warstw do ochrony
Każdy atak na stronę internetową trafia w jedną z sześciu warstw. Poniższa tabela to mapa reszty przewodnika: co znajduje się na każdej warstwie, jak zwykle jest atakowane i które darmowe narzędzie potwierdzi, że Twoja ochrona faktycznie działa.
| Warstwa | Co robią tu atakujący | Kluczowe praktyki | Jak sprawdzić |
|---|---|---|---|
| 1. Domena i DNS | Przejmują domenę, zmieniają serwery nazw, przejmują porzucone subdomeny, uzyskują nieuprawnione certyfikaty | Registrar lock, MFA, DNSSEC, CAA, audyt nieaktualnych rekordów | Wyszukiwanie WHOIS, Kontrola kondycji DNS, Wyszukiwarka Subdomen |
| 2. Transport (TLS) | Wymuszają powrót do HTTP, usuwają szyfrowanie, wykorzystują stare szyfry i wygasłe certyfikaty | TLS 1.2+, HSTS (preload opcjonalnie), automatyczne odnawianie | Sprawdzanie Certyfikatu SSL |
| 3. Nagłówki HTTP | Wstrzykują skrypty (XSS), osadzają stronę w ramce do clickjackingu, wykorzystują zgadywanie typów treści, wyciągają adresy z nagłówka Referer | CSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | Checker nagłówków HTTP |
| 4. Aplikacja | Credential stuffing, injection, błędy kontroli dostępu, CSRF, niebezpieczne przesyłanie plików | Argon2id + MFA + limity żądań, zapytania parametryzowane, autoryzacja po stronie serwera, ciasteczka SameSite | Przegląd kodu, ZAP, Test Siły Hasła |
| 5. Zależności | Zatrute pakiety, znane CVE w bibliotekach, przejęte potoki CI | Lockfile, audyty, przypięte wersje, SBOM, tokeny z minimalnymi uprawnieniami | npm audit, Dependabot, Trivy |
| 6. Serwer i utrzymanie | Otwarte porty, domyślne hasła, brak poprawek, brak kopii zapasowych, brak logów | Firewall, SSH tylko z kluczami, regularne łatanie, kopie zapasowe 3-2-1, centralne gromadzenie logów | Sprawdzanie Portów, Sprawdzanie Czarnej Listy IP |
Pracuj od góry do dołu. Warstwy 1–3 to konfiguracja, którą skończysz w jedno popołudnie, a chroni ona od razu każdą podstronę serwisu. Warstwy 4–6 to stałe nawyki, które muszą stać się częścią code review i procesu wdrożeń.
Warstwa 1: zabezpiecz domenę i DNS
Wszystko inne w tym przewodniku zakłada, że nadal kontrolujesz swoją domenę. Jeśli atakujący zaloguje się na Twoje konto u rejestratora albo zmieni serwery nazw, może skierować Twój ruch dokądkolwiek, uzyskać ważny certyfikat na Twoją domenę i czytać każdy e-mail wysłany do Ciebie — a kod Twojej aplikacji nawet się nie uruchomi. Dlatego bezpieczeństwo domeny i DNS to pierwsza z dobrych praktyk bezpieczeństwa stron i niemal w całości sprowadza się do konfiguracji.
Zacznij od wyszukiwania WHOIS dla własnej domeny i potwierdź trzy rzeczy: kody statusu zawierają clientTransferProhibited, data wygaśnięcia jest odległa o ponad rok, a rejestrator to firma, w której naprawdę masz konto. Zaskakująco często domena firmy wisi na koncie byłego podwykonawcy. Nasz przewodnik po WHOIS wyjaśnia każdy kod statusu, jaki zobaczysz.
Registrar lock, MFA i alerty o wygaśnięciu
Włącz registrar lock (nazywany też blokadą transferu), aby domeny nie dało się przenieść do innego rejestratora, dopóki jej wyraźnie nie odblokujesz, i włącz uwierzytelnianie wieloskładnikowe (MFA) na samym koncie u rejestratora. Konta u rejestratorów to ulubiony cel phishingu właśnie dlatego, że jedno logowanie kontroluje wszystko, co od niego zależy. Tam, gdzie rejestrator na to pozwala, używaj klucza sprzętowego lub aplikacji uwierzytelniającej zamiast SMS-ów.
Ustaw automatyczne odnawianie domeny z metodą płatności, która nie wygaśnie, i mimo to dodaj przypomnienie w kalendarzu na 60 dni przed datą wygaśnięcia. Domena, której ważność upłynęła, nie przepada w dniu wygaśnięcia, ale gdy skończy się okres odroczenia i okres wykupu (dla .com do około 80 dni), zostaje usunięta, a usługi drop-catch rejestrują ją w kilka sekund po zwolnieniu. Kupujący przejmuje twoją pocztę, twój ruch i wszystkie logowania OAuth, które ufają twojej domenie.
- Registry lock (ręczna blokada na poziomie rejestru, zdejmowana poza zwykłym panelem) jest warta dodatkowej opłaty w przypadku domeny, od której zależy biznes; uniemożliwia zmianę serwerów nazw nawet z przejętego konta u rejestratora.
- Rozdziel role. Osoba, która płaci za domenę, konto, na którym domena jest zarejestrowana, i dostawca DNS powinny być udokumentowane i nie mogą być powiązane ze skrzynką pocztową jednego pracownika.
- Włącz ochronę prywatności WHOIS, aby Twoje dane kontaktowe nie stały się mapą dla phisherów, i podaj na koncie monitorowany adres funkcyjny, np.
domains@.
Podpisz strefę za pomocą DNSSEC
DNSSEC podpisuje twoją strefę DNS, dzięki czemu resolver może wykryć sfałszowane odpowiedzi. Bez niego atakujący, który potrafi zatruć pamięć podręczną resolvera, może skierować twoich odwiedzających na fałszywy serwer, a w przeglądarce nadal zobaczą twoją domenę. Większość zarządzanych dostawców DNS (Cloudflare, Route 53, Google Cloud DNS i wielu rejestratorów) włącza go jednym przełącznikiem; jedyny ręczny krok to opublikowanie rekordu DS u rejestratora. Sprawdź to poleceniem dig albo za pomocą kontroli kondycji DNS, która sprawdza rekord DS i podpisy:
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==
dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9Ogranicz wystawianie certyfikatów rekordem CAA
Rekord CAA (RFC 8659) informuje urzędy certyfikacji (CA), które z nich mogą wystawiać certyfikaty dla Twojej domeny. Każdy publiczny CA musi go sprawdzić przed wystawieniem certyfikatu, więc rekord CAA zamyka drogę atakującemu, który oszukał walidację domeny w innym CA. Trzy rekordy obejmują typowe przypadki: kto może wystawiać certyfikaty, kto może wystawiać certyfikaty wildcard i dokąd zgłaszać odrzucone żądania:
yourdomain.com. CAA 0 issue "letsencrypt.org"
yourdomain.com. CAA 0 issuewild ";"
yourdomain.com. CAA 0 iodef "mailto:security@yourdomain.com"Audyt nieaktualnych rekordów: przejęcie subdomeny
Przejęcie subdomeny (subdomain takeover) ma miejsce, gdy rekord DNS nadal wskazuje usługę, której już nie używasz: CNAME do usuniętej strony GitHub Pages, aplikacji Azure, kubełka S3 albo nazwy hosta dostawcy SaaS. Każdy może zarejestrować porzucony cel, a potem serwować treści pod old-app.yourdomain.com w twoim imieniu, i to z ważnym certyfikatem. To regularne znalezisko w programach bug bounty, bo nikt nie pamięta, że taki rekord istnieje.
Przepuść domenę przez Wyszukiwarkę Subdomen: przeszukuje ona dwa serwisy logów Certificate Transparency, Cert Spotter (aktualne certyfikaty) i crt.sh (wszystkie certyfikaty od 2013 roku), sprawdza 1000 popularnych nazw, rozwiązuje każdą na żywo, oznacza wiszące rekordy CNAME i pokazuje, jaki host lub CDN obsługuje każdą z nich. Usuń każdy rekord, którego cel zwraca NXDOMAIN albo stronę dostawcy „no such app”; pojedynczą nazwę potwierdzi Wyszukiwanie DNS. Powtarzaj co kwartał i uczyń usunięcie rekordu DNS częścią wygaszania każdej usługi.
Certificate Transparency to także Twój system wczesnego ostrzegania: Cert Spotter i monitoring CT w Cloudflare mogą wysłać Ci e-mail za każdym razem, gdy jakikolwiek CA wystawi certyfikat dla Twojej domeny. Nieoczekiwany certyfikat bywa pierwszym widocznym sygnałem przejęcia DNS lub konta u rejestratora.
Warstwa 2: HTTPS i TLS skonfigurowane porządnie
HTTPS nie jest już dobrą praktyką, tylko punktem wyjścia: przeglądarki oznaczają zwykłe strony HTTP jako „Niezabezpieczone”. Google zapowiedział też, że od Chrome 154 (październik 2026) przeglądarka będzie pytać, zanim otworzy jakąkolwiek publiczną stronę przez zwykły HTTP (Google). Stronę bezpieczną od jedynie zaszyfrowanej nadal odróżniają: akceptowane wersje TLS, to, czy w ogóle da się do ciebie dotrzeć przez HTTP, i to, czy odnawianie jest na tyle zautomatyzowane, by przetrwać skracanie ważności certyfikatów, które ruszyło w marcu 2026.
TLS 1.2 jako minimum, TLS 1.3 jako preferowany
TLS 1.0 i 1.1 zostały formalnie wycofane przez RFC 8996 w 2021 roku i żadna aktualna przeglądarka ich nie negocjuje. Wyłącz je na serwerze, preferuj TLS 1.3 (który eliminuje wszystkie znane słabe szyfry i kończy handshake w jednym przejściu tam i z powrotem) i zostaw TLS 1.2 wyłącznie z zestawami szyfrów AEAD, takimi jak ECDHE-ECDSA-AES128-GCM-SHA256 lub ECDHE-RSA-CHACHA20-POLY1305.
Przy testach z zewnątrz liczą się dwie linie: wynegocjowany protokół oraz Verify return code: 0, który oznacza, że cały łańcuch certyfikatów przeszedł walidację. Brakujący certyfikat pośredni to częsta przyczyna zgłoszeń „działa w Chrome, nie działa w curl ani na Androidzie”; jak to naprawić, pokazuje nasz poradnik o łańcuchu certyfikatów SSL, a Sprawdzanie Certyfikatu SSL wprost zgłasza niekompletny łańcuch. Oto kontrola wykonana dla dnsrobot.net 27 października 2026, a potem test, czy serwer odrzuca TLS 1.1:
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
| grep -E 'Protocol|Cipher|Verify return'
# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)
# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
-cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'
# Refused, as it should be: ...tlsv1 alert protocol version...
# New, (NONE), Cipher is (NONE)
# Still accepted (fix it): New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
# (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)Listy szyfrów to miejsce, w którym skopiowane konfiguracje się starzeją. Zamiast pisać je ręcznie, wygeneruj aktualny zalecany blok serwera dla nginx, Apache, Caddy lub HAProxy w Mozilla SSL Configuration Generator i wybierz profil „Intermediate”, chyba że musisz obsługiwać bardzo stare klienty.
HSTS: przeglądarka już nigdy nie użyje HTTP
Samo przekierowanie z HTTP na HTTPS nie wystarczy. Pierwsze żądanie, jakie odwiedzający wysyła do http://yourdomain.com, wciąż wędruje otwartym tekstem, a atakujący w tej samej sieci może na nie odpowiedzieć, zanim zrobi to Twoje przekierowanie. HTTP Strict Transport Security (RFC 6797) rozwiązuje ten problem: gdy przeglądarka raz zobaczy ten nagłówek, każdy kolejny adres http:// Twojej domeny przepisuje na https://, zanim cokolwiek wyśle.
Ustaw max-age na co najmniej rok (31536000 sekund) i dodaj includeSubDomains, gdy każda subdomena obsługuje HTTPS. Dodanie domeny do listy preload na hstspreload.org, która wbudowuje domenę w Chrome, Firefoksa, Safari i Edge, jest opcjonalne: opiekunowie listy piszą teraz, że HSTS jest zalecany, a preload nie, bo Chrome i Safari i tak podnoszą nawigację do HTTPS, a opuszczenie listy trwa miesiącami. Sprawdź nagłówek w Sprawdzaniu Nagłówków HTTP, które ocenia HSTS testami Mozilla HTTP Observatory.
Strict-Transport-Security: max-age=31536000; includeSubDomainsCertyfikaty 47-dniowe: zautomatyzuj odnawianie już teraz
Głosowanie SC-081 organizacji CA/Browser Forum etapami skraca maksymalny okres ważności każdego publicznego certyfikatu TLS. Pierwsze cięcie weszło w życie 15 marca 2026 roku, więc każdy certyfikat kupiony lub odnowiony dziś jest już ograniczony do 200 dni, a do 2029 roku certyfikat trzeba będzie wymieniać mniej więcej co sześć tygodni:
| Data wejścia w życie | Maksymalna ważność certyfikatu | Ponowne użycie walidacji domeny |
|---|---|---|
| Przed 15 marca 2026 | 398 dni | 398 dni |
| 15 marca 2026 | 200 dni | 200 dni |
| 15 marca 2027 | 100 dni | 100 dni |
| 15 marca 2029 | 47 dni | 10 dni |
Ręczne odnawianie nie wytrzyma tego harmonogramu. Dobra praktyka to w pełni zautomatyzowane wystawianie certyfikatów przez ACME: Let's Encrypt lub Google Trust Services za pomocą certbota, acme.sh, Caddy albo automatycznych certyfikatów wbudowanych w Cloudflare, Vercel, Netlify i większość paneli hostingowych. Przetestuj ścieżkę odnawiania, zanim będzie potrzebna (certbot renew --dry-run w przypadku certbota); szukaj przede wszystkim rekordu CAA lub reguły firewalla dodanych od ostatniego odnowienia, które teraz blokują walidację. Niezależnie od narzędzia monitoruj datę wygaśnięcia także z zewnątrz: Sprawdzanie Certyfikatu SSL pokazuje liczbę pozostałych dni, a wygasły certyfikat zamienia każdą wizytę w pełnoekranowe ostrzeżenie przeglądarki.
Warstwa 3: nagłówki bezpieczeństwa HTTP
Nagłówki bezpieczeństwa to instrukcje, które serwer daje przeglądarce co do tego, co wolno, a czego nie wolno robić z twoimi stronami: jakie skrypty mogą działać, czy stronę można osadzać w ramce, czy przeglądarka może zgadywać typy treści i co ma mówić innym witrynom o tym, skąd przyszedł odwiedzający. Nic nie kosztują, działają na wszystkie strony naraz i blokują całe klasy ataków. To także warstwa, w której większość stron częściowo się myli, dlatego Checker nagłówków HTTP ocenia je testami Mozilla HTTP Observatory. Oto, co github.com wysłał 27 października 2026, skrócone do nagłówków bezpieczeństwa (jego script-src wymienia jeden host zasobów i skrót skryptu, bez 'unsafe-inline'):
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...Siedem nagłówków, które powinna wysyłać każda strona
To wartości, do których warto dążyć na typowej stronie. W ocenie Mozilla HTTP Observatory, której używa nasze Checker nagłówków HTTP, brak CSP kosztuje 25 punktów, brak HSTS lub ochrony przed osadzaniem w ramce po 20, a brak nosniff 5; Referrer-Policy i COOP dodają punkty bonusowe, jeśli wynik nadal wynosi co najmniej 90. Permissions-Policy nie jest punktowany (czytają go tylko przeglądarki oparte na Chromium), ale nadal warto go ustawić.
| Nagłówek | Zalecana wartość | Co blokuje |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Downgrade protokołu, kradzież ciasteczek przez HTTP |
Content-Security-Policy | script-src oparty na nonce z 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none' | Cross-site scripting (XSS), wstrzykiwanie danych, clickjacking |
X-Content-Type-Options | nosniff | MIME sniffing, który zamienia przesłany plik w wykonywalny skrypt |
Referrer-Policy | strict-origin-when-cross-origin | Wyciek pełnych adresów URL (tokenów, wyszukiwanych fraz) do stron trzecich |
Permissions-Policy | camera=(), microphone=(), geolocation=(), payment=() | Ciche korzystanie z potężnych API przeglądarki przez zewnętrzne skrypty |
X-Frame-Options | DENY (starszy zamiennik dla frame-ancestors) | Clickjacking w przeglądarkach bez CSP Level 2 |
Cross-Origin-Opener-Policy | same-origin | Ataki między oknami przez window.opener |
Content Security Policy bez psucia strony
Content Security Policy to najskuteczniejsza pojedyncza obrona przed XSS, bo blokuje wstrzyknięte skrypty nawet wtedy, gdy błąd umożliwiający wstrzyknięcie istnieje. Haczyk polega na tym, że restrykcyjna polityka psuje każdy skrypt inline i każdy zewnętrzny tag, o którym zapomniano. Nowoczesne podejście, zalecane przez Google i opisane w MDN, to polityka oparta na nonce: serwer generuje losowy nonce dla każdej odpowiedzi, dodaje go do każdego tagu script, który celowo renderuje, a przeglądarka odrzuca wszystko inne.
'strict-dynamic' sprawia, że taka polityka sprawdza się w praktyce: skrypt z nonce może ładować kolejne skrypty (analitykę, menedżery tagów, widżety) bez dodawania każdego z nich do listy dozwolonych, a tokeny https: i 'unsafe-inline' są ignorowane przez nowoczesne przeglądarki i służą jedynie jako fallback dla starych. Zacznij wdrożenie od Content-Security-Policy-Report-Only, obserwuj raporty o naruszeniach przez tydzień, a potem przełącz się na tryb egzekwowania. Frameworki takie jak Next.js, Rails i Django mają wbudowaną obsługę nonce; strony statyczne mogą zamiast tego użyć script-src opartego na hashach.
Content-Security-Policy:
script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
report-to csp-endpoint
<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>Polityka oparta na liście dozwolonych źródeł, np. script-src 'self' https://cdn.example.com, jest lepsza niż nic, ale każdy endpoint JSONP lub stara biblioteka na dozwolonym hoście może posłużyć do jej obejścia. Jeśli jeszcze nie możesz używać nonce, ustaw przynajmniej object-src 'none' i base-uri 'none', co od razu zamyka dwie popularne metody obejścia.
Clickjacking: frame-ancestors i X-Frame-Options
Clickjacking polega na niewidocznym załadowaniu Twojej strony wewnątrz strony atakującego i nakłonieniu odwiedzającego do kliknięcia przycisku, którego nie widzi. frame-ancestors 'none' w CSP (lub 'self', jeśli osadzasz własne strony) zapobiega temu we wszystkich aktualnych przeglądarkach, a X-Frame-Options: DENY chroni starsze. Jeśli celowo udostępniasz widżet do osadzania, zwolnij z tej reguły tylko jego ścieżkę i tylko dla originów, które go potrzebują; nasz przewodnik po X-Frame-Options omawia dokładne reguły serwera i błędy „refused to connect”, na które trafisz podczas testów.
nosniff, Referrer-Policy, Permissions-Policy i COOP
X-Content-Type-Options: nosniff nie pozwala przeglądarce ignorować nagłówka Content-Type i zgadywać typu treści — a właśnie takie zgadywanie zamienia przesłany przez użytkownika „obrazek” zawierający HTML w wykonywalną stronę. Referrer-Policy: strict-origin-when-cross-origin (domyślna wartość w aktualnych przeglądarkach, ale ustaw ją jawnie) wysyła innym witrynom tylko Twój origin, więc tokeny resetu hasła i wyszukiwane frazy w adresach URL pozostają prywatne. Permissions-Policy wyłącza funkcje przeglądarki, z których nie korzystasz, więc przejęty zewnętrzny skrypt nie włączy kamery ani nie odczyta lokalizacji. Cross-Origin-Opener-Policy: same-origin zrywa powiązanie window.opener ze stronami, które otwierasz, co blokuje całą klasę ataków między oknami.
Równie ważne są nagłówki do usunięcia: Server i X-Powered-By zdradzają skanerom luk dokładne wersje oprogramowania, a X-XSS-Protection jest przestarzały i w starych przeglądarkach może powodować błędy, więc ustaw go na 0 albo usuń. Wykrywanie CMS pokazuje, czego każdy może się dowiedzieć o twoim stosie i jego wersjach z samej strony.
Ustawiaj nagłówki raz, na brzegu (CDN, reverse proxy lub middleware frameworka), zamiast na każdej stronie osobno. W Next.js jest to plik proxy lub middleware; w nginx blok add_header w kontekście server; w Apache Header always set. Następnie po każdym wdrożeniu ponownie uruchom Checker nagłówków HTTP, bo nowa wersja frameworka lub ustawienie CDN może po cichu usunąć któryś z nich.
Warstwa 4: uwierzytelnianie odporne na credential stuffing
Atakujący rzadko zgadują hasła po jednym. Odtwarzają miliardy par e-mail–hasło, które wyciekły z innych serwisów (credential stuffing), a resztę wyłudzają phishingiem. Dobre praktyki uwierzytelniania mają więc trzy części: przechowuj hasła tak, aby wyciek bazy danych nie oznaczał wycieku haseł, spraw, aby samo skradzione hasło było bezużyteczne, i spowolnij ataki brute force na tyle, żeby przestały mieć znaczenie. OWASP umieszcza Authentication Failures (błędy uwierzytelniania) na pozycji A07 w OWASP Top 10:2025.
Hashuj hasła za pomocą Argon2id lub bcrypt
Nigdy nie przechowuj hasła ani jego szybkiego hasha. MD5, SHA-1, a nawet SHA-256 zaprojektowano z myślą o szybkości, więc wyciekłą tabelę takich hashy można testować z prędkością miliardów prób na sekundę na jednym GPU. Używaj wolnej, pamięciochłonnej funkcji hashującej przeznaczonej do haseł z unikalną solą dla każdego hasła. OWASP Password Storage Cheat Sheet zaleca, w kolejności:
- Argon2id z co najmniej 19 MiB pamięci, 2 iteracjami i stopniem równoległości 1 (lub 46 MiB przy 1 iteracji).
- scrypt z N = 2^17, r = 8, p = 1, gdy Argon2 jest niedostępny.
- bcrypt ze współczynnikiem pracy (work factor) 10 lub wyższym (pamiętaj o limicie 72 bajtów danych wejściowych; wstępne hashowanie dłuższych haseł wymaga ostrożności).
- PBKDF2-HMAC-SHA256 z 600 000 iteracji tylko tam, gdzie wymaga tego zgodność z FIPS.
// Node.js with the argon2 package
import argon2 from "argon2";
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 19456, // KiB = 19 MiB
timeCost: 2,
parallelism: 1,
});
// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);Dobierz koszt tak, by jeden hash liczył się mniej więcej 100 do 250 ms na twoim serwerze logowania. Prawdziwy użytkownik tego nie zauważy, ale każdy rdzeń procesora ograniczysz do garstki prób na sekundę, a nawet wydajną kartę graficzną do tysięcy zamiast miliardów. Przy każdym udanym logowaniu przeliczaj hash od nowa, gdy podnosisz parametry, żeby stare hashe same się aktualizowały.
Zasady dotyczące haseł, które naprawdę pomagają (NIST SP 800-63B)
Reguły złożoności, które większość stron wciąż wymusza (jedna wielka litera, jeden symbol, zmiana co 90 dni), prowadzą do przewidywalnych haseł w stylu Summer2026! i skłaniają ludzi do ich ponownego używania. Aktualne wytyczne NIST SP 800-63B zastępują je regułami, które mierzą to, co naprawdę ważne:
- Minimum 8 znaków, gdy wymagane jest również MFA, i co najmniej 15 znaków dla hasła używanego samodzielnie; dopuszczaj co najmniej 64 znaki.
- Żadnych reguł złożoności i żadnej wymuszonej okresowej zmiany; wymagaj zmiany hasła tylko wtedy, gdy istnieją dowody jego przejęcia.
- Sprawdzaj każde nowe hasło z listą haseł, które wyciekły (API zakresów Have I Been Pwned pozwala to zrobić bez wysyłania hasła) i odrzucaj te, które już wyciekły.
- Pozwalaj na wklejanie i menedżery haseł, akceptuj spacje i Unicode oraz podawaj wskazówki, które pomagają wybrać mocne hasło, zwłaszcza zaraz po odrzuceniu poprzedniego.
Nasz Test Siły Hasła pokazuje, czym te miary różnią się od starych reguł: szacuje, ile czasu zajmuje złamanie hasła w 8 nazwanych atakach, pokazuje wzorce, które je osłabiają, i sprawdza je z danymi z wycieków bez wysyłania hasła, co daje znacznie bardziej przydatną informację zwrotną niż czerwony komunikat „wymagany symbol”.
MFA i passkeys
Uwierzytelnianie wieloskładnikowe sprawia, że skradzione hasło prowadzi donikąd. Oferuj je wszystkim i wymagaj go od ról administracyjnych, finansowych i wsparcia. Uszereguj opcje według odporności na phishing: passkeys i klucze bezpieczeństwa FIDO2 nie dają się wyłudzić phishingiem, bo poświadczenie jest powiązane z Twoim prawdziwym originem; aplikacje uwierzytelniające (TOTP) są dobre; kody SMS są lepsze niż nic, ale można je przechwycić przez SIM swapping. Passkeys są obsługiwane we wszystkich aktualnych przeglądarkach i systemach operacyjnych i całkowicie eliminują hasło, a wraz z nim credential stuffing jako kategorię ataku.
Chroń ścieżkę odzyskiwania konta równie starannie jak logowanie: kody odzyskiwania przechowywane jako hashe, resety przez e-mail z jednorazowymi tokenami, które wygasają w ciągu 15 minut, i żadnych pytań pomocniczych.
Limitowanie żądań, blokady i ochrona przed botami
Stosuj rate limiting na endpointach logowania, rejestracji, resetu hasła i MFA — dla każdego adresu IP i dla każdego konta — i po przekroczeniu limitu zwracaj 429 Too Many Requests z nagłówkiem Retry-After (nasz przewodnik po błędzie HTTP 429 opisuje, jak powinni reagować klienci). Połącz to z rosnącym opóźnieniem lub tymczasową blokadą po powtarzających się nieudanych próbach na jednym koncie oraz z CAPTCHA lub wyzwaniem proof-of-work na endpointach narażonych na rozproszone ataki. Zapisuj w logach każde nieudane logowanie wraz ze źródłowym adresem IP, aby wzorzec ataku credential stuffing był widoczny w ciągu minut, a nie miesięcy.
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location = /api/login {
limit_req zone=login burst=4 nodelay;
limit_req_status 429;
proxy_pass http://app;
}Komunikaty o błędach dla „nieznanego użytkownika” i „błędnego hasła” muszą być identyczne, a czas odpowiedzi taki sam w obu przypadkach (hashuj fikcyjne hasło, gdy użytkownik nie istnieje). W przeciwnym razie formularz logowania staje się jednocześnie API do enumeracji użytkowników.
Sesje, ciasteczka i CSRF
Po zalogowaniu ciasteczko sesji jest użytkownikiem, więc zasługuje na taką samą ochronę jak hasło. Większość pracy wykonują trzy atrybuty ciasteczka i jeden prefiks nazwy:
Secureoznacza, że ciasteczko nigdy nie jest wysyłane przez zwykłe HTTP, więc nie da się go podsłuchać w publicznej sieci Wi-Fi.HttpOnlysprawia, że ciasteczko jest niewidoczne dla JavaScriptu, więc błąd XSS nie pozwoli go odczytać.SameSite=Lax(lubStrictdla paneli administracyjnych) sprawia, że ciasteczko nie jest dołączane do międzywitrynowych żądań POST, co neutralizuje większość ataków CSRF.- Prefiks
__Host-sprawia, że przeglądarka akceptuje ciasteczko tylko wtedy, gdy ma ono atrybutSecure,Path=/i nie ma atrybutuDomain, więc subdomena nie może go nadpisać.
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800Akcje zmieniające stan nigdy nie mogą być dostępne przez GET. Link w rodzaju /account/delete?id=42 może zostać wywołany przez tag <img> na dowolnej stronie odwiedzanej przez użytkownika, niezależnie od tego, jak dobre są flagi Twoich ciasteczek.
CSRF: druga linia obrony za SameSite
Cross-site request forgery (CSRF) nakłania zalogowaną przeglądarkę do wysłania z innej strony żądania, które zmienia stan w Twoim serwisie. Ciasteczka SameSite powstrzymują typowy przypadek, ale na każdym żądaniu innym niż GET utrzymuj drugą linię obrony: token anty-CSRF przypisany do sesji w ukrytym polu lub własnym nagłówku albo sprawdzenie, czy nagłówek Origin (lub Sec-Fetch-Site) odpowiada Twojemu originowi. Większość frameworków (Django, Rails, Laravel, server actions w Next.js) robi to domyślnie; błąd polega na wyłączeniu tej ochrony dla endpointu API, a potem wywoływaniu go z przeglądarki.
Identyfikatory sesji, rotacja i JWT
Generuj identyfikatory sesji z co najmniej 128 bitami losowości, zmieniaj identyfikator przy logowaniu i przy każdej zmianie uprawnień, aby udaremnić session fixation, wygaszaj sesje po okresie bezczynności i daj użytkownikom przycisk „wyloguj ze wszystkich urządzeń”, który unieważnia je po stronie serwera. Tokeny JWT niech będą krótkotrwałe (minuty, z refresh tokenem, który można odwołać); nigdy nie przechowuj ich w localStorage, gdzie może je odczytać dowolny skrypt, a wyciek klucza podpisującego traktuj jak pełne naruszenie bezpieczeństwa, bo każdy token, który ten klucz kiedykolwiek podpisał, można teraz podrobić.
Injection i XSS: waliduj dane wejściowe, koduj dane wyjściowe
Injection (A05:2025, wstrzykiwanie kodu) i cross-site scripting to ten sam błąd w różnych miejscach: dane od użytkownika trafiają do interpretera (SQL, powłoki, zapytania LDAP, strony HTML) tak, jakby były kodem. Rozwiązanie też jest wszędzie takie samo: oddzielaj dane od kodu i nigdy nie buduj polecenia przez sklejanie stringów.
Zapytania parametryzowane zamiast sklejania stringów
W przypadku SQL używaj prepared statements lub ORM, który je generuje; baza danych traktuje wtedy dane wejściowe jako wartość, która nigdy nie zmieni struktury zapytania. Ta sama zasada dotyczy poleceń powłoki (przekazuj tablicę argumentów, nigdy string), filtrów NoSQL (odrzucaj w danych od użytkownika obiekty operatorów, takie jak {"$gt": ""}) i ścieżek plików (rozwiąż ścieżkę i upewnij się, że pozostaje w docelowym katalogu).
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);
// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);
// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))Kodowanie danych wyjściowych powstrzymuje XSS
Do cross-site scriptingu dochodzi, gdy tekst kontrolowany przez użytkownika trafia na stronę bez zakodowania go odpowiednio do kontekstu, w którym się znajdzie. Nowoczesne silniki szablonów (React i JSX, Vue, Jinja2, Blade, ERB) domyślnie kodują dane; dziś XSS bierze się zwykle z furtek, które tę ochronę omijają: dangerouslySetInnerHTML, v-html, |safe, innerHTML oraz budowania adresów URL lub inline'owych handlerów zdarzeń z danych użytkownika. Koduj dane dokładnie pod dany kontekst, a rozbudowany HTML oczyszczaj specjalnie do tego stworzoną biblioteką, taką jak DOMPurify, a nie wyrażeniem regularnym.
| Gdzie trafiają dane | Jak kodować | Przykład |
|---|---|---|
| Treść HTML | Encje HTML | < zmienia się w <, a " w " |
| Atrybut HTML | Encje w atrybucie ujętym w cudzysłów | Zawsze ujmuj atrybut w cudzysłów; koduj " i ' |
| JavaScript | Nie wstrzykuj danych do treści skryptu; przekazuj je przez atrybuty data- lub blok JSON <script type="application/json"> | </script> wewnątrz stringa zamienia się w \u003c/script\u003e |
| Parametr URL | Kodowanie procentowe (percent-encoding) | encodeURIComponent(value) |
| Wartość CSS | Unikaj całkowicie; wybieraj nazwy klas z listy dozwolonych | Nigdy nie wstawiaj danych od użytkownika do style |
SSRF, przesyłanie plików i deserializacja
Server-side request forgery (SSRF): jeśli Twój serwer pobiera adres URL podany przez użytkownika (webhooki, proxy obrazów, podglądy linków), atakujący może skierować go na usługi wewnętrzne lub endpoint metadanych chmury 169.254.169.254 i odczytać poświadczenia. Najpierw rozwiąż nazwę hosta, odrzucaj zakresy prywatne i link-local, wyłącz przekierowania i umieść mechanizmy pobierające w segmencie sieci, z którego nie da się dotrzeć do niczego wewnętrznego.
Przesyłanie plików: sprawdzaj typ pliku na podstawie jego zawartości, a nie rozszerzenia czy nagłówka Content-Type wysłanego przez klienta; egzekwuj limit rozmiaru; przechowuj pliki poza katalogiem głównym serwera WWW lub w object storage pod losową nazwą, którą sam generujesz; a jeśli to możliwe, serwuj je z osobnego originu z nosniff i Content-Disposition: attachment. Nigdy nie pozwól, aby przesłany plik trafił tam, gdzie serwer WWW go wykona.
Deserializacja i mass assignment: nigdy nie deserializuj niezaufanych danych w formacie, który może tworzyć instancje dowolnych klas (natywna serializacja Javy, pickle w Pythonie, unserialize w PHP, YAML z niestandardowymi tagami); używaj JSON ze schematem. Wiąż treść żądania z jawną listą dozwolonych pól, aby użytkownik nie mógł wysłać POST-em "role": "admin" do modelu, który akurat ma taką kolumnę.
Broken Access Control: ryzyko numer jeden
Broken Access Control (błędy kontroli dostępu) zajmuje pierwsze miejsce w OWASP Top 10 od 2021 roku i utrzymuje je jako A01:2025. To nie pojedynczy błąd, lecz nawyk: przy każdym żądaniu sprawdza się, kim ktoś jest (uwierzytelnianie), ale zapomina się sprawdzić, do czego ma dostęp (autoryzacja). Klasyczna postać to insecure direct object reference (IDOR): GET /api/invoices/1042 działa dla właściciela faktury, ale też dla każdego, kto zmieni numer.
- Domyślnie odmawiaj. Każda trasa wymaga jawnej reguły przyznającej dostęp; brak reguły oznacza 403, a nie 200.
- Egzekwuj na serwerze, dla każdego obiektu. Ukrycie przycisku w interfejsie to nie kontrola dostępu. Każdy odczyt i zapis musi potwierdzać, że bieżący użytkownik jest właścicielem konkretnego rekordu lub ma do niego uprawnienia — również w endpointach zbiorczych, eksportach i zadaniach w tle.
- Używaj nieprzewidywalnych identyfikatorów tam, gdzie to pomaga (UUID), ale nigdy na nich nie polegaj: ukrycie to nie autoryzacja.
- Zablokuj CORS.
Access-Control-Allow-Origin: *z poświadczeniami albo odbijanie dowolnego nagłówkaOriginwysłanego w żądaniu oddaje Twoje API każdej stronie, którą odwiedza użytkownik. - Wyłącz listowanie katalogów, blokuj
.git,.env, kopie zapasowe i pliki konfiguracyjne na poziomie serwera WWW, a panele administracyjne trzymaj poza publicznym internetem albo za MFA i listą dozwolonych adresów IP. - Limituj i loguj błędy autoryzacji. Seria odpowiedzi 403 w jednej sesji oznacza trwający atak enumeracyjny.
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
if (!invoice || invoice.ownerId !== req.user.id) {
return res.status(404).end(); // 404, not 403: don't confirm the record exists
}
res.json(invoice);
});Warstwa 5: zależności i łańcuch dostaw oprogramowania
Większość kodu w typowej aplikacji webowej to kod, który pobrałeś, a nie napisałeś. Dlatego Software Supply Chain Failures debiutuje na pozycji A03 w OWASP Top 10 2025, a wykorzystanie luk wyprzedziło phishing i skradzione dane logowania w DBIR 2026. We wrześniu 2025 po udanym phishingu jednego opiekuna złośliwy kod kradnący kryptowaluty trafił do chalk, debug i 16 innych pakietów npm, które razem mają ponad dwa miliardy pobrań tygodniowo; każdy projekt, który w tym oknie zainstalował niezablokowaną wersję, pobrał go automatycznie.
- Commituj lockfile (
package-lock.json,yarn.lock,pnpm-lock.yaml,poetry.lock,go.sum) i w CI instaluj zależności przeznpm ci, aby buildy były powtarzalne, a nowe wydanie upstream nie mogło wślizgnąć się bez przeglądu. - Skanuj w sposób ciągły:
npm audit,pip-audit,bundler-audit, GitHub Dependabot lub Renovate do aktualizacji oraz skaner kontenerów, taki jak Trivy lub Grype, dla warstwy systemu operacyjnego. - Opóźniaj aktualizacje niezwiązane z bezpieczeństwem o kilka dni (
minimumReleaseAgew Renovate), aby zatrute wydanie zwykle zostało wycofane, zanim je wdrożysz — ale poprawki bezpieczeństwa stosuj natychmiast. - Przypinaj zewnętrzne akcje i skrypty w CI do SHA commita i używaj Subresource Integrity (
integrity="sha384-...") dla każdego skryptu ładowanego z publicznego CDN. - Dawaj CI minimalne uprawnienia: tokeny tylko do odczytu tam, gdzie to możliwe, krótkotrwałe poświadczenia OIDC zamiast długowiecznych sekretów i prawa do publikacji ograniczone do zadania wydającego release.
- Generuj SBOM (CycloneDX lub SPDX) podczas builda, aby po pojawieniu się kolejnego CVE klasy Log4Shell odpowiedzieć na pytanie „czy nas to dotyczy?” w kilka minut.
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high
# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4 <- can change underneath you
# uses: actions/checkout@<full-commit-sha> # v4.2.2
# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
integrity="sha384-<base64-hash>"
crossorigin="anonymous"></script>npm ci --ignore-scripts blokuje skrypty uruchamiane podczas instalacji, z których korzysta większość złośliwego oprogramowania w npm; następnie włącz skrypty ponownie tylko dla nielicznych pakietów, które naprawdę potrzebują kroku budowania.
Jeśli korzystasz z WordPressa lub innego CMS-a, te same zasady dotyczą wtyczek i motywów, od których zaczyna się większość włamań na CMS-y. Aktualizuj rdzeń i każdą wtyczkę, usuwaj te, których nie używasz, i sprawdź w Wykrywaniu CMS, czego skaner może się dowiedzieć o Twoich wersjach.
Warstwa 6: hardening serwera (porty, poprawki, sekrety, kopie zapasowe)
Warstwa aplikacji nie ma znaczenia, jeśli serwer pod nią przyjmuje logowanie hasłem przez SSH, udostępnia bazę danych na publicznym porcie albo nie był aktualizowany od chwili postawienia. Dobre praktyki serwerowe są nudne — i to właśnie tędy wchodzi ransomware.
Zamknij każdy port, którego nie potrzebujesz
Publiczny serwer WWW potrzebuje otwartych portów 80 i 443 oraz SSH dostępnego z Twojego zakresu adresów IP. Bazy danych (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), panele administracyjne i endpointy metryk powinny nasłuchiwać tylko na localhost lub w sieci prywatnej. Po każdej zmianie sprawdzaj to z zewnątrz za pomocą Sprawdzania Portów, bo właśnie taki widok ma atakujący, a grupy zabezpieczeń w chmurze łatwo źle odczytać.
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable # check your own IP is in that range first, or you lock yourself out
# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
| sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) ' # what sshd will really use
sudo systemctl reload sshW Ubuntu i Debianie sshd czyta pliki z /etc/ssh/sshd_config.d/ przed resztą sshd_config, a dla każdego ustawienia wygrywa pierwsza przeczytana wartość. Dlatego powyższe polecenia zapisują drop-in o nazwie 00-hardening.conf: edycja niżej w głównym pliku przegra z drop-inem obrazu chmurowego, który mówi PasswordAuthentication yes. Zanim się wylogujesz, potwierdź wynik poleceniem sudo sshd -T. W Sprawdzaniu Portów port, który zapora odrzuca, wygląda jak Filtrowany (brak odpowiedzi), a port, na którym nic nie nasłuchuje, jak Zamknięty: oba są w porządku, do naprawy jest Otwarty.
Łataj regularnie, trzymaj sekrety poza kodem
Włącz automatyczne aktualizacje bezpieczeństwa systemu operacyjnego, zapisz się na listy bezpieczeństwa swojego środowiska uruchomieniowego i frameworka, a krytyczne CVE w czymkolwiek dostępnym z internetu traktuj jako zadanie na ten sam dzień. Uruchamiaj usługi jako użytkownicy bez uprawnień, w kontenerach lub z sandboxingiem systemd, aby przejęty proces nie mógł odczytać całej maszyny.
Sekrety (hasła do baz danych, klucze API, klucze podpisujące) nigdy nie powinny trafiać do repozytorium, warstwy obrazu Dockera ani do JavaScriptu po stronie klienta. Wczytuj je ze zmiennych środowiskowych wstrzykiwanych podczas wdrożenia lub z menedżera sekretów, zmieniaj je, gdy odchodzi ktoś, kto miał do nich dostęp, i skanuj historię repozytorium narzędziem takim jak gitleaks — bo klucz raz zacommitowany jest skompromitowany na zawsze, nawet po usunięciu commita.
Kopie zapasowe odporne na ransomware i CDN przed serwerem
Stosuj zasadę 3-2-1: trzy kopie, na dwóch różnych nośnikach, jedna poza siedzibą, i zadbaj, aby co najmniej jedna kopia była niezmienna (immutable) lub offline, tak by ransomware, które dotrze do serwera, nie zaszyfrowało również kopii zapasowych. Szyfruj kopie, uwzględniaj w nich bazę danych i katalog z przesłanymi plikami, a przede wszystkim regularnie testuj odtwarzanie. Kopia zapasowa, z której nikt nigdy niczego nie odtworzył, to nadzieja, a nie plan. To czas przywrócenia decyduje, czy incydent będzie zwykłą przerwą w działaniu, czy końcem firmy.
Postaw przed serwerem źródłowym CDN lub WAF (Cloudflare, Fastly, AWS CloudFront z WAF albo odpowiednik u twojego hostingodawcy). Pochłania on wolumetryczne DDoS, stosuje zarządzane reguły przeciw typowym ładunkom wstrzyknięć i złym botom, ukrywa IP serwera źródłowego i daje miejsce na limity żądań oraz reguły geograficzne bez dotykania aplikacji. Następnie ogranicz zaporę serwera źródłowego tak, by do portu 443 bezpośrednio mogły się łączyć tylko zakresy IP CDN; w przeciwnym razie atakujący po prostu go ominą. Sprawdzanie hostingu pokazuje, jaki CDN stoi przed stroną i co publiczne dane mówią o hostingu za nim.
Uwierzytelnianie poczty: SPF, DKIM i DMARC
Bezpieczeństwo strony obejmuje też pocztę, która dostarcza resety haseł, faktury i odpowiedzi z pomocy. Bez SPF, DKIM i DMARC każdy może wysłać maila jako billing@yourdomain.com; od lutego 2024 Google i Yahoo wymagają wszystkich trzech od masowych nadawców, a od maja 2025 to samo robi Microsoft dla Outlook.com. Cały zestaw to trzy rekordy TXT w DNS:
yourdomain.com. TXT "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com. TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"DMARC p=reject to także narzędzie ochrony marki: tylko on powstrzymuje kampanię phishingową przed wpisaniem dokładnie Twojej domeny w polu nadawcy (From). Raporty zbiorcze (rua=) pokazują, kto próbuje.
Zacznij DMARC od p=none, żeby zbierać raporty, a gdy każdy legalny nadawca (platforma mailingowa, helpdesk, CRM) przechodzi dopasowanie, przejdź na p=quarantine, a potem p=reject. Dodaj rekordy MTA-STS i TLS-RPT, aby wymusić szyfrowane dostarczanie do twoich serwerów poczty. Na domenach, które nigdy nie wysyłają ani nie odbierają poczty, opublikuj null MX (MX 0 .), v=spf1 -all i rekord DMARC z p=reject: null MX tylko mówi, że domena nie przyjmuje poczty, a to SPF i DMARC pozwalają odbiorcom odrzucać fałszerstwa. Każdy rekord sprawdź w Sprawdzaniu Rekordu SPF, Sprawdzaniu DKIM i Sprawdzaniu DMARC, a jeśli dostarczalność spada, sprawdź adresy IP nadawców na listach blokad w Sprawdzaniu Czarnej Listy IP.
Loguj, monitoruj i planuj na wypadek włamania
Dwie z dziesięciu kategorii OWASP 2025 dotyczą tego, co dzieje się po błędzie: Security Logging and Alerting Failures (A09, błędy logowania zdarzeń i alertowania) oraz nowa kategoria Mishandling of Exceptional Conditions (A10, niewłaściwa obsługa sytuacji wyjątkowych). Typowe włamanie wciąż pozostaje niewykryte miesiącami, bo dowody nigdy nie zostały zapisane — albo zostały, ale nikt do nich nie zajrzał.
- Loguj zdarzenia bezpieczeństwa z kontekstem: każde udane i nieudane logowanie, zmiany MFA, resety haseł, zmiany uprawnień, odmowy dostępu, błędy walidacji danych wejściowych i działania administratorów — każde ze znacznikiem czasu, identyfikatorem użytkownika, źródłowym adresem IP i user agentem.
- Nigdy nie zapisuj sekretów w logach: haseł, tokenów sesji, pełnych numerów kart, kluczy API. Maskuj je w warstwie zapisu logów, a nie w każdym miejscu wywołania.
- Wysyłaj logi poza serwer do centralnego magazynu (CloudWatch, Loki, Elastic, SIEM) z retencją co najmniej 90 dni, aby atakujący z uprawnieniami roota nie mógł zatrzeć śladów.
- Ustawiaj alerty na wzorce, a nie pojedyncze zdarzenia: 50 nieudanych logowań w ciągu minuty, skok liczby odpowiedzi 403 w jednej sesji, nowe konto administratora utworzone poza godzinami pracy, certyfikat wystawiony dla Twojej domeny, którego nikt u Ciebie nie zamawiał.
- Odmawiaj w razie awarii (fail closed): gdy kontrola zależna (usługa uwierzytelniania, rate limiter, WAF) zwraca błąd, odrzuć żądanie. Kategoria A10 istnieje, bo tak wiele systemów przyznaje dostęp, gdy kontrola, która powinna była go zablokować, rzuca wyjątek.
- Monitoruj z zewnątrz: dostępność, wygasanie certyfikatów, zmiany DNS, wpisy na czarnych listach i regresje nagłówków. Po każdym wdrożeniu uruchamiaj ponownie Sprawdzanie Certyfikatu SSL, Checker nagłówków HTTP i kontrolę kondycji DNS (40 testów delegacji, serwerów nazw, DNSSEC oraz SPF/DMARC).
Napisz plan reagowania na incydenty, zanim będzie potrzebny
Ustal z góry, kto jest na dyżurze, jak zmienić wszystkie poświadczenia, jak przełączyć stronę w tryb tylko do odczytu, gdzie leżą czyste kopie zapasowe oraz którego regulatora lub które grupy klientów trzeba powiadomić i w ciągu ilu godzin (72 w RODO). Raz w roku przeprowadź ćwiczenie na sucho (tabletop). Przećwiczony plan zamienia dni improwizacji w listę kontrolną.
Opublikuj plik security.txt pod adresem /.well-known/security.txt (RFC 9116) z linią Contact: i datą Expires:, czyli dwoma wymaganymi polami (klucz Encryption: jest opcjonalny). Badacze, którzy znajdą błąd na twojej stronie, zajrzą tam najpierw; bez niego mogą nie znaleźć nikogo, komu mogliby go zgłosić.
Testuj: skanery, testy penetracyjne i ciągła weryfikacja
Każde z powyższych zabezpieczeń da się zweryfikować, a weryfikację warto w miarę możliwości zautomatyzować, żeby z czasem nie zanikła. Rozsądna drabina — od darmowych i natychmiastowych testów po okresowe i płatne:
| Test | Narzędzie | Jak często |
|---|---|---|
| Konfiguracja TLS, łańcuch, wygaśnięcie | Sprawdzanie Certyfikatu SSL, SSL Labs, testssl.sh | Po każdej zmianie certyfikatu lub serwera; wygaśnięcie codziennie |
| Nagłówki bezpieczeństwa i CSP | Checker nagłówków HTTP, MDN HTTP Observatory | Po każdym wdrożeniu (dodaj do CI) |
| Otwarte porty | Sprawdzanie Portów, nmap spoza twojej sieci | Po każdej zmianie firewalla lub konfiguracji chmury |
| DNS, DNSSEC, uwierzytelnianie poczty | Kontrola kondycji DNS, Sprawdzanie DMARC | Co miesiąc i po każdej zmianie w DNS |
| Nieaktualne subdomeny | Wyszukiwarka Subdomen | Co kwartał i przy każdym wyłączaniu usługi |
| Zależności ze znanymi podatnościami | npm audit, Dependabot, Trivy | Przy każdym buildzie |
| Błędy na poziomie kodu (SAST) | Semgrep, CodeQL | Przy każdym pull requeście |
| Podatności działającej aplikacji (DAST) | ZAP, Nuclei | Co tydzień na środowisku stagingowym |
| Autoryzacja i logika biznesowa | Ręczny test penetracyjny lub program bug bounty | Raz w roku i po wdrożeniu ważnych nowych funkcji |
Skanery dobrze radzą sobie z injection, nagłówkami i przestarzałymi komponentami, a słabo z autoryzacją i logiką biznesową, więc zaplanuj budżet na co najmniej jeden test wykonywany przez człowieka rocznie dla wszystkiego, co obsługuje płatności lub dane osobowe. Naprawiaj według ekspozycji: wszystko, co nieuwierzytelniony użytkownik może wykorzystać z internetu, ma pierwszeństwo.
Lista kontrolna bezpieczeństwa strony internetowej
Skopiuj ją do README projektu lub systemu zgłoszeń. Każdy wiersz to jedna z opisanych wyżej praktyk, sformułowana tak, aby dało się ją oznaczyć jako wykonaną lub nie; ostatnia kolumna to dowód.
| Warstwa | Praktyka | Gotowe, gdy |
|---|---|---|
| Domena | Registrar lock i MFA na koncie u rejestratora; automatyczne odnawianie włączone | WHOIS pokazuje clientTransferProhibited; wygaśnięcie za ponad 12 miesięcy |
| DNS | Strefa podpisana DNSSEC; rekord CAA wymieniający tylko Twoje CA | dig +dnssec zwraca RRSIG; rekord DS obecny w strefie nadrzędnej |
| DNS | Brak wiszących rekordów CNAME i A | Każda nazwa hosta z Wyszukiwarki Subdomen wskazuje zasób pod Twoją kontrolą |
| TLS | Tylko TLS 1.2+, preferowany TLS 1.3, serwowany pełny łańcuch | Sprawdzanie Certyfikatu SSL: łańcuch kompletny, TLS 1.0/1.1 odrzucane |
| TLS | HSTS z max-age na rok i includeSubDomains (preload opcjonalnie) | Checker nagłówków HTTP zalicza test HSTS |
| TLS | Odnawianie zautomatyzowane przez ACME; wygaśnięcie monitorowane | certbot renew --dry-run przechodzi; alert ustawiony na 14 dni przed wygaśnięciem |
| Nagłówki | CSP (oparta na nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy | Ocena A lub A+ w Sprawdzaniu Nagłówków HTTP |
| Uwierzytelnianie | Hashowanie Argon2id lub bcrypt; zasady haseł NIST; sprawdzanie z listą wycieków | Jeden hash trwa od 100 do 250 ms; brak reguł złożoności |
| Uwierzytelnianie | MFA dostępne dla wszystkich, wymagane dla administratorów; obsługa passkeys | Logowanie administratora niemożliwe bez drugiego składnika |
| Uwierzytelnianie | Limity żądań na endpointach logowania, resetu hasła i MFA dla każdego IP i każdego konta | Sześć szybkich prób z jednego IP: szósta zwraca 429 |
| Sesje | Ciasteczko __Host- z Secure, HttpOnly, SameSite; rotacja ID przy logowaniu | Atrybuty ciasteczka widoczne w DevTools; stara sesja nieważna po zalogowaniu |
| Dane wejściowe | Zapytania parametryzowane wszędzie; kodowanie wyjścia zależne od kontekstu; przesyłane pliki walidowane po zawartości | Przeszukanie kodu nie znajduje zapytań sklejanych ze stringów; payloady XSS wyświetlają się jako tekst |
| Kontrola dostępu | Routing z domyślną odmową; sprawdzanie własności każdego obiektu; restrykcyjny CORS | Odtworzenie żądań z identyfikatorami innego użytkownika zwraca 404 lub 403 |
| Zależności | Lockfile w repozytorium; npm ci; audyt w CI; akcje przypięte do SHA; SRI dla skryptów z CDN | Build kończy się błędem przy CVE o wysokiej ważności |
| Serwer | Publicznie tylko 80 i 443; SSH wyłącznie z kluczami; automatyczne aktualizacje bezpieczeństwa; sekrety w zmiennych środowiskowych lub menedżerze sekretów | Sprawdzanie Portów pokazuje porty 3306 i 6379 jako zamknięte lub filtrowane, a 22 także spoza twojego zakresu |
| Kopie zapasowe | 3-2-1 z jedną kopią niezmienną; odtwarzanie przetestowane | Ostatni udany test odtwarzania nie starszy niż 90 dni |
| Poczta | SPF -all, DKIM, DMARC p=reject, MTA-STS | Sprawdzanie DMARC zaliczone; raporty zbiorcze napływają |
| Monitoring | Zdarzenia uwierzytelniania i autoryzacji logowane centralnie; alerty na wzorce; zewnętrzny monitoring dostępności, certyfikatów i DNS | Testowy alert wysłany i odebrany |
| Reagowanie | Spisany plan reagowania na incydenty; opublikowany security.txt; przeprowadzone ćwiczenie tabletop | Plan przejrzany w ciągu ostatnich 12 miesięcy |
Jak to się ma do OWASP Top 10:2025
OWASP Top 10 to najczęściej cytowana lista zagrożeń dla aplikacji webowych, a edycja z 2025 roku zmieniła kolejność i wprowadziła dwie nowe kategorie. Jeśli klient, audytor lub framework zgodności zapyta, jak się do niej odnosisz, oto zestawienie z praktykami z tego przewodnika:
| OWASP Top 10:2025 | Praktyki z tego przewodnika |
|---|---|
| A01 Broken Access Control | Domyślna odmowa, kontrola dla każdego obiektu, restrykcyjny CORS, zabezpieczone panele administracyjne |
| A02 Security Misconfiguration | Nagłówki bezpieczeństwa, HSTS, zamknięte porty, usunięte nagłówki z wersjami, wyłączone listowanie katalogów |
| A03 Software Supply Chain Failures (nowa) | Lockfile, audyty, przypięte akcje, SRI, SBOM, CI z minimalnymi uprawnieniami |
| A04 Cryptographic Failures | TLS 1.2+ i 1.3, HSTS, Argon2id, zarządzanie sekretami, szyfrowane kopie zapasowe |
| A05 Injection | Zapytania parametryzowane, kodowanie danych wyjściowych, CSP, walidacja przesyłanych plików |
| A06 Insecure Design | Model zagrożeń dla każdej warstwy, domyślne zachowanie fail closed, limitowanie żądań uwzględnione w projekcie |
| A07 Authentication Failures | Zasady haseł NIST, sprawdzanie wycieków, MFA i passkeys, rotacja sesji |
| A08 Software or Data Integrity Failures | SRI, podpisane i przypięte zależności, bezpieczna deserializacja |
| A09 Security Logging and Alerting Failures | Centralne logi, alerty na wzorce, monitoring zewnętrzny |
| A10 Mishandling of Exceptional Conditions (nowa) | Fail closed, jednolite odpowiedzi błędów, żadnych stack trace'ów dla użytkowników |
OWASP ASVS (Application Security Verification Standard) przekłada ten sam materiał na ponumerowaną listę kontrolną do audytów. Poziom 1 to realistyczny cel dla każdej publicznej strony; poziom 2 — dla wszystkiego, co przetwarza dane osobowe lub finansowe.
Sprawdź nagłówki bezpieczeństwa swojej strony w kilka sekund
Darmowe Checker nagłówków HTTP od DNS Robot pokazuje nagłówki odpowiedzi dowolnego adresu URL dokładnie tak, jak wysyła je serwer, i ocenia nagłówki bezpieczeństwa testami Mozilla HTTP Observatory, z poprawką dla każdego brakującego. Bez rejestracji.
Źródła
- 2026 Data Breach Investigations Report, Verizon
- OWASP Top 10:2025, OWASP
- Password Storage Cheat Sheet, OWASP
- SP 800-63B-4: Authentication and Authenticator Management, NIST
- Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
- HTTPS by default, Google
- RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF
Bezpieczeństwo strony internetowej — najczęstsze pytania
Jakie są najważniejsze zasady bezpieczeństwa strony internetowej?
Czym jest OWASP Top 10 i czy nadal ma znaczenie w 2026 roku?
Jakie nagłówki bezpieczeństwa HTTP powinna wysyłać każda strona?
Czy HTTPS wystarczy, aby zapewnić bezpieczeństwo strony internetowej?
Jak bezpiecznie przechowywać hasła użytkowników?
Czym jest Content Security Policy i czy jest potrzebna?
Jak sprawdzić bezpieczeństwo strony internetowej?
Dlaczego certyfikaty TLS mają coraz krótszą ważność?
Jak często aktualizować zależności strony internetowej?
Czy małe strony internetowe naprawdę są atakowane?
Powiązane artykuły
Powiązane narzędzia
Sprawdzanie Nagłówków HTTP
Analizuj nagłówki odpowiedzi HTTP i ocenę nagłówków bezpieczeństwa
Sprawdzanie Certyfikatu SSL
Weryfikuj ważność certyfikatu SSL i szczegóły bezpieczeństwa
Sprawdzanie Portów
Testuj łączność portów i dostępność usług
Kontrola kondycji DNS
Oceń DNS domeny: delegacja, serwery nazw, SOA, DNSSEC i poczta w 40 testach
Sprawdzanie DMARC
Sprawdź politykę DMARC i ustawienia wyrównania dla dowolnej domeny
Wyszukiwarka Subdomen
Odkryj wszystkie subdomeny dowolnej domeny



