Przejdź do treści
← wszystkie przedmioty

Bezpieczeństwo aplikacji (AppSec): OWASP Top 10 w praktyce

Praktyczny przegląd OWASP Top 10: wstrzyknięcia, XSS, CSRF, IDOR, SSRF, deserializacja, supply chain i hashowanie haseł, z kodem i obroną w głąb dla inżynierów.

TEMATY EGZAMINACYJNE W TYM PRZEDMIOCIE
  • Parametryzowane zapytania jako jedyna niezawodna obrona przed SQL Injection
  • Kontekstowe enkodowanie wyjścia i strict CSP z nonce przeciw XSS
  • CSRF: token + SameSite jako obrona w głąb, także na endpointach przed logowaniem
  • Weryfikacja właściciela zasobu przy każdym żądaniu jako obrona przed IDOR
  • Argon2id/bcrypt do haseł, nigdy MD5/SHA - zasada least privilege wszędzie
  • SSRF: walidacja adresu IP po rezolucji DNS, blokada endpointów metadanych chmury

1 · Wstrzyknięcia: SQL, Command i NoSQL Injection

★ egzamin

Wstrzyknięcie (injection) figuruje w OWASP Top 10:2025 jako kategoria A05 i pozostaje jednym z najgroźniejszych błędów: dane wejściowe użytkownika trafiają do interpretera (SQL, powłoki systemowej, silnika NoSQL) i zostają wykonane jako kod zamiast być traktowane jako dane. Skutek: pełny odczyt/zapis bazy, zdalne wykonanie kodu, przejęcie serwera.

Zasada nadrzędna
Parametryzowane zapytania (prepared statements) to jedyna niezawodna obrona przy SQL. Walidacja wejścia to dodatkowa warstwa, nie zamiennik.
Termin kluczowy
SQL Injection - Wstrzyknięcie fragmentu SQL przez niesparametryzowane dane wejściowe, pozwalające zmienić logikę zapytania (np. ominąć WHERE, dołączyć UNION SELECT, wywołać podzapytania administracyjne).
Termin kluczowy
Command Injection - Wstrzyknięcie poleceń powłoki systemowej przez dane przekazywane do funkcji uruchamiających procesy (os.system, exec, subprocess z shell=True), gdy budowane są jako string zamiast listy argumentów.
Termin kluczowy
NoSQL Injection - Wstrzyknięcie operatorów zapytań (np. $where, $ne, $gt w MongoDB) przez niekontrolowane obiekty JSON, pozwalające ominąć uwierzytelnienie lub wykonać dowolny JavaScript po stronie bazy.
Pułapka
Częsty błąd: deweloper 'sparametryzował' zapytanie, ale kolumnę w ORDER BY lub nazwę tabeli nadal wstawia przez f-string, bo 'parametrów tam nie da się użyć'. To wciąż SQL injection, tylko w innym miejscu zapytania - rozwiązanie to whitelisting dozwolonych nazw kolumn/tabel, nigdy interpolacja.
SQL: niebezpieczne vs parametryzowane zapytanie python
# NIEBEZPIECZNE: konkatenacja stringów
query = f"SELECT * FROM users WHERE email = '{email}'"
cursor.execute(query)  # email = "' OR '1'='1" omija filtr

# BEZPIECZNE: parametryzowane zapytanie, driver escapuje wartość
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (email,),
)
Command Injection: unikanie powłoki python
import subprocess

# NIEBEZPIECZNE: shell=True + interpolacja
subprocess.run(f"convert {filename} output.png", shell=True)

# BEZPIECZNE: lista argumentów, brak powłoki
subprocess.run(["convert", filename, "output.png"], shell=False, check=True)
NoSQL Injection: MongoDB javascript
// NIEBEZPIECZNE: obiekt z request.body trafia bezpośrednio do query
db.users.findOne({ username: req.body.username, password: req.body.password });
// atak: password = { "$ne": null } omija uwierzytelnienie

// BEZPIECZNE: wymuszenie typu string przed budową zapytania
const username = String(req.body.username);
const password = String(req.body.password);
db.users.findOne({ username, password: hash(password) });
  • Zawsze używaj parametryzowanych zapytań lub bezpiecznych metod ORM, nigdy raw query ze sklejaniem stringów
  • Konto bazodanowe aplikacji ma mieć minimalne uprawnienia (least privilege), nie prawa administratora
  • Nazwy kolumn/tabel w ORDER BY, LIMIT i podobnych miejscach: whitelist, nie interpolacja
  • Wyłącz niebezpieczne funkcje silnika bazy (np. xp_cmdshell w SQL Server)
  • Nigdy nie zwracaj surowego błędu SQL do klienta - ujawnia strukturę bazy
Mnemonik
Dane to dane, kod to kod: user input nigdy nie powinien zmieniać struktury zapytania, tylko jego wartości.

2 · Broken Authentication i zarządzanie sesją

★ egzamin

Błędy uwierzytelniania i zarządzania sesją (OWASP A07: Authentication Failures) prowadzą do przejęcia konta bez znajomości hasła: przewidywalne tokeny sesji, brak wygasania, brak rotacji po zmianie uprawnień.

ASVS 5.0, poziom L1
Token sesji wymaga min. 128 bitów entropii, generowany kryptograficznie bezpiecznym generatorem liczb losowych, nigdy z Math.random() ani sekwencyjnego licznika.
Termin kluczowy
Session Fixation - Atakujący narzuca ofierze znany identyfikator sesji (np. przez link z ?sessionid=), a po zalogowaniu ofiary przejmuje tę samą sesję, bo aplikacja nie regeneruje ID po uwierzytelnieniu.
Termin kluczowy
Broken Session Management - Sesje, które nie wygasają, nie są unieważniane po wylogowaniu, lub pozostają aktywne po zmianie hasła czy uprawnień użytkownika.
Pułapka
Częsty błąd: token sesji jest unieważniany tylko po stronie klienta (usunięcie ciasteczka), a serwer nadal go akceptuje - atakujący z przechwyconym tokenem ma dostęp mimo 'wylogowania' ofiary.
Regeneracja ID sesji po logowaniu (Flask) python
from flask import session, current_app

@app.route("/login", methods=["POST"])
def login():
    user = authenticate(request.form["email"], request.form["password"])
    if user is None:
        abort(401)

    session.clear()
    current_app.session_interface.regenerate(session)  # rotates the actual session ID (Flask-Session); session.clear() alone only empties the payload, it does not fix a pre-login session ID
    session["user_id"] = user.id
    session["issued_at"] = time.time()
    return redirect("/dashboard")
Wygasanie sesji i invalidacja po stronie serwera python
SESSION_TTL_SECONDS = 30 * 60

def is_session_valid(session: dict) -> bool:
    if "user_id" not in session:
        return False
    if time.time() - session["issued_at"] > SESSION_TTL_SECONDS:
        return False
    return session["user_id"] not in revoked_user_ids  # server-side revocation list
  • Wymuszaj MFA dla operacji wrażliwych (ASVS L2)
  • Sprawdzaj hasła wobec list wycieków (np. Have I Been Pwned range API)
  • Rate-limiting na endpointach logowania, blokada po N nieudanych próbach
  • Unieważniaj wszystkie sesje/tokeny po zmianie hasła lub usunięciu z organizacji
  • Ciasteczko sesji: HttpOnly, Secure, SameSite - nigdy w localStorage

Sesja stanowa (server-side)

  • Łatwa natychmiastowa rewokacja
  • Wymaga magazynu (Redis/DB)
  • Domyślnie bezpieczniejsza dla wrażliwych operacji

JWT bezstanowy

  • Brak zapytania do bazy przy każdej weryfikacji
  • Rewokacja wymaga blacklisty/jti + krótkiego TTL
  • Ryzyko: alg confusion, przechowywanie w localStorage
Mnemonik
Nowa sesja przy każdej zmianie stanu uprzywilejowania: logowanie, zmiana hasła, zmiana roli - zawsze session.clear() lub rotacja tokenu.

3 · XSS: Stored, Reflected, DOM i kontekstowe enkodowanie

★ egzamin

XSS (Cross-Site Scripting) pozwala atakującemu wykonać dowolny JavaScript w przeglądarce ofiary w kontekście zaufanej domeny: kradzież ciasteczek sesji, keylogging, podmiana treści, ataki na innych użytkowników.

Trzy warianty
Stored: payload zapisany w bazie i serwowany innym użytkownikom. Reflected: payload w parametrze URL odbity natychmiast w odpowiedzi. DOM-based: payload nigdy nie trafia na serwer, wykonuje się przez manipulację DOM po stronie klienta (np. innerHTML z location.hash).
Termin kluczowy
Stored XSS - Złośliwy skrypt trwale zapisany w bazie danych (np. w komentarzu, opisie profilu) i renderowany bez enkodowania każdemu użytkownikowi odwiedzającemu stronę - najgroźniejszy wariant, bo skaluje się automatycznie.
Termin kluczowy
DOM-based XSS - Podatność istnieje wyłącznie w kodzie JavaScript po stronie klienta: dane ze źródła kontrolowanego przez atakującego (location.hash, document.referrer, postMessage) trafiają do zlewu (innerHTML, eval, document.write) bez przejścia przez serwer.
Pułapka
Częsty błąd: developerzy sanitują dane przy zapisie do bazy, ale ten sam string renderowany jest w trzech różnych kontekstach (HTML, atrybut, JavaScript inline) - enkodowanie musi być kontekstowe przy wyjściu (output encoding), nie jednorazowe przy wejściu.
React: domyślne escapowanie vs świadome ominięcie tsx
// BEZPIECZNE: JSX escapuje automatycznie przy renderze
function Comment({ text }: { text: string }) {
  return <p>{text}</p>;
}

// NIEBEZPIECZNE: świadome wyłączenie escapowania bez sanitizacji
function CommentUnsafe({ html }: { html: string }) {
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

// BEZPIECZNE, gdy HTML jest wymagany: sanitizacja przez DOMPurify
import DOMPurify from "dompurify";
function CommentRichText({ html }: { html: string }) {
  const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ["b", "i", "a"] });
  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}
Content-Security-Policy: strict nonce zamiast allowlisty domen http
Content-Security-Policy:
  script-src 'nonce-{RANDOM_PER_REQUEST}' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
Kontekst wyjściaRodzaj enkodowaniaPrzykład
HTML bodyHTML entity encode< -> &lt;, > -> &gt;
Atrybut HTMLHTML attribute encode + cudzysłów" -> &quot;
JavaScript inlineJS string escape, nigdy wstawianie surowego stringu' -> \'
URL/query stringURL encode (percent-encoding)spacja -> %20
CSSCSS escapeznaki specjalne jako \XX
  • Włącz strict CSP z nonce per-request zamiast allowlisty domen (allowlista jest łamliwa i rozrasta się do setek hostów)
  • Nagłówki: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin
  • SVG upload może zawierać <script> - traktuj jak HTML, nie jak obraz
  • Loguj naruszenia CSP przez report-to/report-uri
Mnemonik
Escapuj przy wyjściu, w kontekście, w którym dane wylądują - nie raz przy wejściu na wszelki wypadek.

4 · CSRF i obrona SameSite

★ egzamin

CSRF zmusza przeglądarkę ofiary, zalogowanej w aplikacji, do wysłania niezamierzonego żądania (np. zmiana hasła, przelew): przeglądarka automatycznie dołącza ciasteczka sesji do żądania z dowolnej domeny, więc serwer widzi je jako 'uwierzytelnione'.

Zasada
Każdy endpoint zmieniający stan (POST/PUT/PATCH/DELETE oraz każdy GET, który zmienia stan - co jest błędem samo w sobie) wymaga ochrony CSRF, włącznie z endpointami przed logowaniem: login, rejestracja, reset hasła.
Termin kluczowy
Login CSRF - Atakujący wymusza zalogowanie ofiary na konto kontrolowane przez atakującego, np. by śledzić późniejszą aktywność ofiary w kontekście cudzego konta - często pomijane, bo 'to przecież nie zmienia danych ofiary'.
Termin kluczowy
Double-submit cookie - Wzorzec obrony: token CSRF wysyłany jednocześnie w ciasteczku i w nagłówku/body żądania; serwer odrzuca żądanie, jeśli wartości się nie zgadzają - działa bez serwerowego magazynu tokenów.
Pułapka
Częsty błąd: walidacja tokenu CSRF jest 'opcjonalna', gdy token jest pusty (np. stare klienty API) - brak tokenu musi zawsze oznaczać odrzucenie żądania, nigdy przepuszczenie.
SameSite jako warstwa obrony w głąb http
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
Middleware CSRF w Flask (flask-wtf) python
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
csrf = CSRFProtect(app)  # wymusza token na każdym POST/PUT/PATCH/DELETE

@app.route("/account/email", methods=["POST"])
def change_email():
    # token walidowany automatycznie przez CSRFProtect przed wejściem tutaj;
    # brak/zły token -> 400 Bad Request
    ...

SameSite=Strict

  • Ciasteczko nigdy nie wysyłane cross-site
  • Najwyższe bezpieczeństwo
  • Może zepsuć nawigację z linków zewnętrznych (np. e-mail -> zalogowana strona)

SameSite=Lax

  • Ciasteczko wysyłane przy nawigacji top-level (kliknięcie linku)
  • Dobry kompromis, częste zachowanie domyślne
  • Nadal wymaga tokenu CSRF dla pełnej ochrony
  • SameSite to warstwa dodatkowa, nie zamiennik tokenu CSRF
  • Nadmiernie permisywny CORS (Access-Control-Allow-Origin: *) z Allow-Credentials potrafi obejść SameSite
  • Nie wstawiaj tokenu CSRF do URL - używaj nagłówka, np. X-CSRF-Token
  • Regeneruj token po zmianie stanu uwierzytelnienia
Mnemonik
Brak tokenu = odrzucone żądanie, zawsze, bez wyjątków 'na razie'.

5 · Niebezpieczna deserializacja

Deserializacja niezaufanych danych pozwala atakującemu skonstruować obiekt, którego proces odtwarzania (deserializacji) wykonuje dowolny kod, zanim aplikacja zdąży cokolwiek zwalidować. Klasyczny przykład: pickle w Pythonie, ObjectInputStream w Javie, unserialize() w PHP.

Dlaczego to groźne
W przeciwieństwie do XSS czy SQLi, atak trafia zanim dane trafią w ręce logiki biznesowej - często wystarczy jeden request HTTP ze złośliwym payloadem serializowanym.
Termin kluczowy
Gadget chain - Łańcuch istniejących w aplikacji klas, których metody (np. __reduce__, readObject) wywoływane są automatycznie przy deserializacji, złożone tak, by ich efekt uboczny uruchomił dowolny kod atakującego.
Pułapka
Częsty błąd: deweloper używa pickle.loads() do 'wygodnego' cache'owania obiektów Pythona w Redis/na dysku, zapominając że Redis/dysk mogą być zapisywalne przez inny, mniej zaufany komponent systemu - pickle nie ma trybu bezpiecznego dla danych z zewnątrz.
pickle: niebezpieczne vs bezpieczna alternatywa python
import pickle, json

# NIEBEZPIECZNE: deserializacja niezaufanych danych wykonuje dowolny kod
data = pickle.loads(untrusted_bytes_from_request)

# BEZPIECZNE: format danych bez wykonywalnego kodu
data = json.loads(untrusted_bytes_from_request)
Java: whitelisting klas przy deserializacji java
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
    "com.app.model.*;!*"  // dozwolone tylko klasy z com.app.model, reszta odrzucona
);
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);
  • Preferuj formaty bez wykonywalnego kodu: JSON, Protocol Buffers, MessagePack
  • Jeśli deserializacja obiektów jest konieczna: podpisuj serializowane dane (HMAC) i weryfikuj podpis przed deserializacją
  • Whitelisting dozwolonych klas/typów zamiast blacklisty
  • Izoluj proces deserializujący (sandbox, brak uprawnień sieciowych/systemowych)
Powiązanie z supply chain
Ataki na deserializację często wykorzystują 'gadgety' z bibliotek trzecich obecnych w classpath/site-packages - kolejny powód do audytu zależności.
Mnemonik
Jeśli format danych umie wywołać kod przy odczycie, traktuj go jak kod, nie jak dane.

6 · Security Misconfiguration i SSRF

★ egzamin

Security Misconfiguration (OWASP A02) to najczęstsza kategoria luk w praktyce: domyślne hasła, włączony debug w produkcji, niepotrzebne usługi, brak nagłówków bezpieczeństwa. SSRF (Server-Side Request Forgery) to jej niebezpieczny szczególny przypadek: serwer wykonuje żądanie HTTP do adresu kontrolowanego przez atakującego.

OWASP 2025
W Top 10:2025 SSRF został włączony do kategorii A01 (Broken Access Control) jako przypadek łamania granic zaufania serwera, ale w praktyce traktuje się go jako odrębną klasę podatności ze względu na specyficzne wektory (webhooki, generatory PDF, import z URL).
Termin kluczowy
SSRF - Podatność, w której serwer aplikacji wykonuje żądanie sieciowe pod adres URL dostarczony lub wpływany przez użytkownika, pozwalając dosięgnąć zasoby wewnętrzne (metadata API chmury, bazy danych, panele admina) niedostępne z zewnątrz.
Termin kluczowy
Cloud metadata endpoint - Wewnętrzny adres (np. 169.254.169.254) udostępniający tymczasowe poświadczenia instancji chmurowej - klasyczny cel SSRF, bo zwraca klucze IAM/role bez uwierzytelnienia.
Pułapka
Częsty błąd: filtr URL blokuje 'localhost' i '127.0.0.1' jako stringi, ale nie łapie zapisu dziesiętnego (2130706433), oktalnego (0177.0.0.1) ani DNS rebinding - walidacja musi się odbywać po rozwiązaniu DNS, na faktycznym adresie IP.
SSRF: walidacja adresu IP po rezolucji DNS python
import ipaddress
import socket
from urllib.parse import urlparse

def is_safe_url(url: str) -> bool:
    parsed = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        return False

    ip = socket.gethostbyname(parsed.hostname)  # rozwiąż DNS PRZED walidacją
    addr = ipaddress.ip_address(ip)
    if addr.is_private or addr.is_loopback or addr.is_link_local:
        return False  # blokuje też 169.254.169.254 (metadata endpoint)
    return True
Misconfiguration: wyłączenie listowania katalogów i banera wersji nginx
server {
    autoindex off;                 # brak listowania katalogów
    server_tokens off;             # ukryj wersję Nginx w nagłówku Server
    location /admin { deny all; }  # panel admina niedostępny z zewnątrz
}
Błąd konfiguracjiKonsekwencjaPoprawka
Tryb debug włączony w produkcjiStack trace ujawnia ścieżki, wersje, czasem sekretyDEBUG=False w produkcji, generyczne strony błędów
Domyślne konto/hasło adminaNatychmiastowy dostęp administracyjnyWymuszona zmiana hasła przy pierwszym uruchomieniu
Nadmiarowe uprawnienia CORS (*)Dowolna domena czyta odpowiedzi APIAllowlist konkretnych originów
Brak limitu przekierowań w kliencie HTTPSSRF przez łańcuch redirectów do zasobu wewnętrznegoLimit/walidacja każdego przeskoku redirecta
  • Allowlist domen docelowych zamiast blacklisty adresów wewnętrznych
  • Ogranicz timeout i rozmiar odpowiedzi przy żądaniach wychodzących
  • Segmentacja sieci: serwis pobierający URL-e działa bez dostępu do sieci wewnętrznej
  • Regularny przegląd konfiguracji przez checklisty (CIS Benchmarks, OWASP ASVS)
Mnemonik
Zaufanie do URL kończy się na scheme http/https - adres IP zawsze sprawdzaj po rezolucji, nie po stringu.

7 · Broken Access Control (IDOR) i zasada najmniejszych uprawnień

★ egzamin

Broken Access Control to od lat #1 kategoria OWASP Top 10 pod względem częstości występowania. IDOR (Insecure Direct Object Reference) to jego najczęstszy podtyp: aplikacja ufa identyfikatorowi zasobu podanemu przez klienta, zamiast weryfikować, czy zalogowany użytkownik ma prawo do tego zasobu.

Zasada nadrzędna
Autoryzacja weryfikowana na poziomie danych (per-request), nie tylko na poziomie routingu - middleware chroniący ścieżkę /admin nie chroni przed dostępem do cudzego zasobu pod /api/orders/{id}.
Termin kluczowy
IDOR - Bezpośrednie odwołanie do obiektu (np. /api/invoices/1042) bez weryfikacji, czy zalogowany użytkownik jest właścicielem zasobu o tym identyfikatorze - zmiana ID w URL ujawnia cudze dane.
Termin kluczowy
Horizontal vs Vertical Privilege Escalation - Eskalacja pozioma: użytkownik A uzyskuje dostęp do danych użytkownika B na tym samym poziomie uprawnień. Eskalacja pionowa: zwykły użytkownik uzyskuje funkcje administratora.
Termin kluczowy
Least Privilege - Każdy komponent (konto bazodanowe, rola użytkownika, klucz API, proces) otrzymuje wyłącznie minimalny zestaw uprawnień niezbędny do realizacji swojej funkcji, nic więcej 'na zapas'.
Pułapka
Częsty błąd: sekwencyjne ID (1, 2, 3...) w publicznym API ułatwiają enumerację zasobów - nawet z poprawną autoryzacją to informacja wywiadowcza (liczba zamówień, tempo wzrostu firmy); UUIDv4 to obrona w głąb, nie zamiennik autoryzacji.
Weryfikacja własności zasobu na poziomie danych (Flask) python
@app.route("/api/invoices/<invoice_id>")
@login_required
def get_invoice(invoice_id):
    invoice = db.get_invoice(invoice_id)

    if invoice is None:
        abort(404)  # nie ujawniaj, czy zasób istnieje

    if invoice.owner_id != current_user.id and not current_user.is_admin:
        abort(404)  # 404, nie 403 - utrudnia enumerację zasobów

    return jsonify(invoice.to_dict())
Least privilege: konto aplikacji bez uprawnień DDL sql
-- Konto aplikacji: tylko operacje na danych, zero uprawnień strukturalnych
CREATE ROLE app_user LOGIN PASSWORD '...';
GRANT SELECT, INSERT, UPDATE, DELETE ON orders, invoices TO app_user;
REVOKE ALL ON SCHEMA public FROM app_user;  -- brak DROP/ALTER/CREATE
  • Weryfikuj właściciela zasobu przy KAŻDYM żądaniu, nie polegaj na tym, że UI 'nie pokazuje' cudzych danych
  • Sprawdzaj też zasoby nadrzędne (np. komentarz -> post -> właściciel posta)
  • Re-waliduj uprawnienia po każdej zmianie roli/organizacji
  • Konta serwisowe i klucze API: osobne, wąskie zakresy (scopes) zamiast jednego klucza z pełnym dostępem
Mnemonik
ID w URL to wskazówka klienta, nie dowód uprawnień - serwer sprawdza właściciela zawsze, niezależnie od tego, co przyszło z frontendu.

8 · Supply chain, zarządzanie sekretami i hashowanie haseł

★ egzamin

Nowoczesna aplikacja to w 80-90% kod cudzy: zależności npm/pip/cargo. OWASP A03:2025 (Software Supply Chain Failures) i A04 (Cryptographic Failures) obejmują ryzyko podatnych zależności oraz błędy w przechowywaniu sekretów i haseł - trzy różne problemy, jedna przyczyna: ślepe zaufanie do tego, co 'zawsze tak było'.

SBOM
Software Bill of Materials to pełna, maszynowo czytelna lista zależności (bezpośrednich i przechodnich) wraz z wersjami - podstawa do automatycznego wykrycia, czy dana CVE dotyczy Twojej aplikacji, zanim ktoś zapyta ręcznie.
Termin kluczowy
Dependency confusion - Atak, w którym prywatny pakiet firmowy zostaje podszyty publicznym pakietem o tej samej nazwie i wyższym numerze wersji w publicznym rejestrze - menedżer pakietów instaluje wersję atakującego, jeśli konfiguracja nie wymusza źródła prywatnego.
Termin kluczowy
Argon2id - Argon2 (zwycięzca Password Hashing Competition 2015); jego wariant Argon2id jest dziś rekomendowany przez OWASP/RFC 9106 do hashowania haseł, odporny na ataki GPU/ASIC dzięki kosztowi pamięciowemu (memory-hard), obok bcrypt i scrypt jedyny akceptowalny wybór do przechowywania haseł.
Pułapka
Częsty błąd: 'hashujemy hasła, więc jest bezpiecznie' - MD5 i SHA-256 to funkcje szybkie (miliardy prób/sekundę na GPU), zaprojektowane do integralności danych, nie do haseł; do haseł tylko funkcje celowo wolne i pamięciochłonne: Argon2id, bcrypt, scrypt.
Hashowanie haseł: niebezpieczne vs poprawne python
import hashlib
from argon2 import PasswordHasher

# NIEBEZPIECZNE: szybki hash bez soli, łamany tęczowymi tablicami w sekundy
hashlib.md5(password.encode()).hexdigest()

# BEZPIECZNE: Argon2id, sól generowana automatycznie, koszt pamięciowy wbudowany
ph = PasswordHasher()
hashed = ph.hash(password)           # zapisz `hashed` do bazy
ph.verify(hashed, password_attempt)  # rzuca wyjątkiem przy niezgodności
Audyt zależności i blokada wersji (Python) bash
# Zamroź dokładne wersje przechodnich zależności (powtarzalny build)
pip freeze > requirements.lock.txt

# Skanuj znane CVE w zainstalowanych pakietach
pip install pip-audit && pip-audit
Sekrety: zmienne środowiskowe, nigdy w repo bash
# .env (w .gitignore, NIGDY commitowane)
DATABASE_URL=postgresql://user:pass@host:5432/db
JWT_SECRET=<losowe 256+ bitów>
Aplikacja czyta wyłącznie ze środowiska, nigdy z hardkodowanej stałej python
import os

database_url = os.environ["DATABASE_URL"]
  • Nigdy nie commituj sekretów do repozytorium (nawet w historii - rotacja po wycieku obowiązkowa)
  • NEXT_PUBLIC_*/REACT_APP_* trafiają do bundla klienta - żadnych kluczy prywatnych pod tymi prefiksami
  • Generuj i utrzymuj SBOM (np. przez cyclonedx/syft) dla każdego wydania
  • Automatyczne skanowanie zależności w CI (Dependabot, pip-audit, npm audit) blokujące merge przy krytycznych CVE
  • Least privilege także dla kluczy API: osobny klucz o wąskim zakresie na integrację, nie jeden klucz-wytrych
Mnemonik
Hasło hashuj wolno i z pamięcią (Argon2id/bcrypt), zależność sprawdzaj zanim zaufasz, sekret trzymaj poza kodem, zawsze.
Fiszki - aktywne przypominanie

Sprawdź się - testowanie to nauka

24 pytań w losowej kolejności. Twoje wyniki zapisują się lokalnie.

Rozpocznij quiz
Zbudowane przez Tenzan Logic