Nowy standard. Twoje centrum tworzenia inteligentnego, szybkiego i zrównoważonego oprogramowania AI

Zobacz teraz
grafika tytułowa wpisu blogowego o najlepszych praktykach bezpieczeństwa w Node.js

Najlepsze praktyki bezpieczeństwa w Node.js: praktyczny przewodnik po bezpiecznych aplikacjach

Zura Iashvili
|   Updated Oct 25, 2026

Najlepsze praktyki bezpieczeństwa w Node.js sprowadzają się do krótkiej listy zabezpieczeń, które twój zespół musi wdrożyć samodzielnie: zablokowanego łańcucha dostaw npm, silnego uwierzytelniania, ograniczeń kosztu pojedynczego żądania, walidacji danych wejściowych oraz utwardzonych ustawień środowiska uruchomieniowego.

Node.js i minimalistyczne frameworki, takie jak Express, domyślnie nie włączają prawie żadnego z tych mechanizmów. W 2025 roku ten problem stał się jeszcze trudniejszy do zignorowania: samoreplikujący się robak Shai-Hulud skompromitował ponad 500 pakietów npm, według CISA, a OWASP Top 10:2025 dodał awarie łańcucha dostaw oprogramowania jako nową kategorię na 3. miejscu.

Ten przewodnik omawia zabezpieczenia, które mają największe znaczenie dla produkcyjnej aplikacji Node.js w 2026 roku, narzędzia do ich wdrożenia oraz kompromisy związane z każdym z nich.

Podsumowanie

Bezpieczna aplikacja Node.js jest efektem świadomych decyzji inżynierskich, a nie samego środowiska uruchomieniowego czy frameworka, ponieważ Node.js ufa każdej linii kodu, którą wykonuje.

Najbardziej wartościowe zabezpieczenia to korzystanie ze wspieranej wersji LTS, kontrolowanie tego, co trafia do drzewa zależności npm, haszowanie haseł za pomocą Argon2id lub scrypt oraz dodanie uwierzytelniania wieloskładnikowego, ograniczanie liczby i rozmiaru wszystkich żądań oraz walidacja danych wejściowych, zanim trafią do bazy danych lub szablonu.

Żadne z tych działań samo w sobie nie jest kosztowne. To ich pominięcie sprawia, że rutynowa aktualizacja zależności albo endpoint logowania przeradza się w naruszenie bezpieczeństwa, a za nim idą koszty reakcji na incydent, ryzyko związane ze zgodnością z przepisami i utrata zaufania klientów.

Dlaczego aplikacje Node.js są domyślnie narażone na zagrożenia?

Aplikacje Node.js są domyślnie narażone na zagrożenia, ponieważ środowisko uruchomieniowe traktuje cały wykonywany kod, w tym każdą zależność npm, jako zaufany, a popularne frameworki pozostawiają zabezpieczenia po twojej stronie. Express nie ustawia domyślnie nagłówków bezpieczeństwa, nie ogranicza liczby żądań ani nie waliduje danych wejściowych. To rozsądna decyzja projektowa w przypadku minimalistycznego frameworka, ale oznacza też, że nowy serwis oparty na Expressie lub NestJS jest tylko tak bezpieczny, jak middleware i praktyki, które wdroży twój zespół.

Dwa najsłabsze punkty bezpośrednio odpowiadają temu, jak zaczynają się naruszenia bezpieczeństwa. W raporcie Verizon 2025 Data Breach Investigations Report nadużycie poświadczeń (22%) i wykorzystanie podatności (20%) były głównymi początkowymi wektorami ataku, a liczba naruszeń z udziałem strony trzeciej wzrosła dwukrotnie do 30%. Dla zespołu Node.js oznacza to endpointy logowania i zależności. Skradziony token npm albo słaba polityka haseł prowadzą do nieautoryzowanego dostępu, a ten z kolei do zgłoszenia naruszenia i opóźnienia wydania. W regulowanych sektorach, takich jak FinTech czy HealthTech, staje się to też problemem zgodności z przepisami, a nie tylko technicznym.

Jakich zabezpieczeń potrzebuje produkcyjna aplikacja Node.js?

Większość pracy nad bezpieczeństwem w Node.js sprowadza się do pięciu obszarów. Poniższa tabela pokazuje, jakie zabezpieczenie zatrzymuje każde typowe zagrożenie i jakich narzędzi Node.js możesz do tego użyć.

Zagrożenie

Zabezpieczenie

Narzędzia Node.js

Złośliwy lub przejęty pakiet npm

Lockfile'e, opóźnienie wdrażania nowych wydań, krótkotrwałe poświadczenia do publikacji

npm ci, min-release-age, trusted publishing

Wycieczona baza haseł

Wolne haszowanie haseł z użyciem soli

crypto.argon2 (Node.js 24.7+), crypto.scrypt

Credential stuffing i brute force

Rate limiting, MFA, sprawdzanie haseł po wyciekach

rate-limiter-flexible, passkeys/WebAuthn

Odmowa usługi

Limity rozmiaru żądań, bezpieczne wyrażenia regularne

express.json({ limit }), eslint-plugin-security

NoSQL injection i XSS

Walidacja schematu, sanityzacja filtrów, kodowanie danych wyjściowych, CSP

Mongoose sanitizeFilter, sanitize-html, helmet

Nieprawidłowa kontrola dostępu

Sprawdzanie autoryzacji przy każdym żądaniu

Middleware tras lub guards w NestJS

Jak chronić aplikację Node.js przed atakami na łańcuch dostaw npm?

Aplikację Node.js chronisz przed atakami na łańcuch dostaw, dokładnie kontrolując, które wersje pakietów są instalowane, opóźniając wdrażanie zupełnie nowych wydań i traktując poświadczenia deweloperów oraz CI jak sekrety produkcyjne. Wrzesień 2025 roku pokazał, dlaczego to ważne. Najpierw atakujący wyłudzili dane maintenera i opublikowali złośliwe wersje szeroko używanych pakietów, takich jak chalk i debug. Tydzień później robak Shai-Hulud zaczął wykradać tokeny npm i GitHub z komputerów deweloperów, a następnie używać ich do publikowania zainfekowanych wersji innych pakietów.

Zabezpieczenia, które ograniczyłyby skalę szkód, to w większości kwestia konfiguracji:

  • Commituj lockfile i instaluj zależności przez npm ci w CI, aby buildy korzystały dokładnie z wersji, które sprawdziliście, a nie z tego, co opublikowano godzinę temu.

  • Dodaj opóźnienie wdrażania nowych wydań. Nowsze wersje npm obsługują ustawienie min-release-age, a pnpm oferuje minimumReleaseAge. Kilka dni zwłoki wystarczy, by większość przejętych wydań została wykryta i wycofana, zanim do ciebie trafi.

  • Ogranicz skrypty instalacyjne. Skrypty cyklu życia uruchamiają dowolny kod podczas npm install. Uruchamianie instalacji z opcją --ignore-scripts i dopuszczanie tylko tych pakietów, które naprawdę potrzebują skryptów, zamyka często wykorzystywany punkt wejścia.

  • Chroń poświadczenia. Wytyczne CISA po Shai-Hulud zalecały rotację poświadczeń deweloperów i obowiązkowe MFA odporne na phishing w GitHub i npm. Jeśli publikujesz pakiety, npm unieważnił wszystkie klasyczne tokeny w grudniu 2025 roku; rekomendowaną drogą jest dziś trusted publishing z CI, które korzysta z krótkotrwałych poświadczeń.

Nadal korzystaj z npm audit, ale miej świadomość jego ograniczeń. Narzędzie wykrywa znane podatności opisane w opublikowanych advisory. Nie wyłapie złośliwej wersji wypuszczonej dziś rano, a właśnie na tym opierały się ataki z 2025 roku.

Jak aplikacja Node.js powinna przechowywać hasła i obsługiwać logowanie?

Aplikacja Node.js powinna haszować hasła za pomocą Argon2id albo, jeśli Argon2id nie jest dostępny, scrypt, i nigdy nie przechowywać ich w postaci zaszyfrowanej ani jako zwykły tekst. Taką kolejność zaleca OWASP Password Storage Cheat Sheet. Bcrypt jest zarezerwowany dla systemów legacy, ponieważ obcina dane wejściowe do 72 bajtów. Do tego nie potrzebujesz już natywnego modułu zewnętrznego: Node.js od lat zawiera crypto.scrypt, a crypto.argon2 pojawiło się w Node.js 24.7.0 (dokumentacja Node.js). Używaj wersji asynchronicznych. Synchroniczne haszowanie blokuje event loop dla wszystkich pozostałych żądań w tym procesie.

Zmieniły się też zasady dotyczące haseł. NIST SP 800-63B zaleca teraz, by nie narzucać reguł składu hasła (wielkie litery, cyfry, symbole) ani okresowych resetów. Zamiast tego wymagaj odpowiedniej długości, co najmniej 15 znaków przy logowaniu wyłącznie hasłem i 8 znaków przy MFA, oraz sprawdzaj nowe hasła pod kątem list haseł ujawnionych w wyciekach lub powszechnie używanych.

Uwierzytelnianie wieloskładnikowe to największa pojedyncza poprawa, jaką możesz wprowadzić w procesie logowania. Gdy Google automatycznie objął weryfikacją dwuetapową ponad 150 milionów użytkowników, odnotował spadek liczby przejętych kont o 50% w tej grupie. Passkeys (WebAuthn) idą o krok dalej, bo nie da się ich wyłudzić. Znaczenie ma też kilka innych szczegółów związanych z logowaniem:

  • Zwracaj ten sam ogólny komunikat błędu przy błędnej nazwie użytkownika i błędnym haśle, aby atakujący nie mogli potwierdzić, które konta istnieją.

  • Jeśli przechowujesz JWT w przeglądarce, umieszczaj je w ciasteczkach HttpOnly, Secure, SameSite, a nie w localStorage, i dodaj ochronę CSRF. Kiedyś standardowy pakiet csurf jest przestarzały, więc wybierz utrzymywaną alternatywę.

Zanim zaczniesz to wszystko budować, zastanów się, czy w ogóle powinieneś. Jeśli uwierzytelnianie nie jest częścią twojego produktu, zarządzany dostawca tożsamości, taki jak Auth0, Okta, Amazon Cognito czy Firebase Authentication, przejmie za ciebie MFA, passkeys i wykrywanie naruszeń. Ceną jest rozliczenie per użytkownik i częściowe uzależnienie od dostawcy, ale zwykle kosztuje to mniej niż utrzymywanie własnego systemu auth i historii jego incydentów.

Jak zatrzymać ataki brute force i denial-of-service na API Node.js?

Ataki brute force i denial-of-service na API Node.js zatrzymasz przez ograniczanie liczby żądań, limity ich rozmiaru oraz przenoszenie kosztownych operacji poza event loop. W Node.js ma to większe znaczenie niż w środowiskach z osobnym wątkiem na każde żądanie: jedno wolne, obciążające CPU żądanie może zablokować wszystkie pozostałe obsługiwane przez ten proces.

Biblioteki takie jak rate-limiter-flexible pozwalają ograniczać liczbę żądań na IP, użytkownika lub trasę. Gdy uruchamiasz więcej niż jedną instancję, oprzyj limiter o Redis albo inny współdzielony magazyn; licznik trzymany w pamięci każdego procesu pozwala atakującym zwielokrotnić limit proporcjonalnie do liczby instancji. Dla endpointów logowania ograniczaj ruch zarówno według IP, jak i nazwy użytkownika, i wybieraj raczej stopniowe opóźnienia niż twarde blokady, bo blokady pozwalają atakującemu celowo odcinać dostęp prawdziwym użytkownikom.

Od wersji Express 4.16 express.json() i express.urlencoded() przyjmują opcję limit (domyślnie 100 KB), więc nie potrzebujesz już osobnego pakietu body-parser. Ustaw ciaśniejsze limity na trasach, które przyjmują tylko małe payloady, a przesyłanie plików obsługuj strumieniowo, zamiast buforować je w pamięci.

Źle napisane wyrażenie regularne ze zagnieżdżonymi kwantyfikatorami może potrzebować kilku sekund, by przetworzyć spreparowany ciąg znaków. Ten wzorzec jest znany jako ReDoS (Regular Expression Denial of Service). Utrzymuj regexy w prostej formie, ograniczaj długość danych wejściowych przed dopasowaniem i używaj reguły lintingu, takiej jak eslint-plugin-security, aby wychwytywać ryzykowne wzorce.

Jak zapobiegać atakom injection i XSS w Node.js?

Atakom injection i XSS w Node.js zapobiegasz, walidując każde dane wejściowe względem schematu na brzegu aplikacji i kodując dane wyjściowe odpowiednio do kontekstu renderowania. Biblioteki do walidacji, takie jak Zod czy express-validator, pozwalają zdefiniować, jak wygląda poprawne żądanie, i odrzucać wszystko inne, co jest skuteczniejsze niż próby usuwania znanych niebezpiecznych danych wejściowych.

W przypadku MongoDB sama walidacja schematu nie wystarczy. Jeśli zapytanie logowania otrzyma { "password": { "$ne": null } } zamiast ciągu znaków, może dopasować dowolnego użytkownika. Włącz w Mongoose sanitizeFilter opcjęktóra opakowuje obiekty operatorów tak, by były traktowane jak wartości dosłowne, albo użyj express-mongo-sanitize do usuwania kluczy z prefiksem $. W przypadku baz SQL używaj zapytań parametryzowanych albo query buildera swojego ORM-u, nigdy konkatenacji stringów.

W ochronie przed XSS polegaj na domyślnym escapingu w swoim silniku szablonów albo frameworku frontendowym, a z sanitize-html lub DOMPurify korzystaj tylko tam, gdzie naprawdę musisz renderować HTML dostarczony przez użytkownika. Starsze poradniki polecają xss-clean, ale ten pakiet jest przestarzały. Dodaj helmet, aby ustawić Content Security Policy i inne nagłówki bezpieczeństwa, co ogranicza skalę szkód, gdy atak injection jednak przejdzie. Trzymaj też eval(), new Function() i child_process.exec() z dala od wszystkiego, nad czym użytkownik ma kontrolę.

Jakie ustawienia środowiska uruchomieniowego i konfiguracji utwardzają wdrożenie Node.js?

Utwardzone wdrożenie Node.js działa na wspieranej wersji LTS, trzyma sekrety poza bazą kodu i bezpiecznie obsługuje błędy. Na październik 2026 roku wspierane linie LTS to Node.js 22 i 24, Node.js 26 jest wydaniem Current, a Node.js 20 nie otrzymuje już poprawek bezpieczeństwa (wydania Node.js). Uruchamianie wersji po zakończeniu wsparcia oznacza, że każda nowa podatność CVE w Node.js pozostaje otwarta w twojej aplikacji.

Pozostała część listy kontrolnej utwardzania jest krótka:

  1. Ogranicz środowisko uruchomieniowe. Permission Model w Node.js, stabilny od wersji 22.13.0, ogranicza dostęp do systemu plików, sieci, procesów potomnych i workerów za pomocą flag takich jak --permission i --allow-fs-read. To pas bezpieczeństwa na wypadek błędów, a nie sandbox dla złośliwego kodu.

  2. Trzymaj sekrety poza Gitem. Ładuj klucze API i poświadczenia do baz danych ze zmiennych środowiskowych albo managera sekretów i włącz skanowanie sekretów w repozytorium.

  3. Używaj HTTPS wszędzie i wysyłaj nagłówek HSTS, który helmet ustawia za ciebie.

  4. Sprawdzaj autoryzację przy każdym żądaniu, nie tylko podczas logowania. Nieprawidłowa kontrola dostępu zajmuje 1. miejsce w OWASP Top 10:2025.

  5. Zwracaj tylko te pola, których klient potrzebuje, aby odpowiedź API nie ujawniała wewnętrznych identyfikatorów, hashy haseł ani danych innych użytkowników.

  6. Wysyłaj klientom ogólne komunikaty błędów, a szczegóły loguj po stronie serwera przy użyciu strukturalnego loggera, takiego jak Pino. Uruchamiaj Express z NODE_ENV=production, aby stack trace'y nie trafiały do odpowiedzi.

  7. Usuń nieużywane trasy i endpointy, bo nieutrzymywany kod to nieobserwowana powierzchnia ataku.

Najważniejsze wnioski

  • Node.js ufa każdemu pakietowi, który uruchamia, więc kontrola zależności to twoja pierwsza warstwa bezpieczeństwa.

  • npm audit wykrywa znane podatności, a nie świeżo przejęte wydania; używaj lockfile'i i opóźnienia wdrażania nowych wydań.

  • Haszuj hasła za pomocą Argon2id lub scrypt, obu dostępnych w nowoczesnym Node.js; używaj asynchronicznych API.

  • MFA i passkeys robią dla bezpieczeństwa logowania więcej niż reguły złożoności haseł.

  • W Node.js jedno kosztowne żądanie może zablokować cały proces, dlatego limity liczby i rozmiaru żądań są niezbędne.

Od czego zespół powinien zacząć pracę nad bezpieczeństwem w Node.js?

Zacznij od zabezpieczeń, które blokują najczęstsze ścieżki prowadzące do naruszeń: wspieranej wersji Node.js, instalacji opartych na lockfile'ach z opóźnieniem wdrażania nowych wydań, MFA i prawidłowego haszowania haseł oraz limitów liczby żądań na endpointach logowania i publicznych. Następnie przejdź trasę po trasie przez walidację, nagłówki i kontrolę dostępu. Bezpieczeństwo w Node.js to stałe utrzymanie, więc włącz te kontrole do code review i CI, zamiast traktować je jak jednorazowy audyt.

Jeśli chcesz, by doświadczony zespół przejrzał istniejącą bazę kodu Node.js albo zbudował nową aplikację internetową z tymi zabezpieczeniami wdrożonymi od pierwszego sprintu, Monterail może pomóc. Skontaktuj się z nami, aby omówić twoją aplikację i związane z nią ryzyka.

FAQ dotyczące bezpieczeństwa Node.js

Zurab Iashvilli avatar.
Zura Iashvili
Senior Node.js Developer
Linkedin
Senior Node.js Developer with a strong track record in backend architecture, scalable systems design, and high-impact API integrations. Specializes in building robust infrastructure that supports growth, reliability, and clean operational workflows. Experienced with microservices, event-driven systems, and modern tooling across the Node.js ecosystem.