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

Bezpieczeństwo strony internetowej jako sześć warstw: domena i DNS, TLS, nagłówki HTTP, aplikacja, zależności, serwer
Bezpieczeństwo strony internetowej jako sześć warstw: domena i DNS, TLS, nagłówki HTTP, aplikacja, zależności, serwer
Zacznij czytać
  1. Czym właściwie jest bezpieczeństwo strony internetowej
  2. Stos bezpieczeństwa strony: sześć warstw do ochrony
  3. Warstwa 1: zabezpiecz domenę i DNS
  4. Warstwa 2: HTTPS i TLS skonfigurowane porządnie
  5. Warstwa 3: nagłówki bezpieczeństwa HTTP
  6. Warstwa 4: uwierzytelnianie odporne na credential stuffing
  7. Sesje, ciasteczka i CSRF
  8. Injection i XSS: waliduj dane wejściowe, koduj dane wyjściowe
  9. Broken Access Control: ryzyko numer jeden
  10. Warstwa 5: zależności i łańcuch dostaw oprogramowania
  11. Warstwa 6: hardening serwera (porty, poprawki, sekrety, kopie zapasowe)
  12. Uwierzytelnianie poczty: SPF, DKIM i DMARC
  13. Loguj, monitoruj i planuj na wypadek włamania
  14. Testuj: skanery, testy penetracyjne i ciągła weryfikacja
  15. Lista kontrolna bezpieczeństwa strony internetowej
  16. Jak to się ma do OWASP Top 10:2025
  17. 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.

WarstwaCo robią tu atakującyKluczowe praktykiJak sprawdzić
1. Domena i DNSPrzejmują domenę, zmieniają serwery nazw, przejmują porzucone subdomeny, uzyskują nieuprawnione certyfikatyRegistrar lock, MFA, DNSSEC, CAA, audyt nieaktualnych rekordówWyszukiwanie WHOIS, Kontrola kondycji DNS, Wyszukiwarka Subdomen
2. Transport (TLS)Wymuszają powrót do HTTP, usuwają szyfrowanie, wykorzystują stare szyfry i wygasłe certyfikatyTLS 1.2+, HSTS (preload opcjonalnie), automatyczne odnawianieSprawdzanie Certyfikatu SSL
3. Nagłówki HTTPWstrzykują skrypty (XSS), osadzają stronę w ramce do clickjackingu, wykorzystują zgadywanie typów treści, wyciągają adresy z nagłówka RefererCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyChecker nagłówków HTTP
4. AplikacjaCredential stuffing, injection, błędy kontroli dostępu, CSRF, niebezpieczne przesyłanie plikówArgon2id + MFA + limity żądań, zapytania parametryzowane, autoryzacja po stronie serwera, ciasteczka SameSitePrzegląd kodu, ZAP, Test Siły Hasła
5. ZależnościZatrute pakiety, znane CVE w bibliotekach, przejęte potoki CILockfile, audyty, przypięte wersje, SBOM, tokeny z minimalnymi uprawnieniaminpm audit, Dependabot, Trivy
6. Serwer i utrzymanieOtwarte porty, domyślne hasła, brak poprawek, brak kopii zapasowych, brak logówFirewall, SSH tylko z kluczami, regularne łatanie, kopie zapasowe 3-2-1, centralne gromadzenie logówSprawdzanie 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:

bash
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...C9

Ogranicz 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:

dns
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:

bash
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.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains

Certyfikaty 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 życieMaksymalna ważność certyfikatuPonowne użycie walidacji domeny
Przed 15 marca 2026398 dni398 dni
15 marca 2026200 dni200 dni
15 marca 2027100 dni100 dni
15 marca 202947 dni10 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'):

bash
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łówekZalecana wartośćCo blokuje
Strict-Transport-Securitymax-age=31536000; includeSubDomainsDowngrade protokołu, kradzież ciasteczek przez HTTP
Content-Security-Policyscript-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-OptionsnosniffMIME sniffing, który zamienia przesłany plik w wykonywalny skrypt
Referrer-Policystrict-origin-when-cross-originWyciek pełnych adresów URL (tokenów, wyszukiwanych fraz) do stron trzecich
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Ciche korzystanie z potężnych API przeglądarki przez zewnętrzne skrypty
X-Frame-OptionsDENY (starszy zamiennik dla frame-ancestors)Clickjacking w przeglądarkach bez CSP Level 2
Cross-Origin-Opener-Policysame-originAtaki 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.

http
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.
javascript
// 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
# 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:

  • Secure oznacza, że ciasteczko nigdy nie jest wysyłane przez zwykłe HTTP, więc nie da się go podsłuchać w publicznej sieci Wi-Fi.
  • HttpOnly sprawia, że ciasteczko jest niewidoczne dla JavaScriptu, więc błąd XSS nie pozwoli go odczytać.
  • SameSite=Lax (lub Strict dla 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 atrybut Secure, Path=/ i nie ma atrybutu Domain, więc subdomena nie może go nadpisać.
http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Akcje 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).

javascript
// 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ą daneJak kodowaćPrzykład
Treść HTMLEncje HTML< zmienia się w &lt;, a " w &quot;
Atrybut HTMLEncje w atrybucie ujętym w cudzysłówZawsze ujmuj atrybut w cudzysłów; koduj " i '
JavaScriptNie 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 URLKodowanie procentowe (percent-encoding)encodeURIComponent(value)
Wartość CSSUnikaj całkowicie; wybieraj nazwy klas z listy dozwolonychNigdy 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łówka Origin wysł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.
javascript
// 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 przez npm 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 (minimumReleaseAge w 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.
bash
# 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ć.

bash
# 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 ssh

W 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:

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:

TestNarzędzieJak często
Konfiguracja TLS, łańcuch, wygaśnięcieSprawdzanie Certyfikatu SSL, SSL Labs, testssl.shPo każdej zmianie certyfikatu lub serwera; wygaśnięcie codziennie
Nagłówki bezpieczeństwa i CSPChecker nagłówków HTTP, MDN HTTP ObservatoryPo każdym wdrożeniu (dodaj do CI)
Otwarte portySprawdzanie Portów, nmap spoza twojej sieciPo każdej zmianie firewalla lub konfiguracji chmury
DNS, DNSSEC, uwierzytelnianie pocztyKontrola kondycji DNS, Sprawdzanie DMARCCo miesiąc i po każdej zmianie w DNS
Nieaktualne subdomenyWyszukiwarka SubdomenCo kwartał i przy każdym wyłączaniu usługi
Zależności ze znanymi podatnościaminpm audit, Dependabot, TrivyPrzy każdym buildzie
Błędy na poziomie kodu (SAST)Semgrep, CodeQLPrzy każdym pull requeście
Podatności działającej aplikacji (DAST)ZAP, NucleiCo tydzień na środowisku stagingowym
Autoryzacja i logika biznesowaRęczny test penetracyjny lub program bug bountyRaz 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.

WarstwaPraktykaGotowe, gdy
DomenaRegistrar lock i MFA na koncie u rejestratora; automatyczne odnawianie włączoneWHOIS pokazuje clientTransferProhibited; wygaśnięcie za ponad 12 miesięcy
DNSStrefa podpisana DNSSEC; rekord CAA wymieniający tylko Twoje CAdig +dnssec zwraca RRSIG; rekord DS obecny w strefie nadrzędnej
DNSBrak wiszących rekordów CNAME i AKażda nazwa hosta z Wyszukiwarki Subdomen wskazuje zasób pod Twoją kontrolą
TLSTylko TLS 1.2+, preferowany TLS 1.3, serwowany pełny łańcuchSprawdzanie Certyfikatu SSL: łańcuch kompletny, TLS 1.0/1.1 odrzucane
TLSHSTS z max-age na rok i includeSubDomains (preload opcjonalnie)Checker nagłówków HTTP zalicza test HSTS
TLSOdnawianie zautomatyzowane przez ACME; wygaśnięcie monitorowanecertbot renew --dry-run przechodzi; alert ustawiony na 14 dni przed wygaśnięciem
NagłówkiCSP (oparta na nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyOcena A lub A+ w Sprawdzaniu Nagłówków HTTP
UwierzytelnianieHashowanie Argon2id lub bcrypt; zasady haseł NIST; sprawdzanie z listą wyciekówJeden hash trwa od 100 do 250 ms; brak reguł złożoności
UwierzytelnianieMFA dostępne dla wszystkich, wymagane dla administratorów; obsługa passkeysLogowanie administratora niemożliwe bez drugiego składnika
UwierzytelnianieLimity żądań na endpointach logowania, resetu hasła i MFA dla każdego IP i każdego kontaSześć szybkich prób z jednego IP: szósta zwraca 429
SesjeCiasteczko __Host- z Secure, HttpOnly, SameSite; rotacja ID przy logowaniuAtrybuty ciasteczka widoczne w DevTools; stara sesja nieważna po zalogowaniu
Dane wejścioweZapytania parametryzowane wszędzie; kodowanie wyjścia zależne od kontekstu; przesyłane pliki walidowane po zawartościPrzeszukanie kodu nie znajduje zapytań sklejanych ze stringów; payloady XSS wyświetlają się jako tekst
Kontrola dostępuRouting z domyślną odmową; sprawdzanie własności każdego obiektu; restrykcyjny CORSOdtworzenie żądań z identyfikatorami innego użytkownika zwraca 404 lub 403
ZależnościLockfile w repozytorium; npm ci; audyt w CI; akcje przypięte do SHA; SRI dla skryptów z CDNBuild kończy się błędem przy CVE o wysokiej ważności
SerwerPublicznie tylko 80 i 443; SSH wyłącznie z kluczami; automatyczne aktualizacje bezpieczeństwa; sekrety w zmiennych środowiskowych lub menedżerze sekretówSprawdzanie Portów pokazuje porty 3306 i 6379 jako zamknięte lub filtrowane, a 22 także spoza twojego zakresu
Kopie zapasowe3-2-1 z jedną kopią niezmienną; odtwarzanie przetestowaneOstatni udany test odtwarzania nie starszy niż 90 dni
PocztaSPF -all, DKIM, DMARC p=reject, MTA-STSSprawdzanie DMARC zaliczone; raporty zbiorcze napływają
MonitoringZdarzenia uwierzytelniania i autoryzacji logowane centralnie; alerty na wzorce; zewnętrzny monitoring dostępności, certyfikatów i DNSTestowy alert wysłany i odebrany
ReagowanieSpisany plan reagowania na incydenty; opublikowany security.txt; przeprowadzone ćwiczenie tabletopPlan 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:2025Praktyki z tego przewodnika
A01 Broken Access ControlDomyślna odmowa, kontrola dla każdego obiektu, restrykcyjny CORS, zabezpieczone panele administracyjne
A02 Security MisconfigurationNagłó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 FailuresTLS 1.2+ i 1.3, HSTS, Argon2id, zarządzanie sekretami, szyfrowane kopie zapasowe
A05 InjectionZapytania parametryzowane, kodowanie danych wyjściowych, CSP, walidacja przesyłanych plików
A06 Insecure DesignModel zagrożeń dla każdej warstwy, domyślne zachowanie fail closed, limitowanie żądań uwzględnione w projekcie
A07 Authentication FailuresZasady haseł NIST, sprawdzanie wycieków, MFA i passkeys, rotacja sesji
A08 Software or Data Integrity FailuresSRI, podpisane i przypięte zależności, bezpieczna deserializacja
A09 Security Logging and Alerting FailuresCentralne 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

  1. 2026 Data Breach Investigations Report, Verizon
  2. OWASP Top 10:2025, OWASP
  3. Password Storage Cheat Sheet, OWASP
  4. SP 800-63B-4: Authentication and Authenticator Management, NIST
  5. Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
  6. HTTPS by default, Google
  7. 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?

Wymuś HTTPS z nowoczesnym TLS i HSTS, wysyłaj restrykcyjne nagłówki bezpieczeństwa (zwłaszcza Content Security Policy), hashuj hasła algorytmem Argon2id i chroń logowanie za pomocą MFA oraz limitów żądań, używaj zapytań parametryzowanych i kodowania danych wyjściowych, egzekwuj kontrolę dostępu na serwerze dla każdego obiektu, aktualizuj i przypinaj zależności, zamknij nieużywane porty i centralnie zbieraj logi zdarzeń bezpieczeństwa. Zacznij od zabezpieczenia domeny i DNS, bo wszystko inne zależy od tego, czy nadal kontrolujesz swoją domenę.

Czym jest OWASP Top 10 i czy nadal ma znaczenie w 2026 roku?

OWASP Top 10 to rozwijany przez społeczność ranking najpoważniejszych zagrożeń bezpieczeństwa aplikacji webowych. Edycja z 2025 roku obejmuje: Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures oraz Mishandling of Exceptional Conditions. Wciąż jest to punkt odniesienia, na który powołuje się większość audytów, frameworków i klientów.

Jakie nagłówki bezpieczeństwa HTTP powinna wysyłać każda strona?

Co najmniej: Strict-Transport-Security, Content-Security-Policy (łącznie z frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin i Permissions-Policy. X-Frame-Options: DENY to starszy zamiennik dla frame-ancestors, a Cross-Origin-Opener-Policy: same-origin to tani dodatek. Usuń nagłówki Server i X-Powered-By, aby skanery nie mogły odczytać wersji Twojego oprogramowania.

Czy HTTPS wystarczy, aby zapewnić bezpieczeństwo strony internetowej?

Nie. HTTPS szyfruje ruch między przeglądarką a serwerem, ale nic nie robi z wstrzyknięciami, błędną kontrolą dostępu, słabymi hasłami, podatnymi zależnościami ani otwartym portem bazy danych. To warstwa podstawowa, a HSTS ją utrwala: gdy przeglądarka raz zobaczy nagłówek, nigdy więcej nie wyśle do twojej domeny zwykłego żądania HTTP.

Jak bezpiecznie przechowywać hasła użytkowników?

Nigdy otwartym tekstem i nigdy w postaci szybkiego hasha, takiego jak MD5 czy SHA-256. Używaj Argon2id (19 MiB pamięci, 2 iteracje) lub bcrypt ze współczynnikiem pracy 10 lub wyższym, z unikalną solą dla każdego hasła, i dobierz parametry tak, aby jeden hash trwał około 100–250 ms. Sprawdzaj nowe hasła z listą wycieków i wymagaj MFA dla kont uprzywilejowanych.

Czym jest Content Security Policy i czy jest potrzebna?

CSP to nagłówek HTTP, który informuje przeglądarkę, z jakich źródeł strona może ładować skrypty, style, ramki i inne zasoby. CSP oparta na nonce z 'strict-dynamic' powstrzymuje większość ataków cross-site scripting nawet wtedy, gdy w kodzie istnieje błąd umożliwiający wstrzyknięcie. Powinna ją mieć każda strona, która wyświetla treści od użytkowników lub ładuje zewnętrzne skrypty; zacznij w trybie report-only i przełącz się na egzekwowanie, gdy raporty o naruszeniach przestaną zgłaszać problemy.

Jak sprawdzić bezpieczeństwo strony internetowej?

Zacznij od kontroli z zewnątrz: kontroli SSL pod kątem wersji TLS, łańcucha i wygaśnięcia; kontroli nagłówków HTTP pod kątem nagłówków bezpieczeństwa; kontroli portów pod kątem wystawionych usług oraz kontroli kondycji DNS pod kątem DNSSEC i SPF/DMARC. Potem przeskanuj zależności poleceniem npm audit lub jego odpowiednikiem dla twojego stosu, uruchom ZAP na kopii stagingowej i ręcznie przetestuj kontrolę dostępu, odtwarzając żądania jako inny użytkownik.

Dlaczego certyfikaty TLS mają coraz krótszą ważność?

CA/Browser Forum przegłosowało skrócenie maksymalnej ważności certyfikatu z 398 dni do 200 dni (15 marca 2026), 100 dni (15 marca 2027) i 47 dni (15 marca 2029), ponieważ krótsze certyfikaty ograniczają szkody po kradzieży klucza lub błędnym wystawieniu certyfikatu i zmniejszają zależność od mechanizmów unieważniania. W praktyce oznacza to, że odnawianie trzeba zautomatyzować za pomocą ACME.

Jak często aktualizować zależności strony internetowej?

Poprawki bezpieczeństwa stosuj od razu po ich wydaniu — w przypadku wszystkiego, co jest dostępne z internetu, najlepiej w ciągu 24 godzin — i uruchamiaj automatyczny audyt przy każdym buildzie. W przypadku aktualizacji niezwiązanych z bezpieczeństwem bezpieczniejsze jest krótkie, kilkudniowe opóźnienie, bo przejęte wydania pakietów są zwykle szybko wycofywane; narzędzia takie jak Renovate mogą wymuszać to opóźnienie automatycznie.

Czy małe strony internetowe naprawdę są atakowane?

Tak, i to nieustannie, bo ataki są zautomatyzowane i nie wybierają celów według wielkości. Skanery sondują każdy publiczny adres IP w poszukiwaniu otwartych portów i znanych podatności CMS-ów, a narzędzia do credential stuffingu próbują wyciekłych haseł w każdym formularzu logowania, jaki znajdą. Mała strona jest też cenna jako hosting dla phishingu, przekaźnik spamu albo przyczółek do ataku na większego klienta.

O autorze

Shaik Vahid

Założyciel DNS Robot. Vahid przez lata pracował we wsparciu hostingu, naprawiając klientom domeny, rekordy DNS, certyfikaty SSL i dostarczanie poczty. Tworzy narzędzia DNS Robot i pisze te poradniki na podstawie błędów, które ludzie naprawdę widzą.

Sprawdzanie Nagłówków HTTP

Analizuj nagłówki odpowiedzi HTTP i ocenę nagłówków bezpieczeństwa