Bezpečnostní zásady v PHP kódu: prevence zranitelností

Bezpečnostní zásady v PHP kódu: Prevence zranitelností

Proč bezpečnost v PHP není jen otázkou frameworku

PHP pohání významnou část webu a jeho bezpečnost stojí na třech pilířích: správném návrhu (modelování hrozeb a bezpečnostní architektura), bezpečné implementaci (obrana na všech vrstvách: vstup → logika → výstup) a provozní disciplíně (konfigurace, aktualizace, monitoring). Bez ohledu na použitý framework (Laravel, Symfony, Nette, Slim aj.) platí, že musíte chránit hranice systému, data, identitu uživatele i integritu běhového prostředí.

Validace vstupů a normalizace dat

Vstup (HTTP parametry, JSON, hlavičky, cookies, uploady) je třeba považovat za nedůvěryhodný. Používejte whitelist validaci (formát, rozsah, délka, povolené znaky) a normalizaci (oříznutí mezer, kanonikalizaci) před dalším zpracováním. Nikdy se nespoléhejte na validaci na straně klienta.

  • Pro strukturovaná data využijte filter_var(), validační knihovny (např. symfony/validator) a vlastní pravidla.
  • Pro identifikátory používejte pevné datové typy (int, uuid), nikoli neomezený string.
  • Neakceptujte další pole v JSON (proti „mass assignment“ používejte explicitní mapování povolených atributů).

Bezpečný výstup a prevence XSS

Cross-Site Scripting vzniká, když neescapovaný vstup skončí v HTML, JavaScriptu, CSS či URL. Zásady:

  • Kontextové escapování: HTML, atribut, URL, JavaScript, CSS – každý kontext má jiná pravidla.
  • Zapněte automatické escapování v šablonách (Twig/Blade/Latte) a ručně escapujte dynamické části v JS (json_encode($data, JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT)).
  • Omezte inline skripty a použijte Content-Security-Policy (CSP) s nonce (Content-Security-Policy: script-src 'self' 'nonce-...').
  • Rich text sanitizujte pomocí whitelistu (např. HTML Purifier) – nikdy nepouštějte nezpracované HTML.

SQL Injection a práce s databází

Všechny dotazy sestavujte pomocí prepared statements (PDO, Doctrine DBAL, Eloquent) s parametrizací. Nikdy nevkládejte vstup přímo do řetězce SQL.

  • Používejte PDO::prepare() a bindValue() s odpovídajícími typy; vypněte emulované prepared statements (PDO::ATTR_EMULATE_PREPARES = false).
  • U ORM zajistěte, aby query builder parametrizoval klauzule; dynamické názvy sloupců validujte proti whitelistu.
  • Rozdělte role databázových uživatelů (pro reporting pouze SELECT, pro uživatele aplikace minimální oprávnění).

Ochrana CSRF a správa relací

Proti Cross-Site Request Forgery se brání pomocí CSRF tokenů v požadavcích měnících stav (POST/PUT/PATCH/DELETE). Doporučení:

  • Generujte kryptograficky silné tokeny (random_bytes(), bin2hex()) vázané na session; ověřujte je a používejte jednorázově (rotace).
  • Nastavte cookies na HttpOnly, Secure a SameSite=Lax/Strict podle kontextu.
  • Po přihlášení vždy vygenerujte nové ID session (session_regenerate_id(true)) – tím zabráníte fixation.
  • U API upřednostňujte bearer tokeny v hlavičce Authorization; u SPA zvažte token typu double-submit nebo strategii SameSite.

Ověřování, autorizace a správa hesel

Bezpečné nakládání s hesly a řízení přístupu jsou klíčové:

  • Hesla ukládejte pomocí password_hash() (přednostně Argon2id nebo bcrypt) a ověřujte pomocí password_verify(). Pro opětovné zahashování při migraci používejte password_needs_rehash().
  • Omezujte počet pokusů o přihlášení, po několika pokusech účet uzamkněte, auditujte přihlášení a používejte MFA (TOTP/WebAuthn).
  • Autorizaci implementujte podle principu deny-by-default, pomocí RBAC/ABAC a kontrol v kontrolerech i na úrovni dotazů (dotazy omezené rozsahem).
  • Pro časové porovnávání tokenů a otisků používejte hash_equals() (ochrana proti časovacím útokům).

Bezpečné nahrávání souborů a práce s cestami

Nahrané soubory představují vysoké riziko:

  • Ukládejte je mimo webroot a zpřístupňujte prostřednictvím kontroleru; při veřejném poskytování nastavte striktní Content-Type/Disposition.
  • Ověřujte MIME (na straně serveru), velikost a typ; generujte nové názvy a strukturu adresářů.
  • Zabraňte RCE a path traversal: nikdy nepracujte s cestami zadanými uživatelem, používejte basename(), mapujte ID na cestu a blokujte .. i nulové bajty.
  • Obrázky a mediální soubory zpracovávejte pomocí bezpečných knihoven; externí binární soubory nespouštějte bez whitelistu argumentů.

Deserializace, eval a vzdálená volání

Vyhněte se nebezpečným funkcím (eval, assert s řetězcem, unserialize nad nedůvěryhodnými daty). Pokud musíte deserializovat, používejte unserialize($data, ['allowed_classes' => false]), nebo ještě lépe JSON s explicitním mapováním. Volání SOAP/RPC a webhooky ověřujte pomocí podepsaných požadavků a nastavujte striktní timeouty.

SSRF, otevřené přesměrování a bezpečná práce s URL

Ověřujte a omezujte externí požadavky:

  • Používejte whitelist domén/hostitelů a zakažte interní rozsahy IP adres (169.254.0.0/16, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16, link-local IPv6).
  • Po přesměrování znovu proveďte DNS překlad a kontrolujte schémata (pouze https).
  • Při přesměrování na základě uživatelských parametrů používejte relativní cesty nebo mapu aliasů; jinak hrozí phishing (open redirect).

Bezpečná kryptografie

Neimplementujte vlastní šifrování. Používejte libsodium (sodium_crypto_aead_xchacha20poly1305_ietf_*) nebo openssl_encrypt s AEAD (AES-GCM). Klíče ukládejte mimo repozitář (env, správce tajných údajů), pravidelně je měňte a omezte přístup k nim. Pro náhodná data používejte random_bytes(), nikoli mt_rand().

HTTP hlavičky a ochrana prohlížeče

Správná sada hlaviček zvyšuje základní úroveň zabezpečení:

  • Strict-Transport-Security (HSTS), vynucení HTTPS.
  • Content-Security-Policy (CSP) s nonce nebo hashi, X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy.
  • Frame-Ancestors (v CSP) jako ochrana proti clickjackingu.

Chybové stavy, logování a informace poskytované navenek

V produkci vypněte vypisování chyb do výstupu a bezpečně je zaznamenávejte:

  • display_errors = Off, log_errors = On, vlastní handler, korelační request-id.
  • Nikdy nezaznamenávejte tajné údaje (hesla, tokeny, klíče). Maskujte osobní údaje podle GDPR.
  • Uživatelům zobrazujte obecné chybové stránky; podrobnosti ukládejte pouze do logů/nástrojů observability (Sentry, ELK, OpenTelemetry).

Konfigurace PHP a zabezpečení prostředí

Bezpečné výchozí nastavení výrazně sníží riziko:

  • expose_php = Off, allow_url_fopen = Off (pokud není nutné), allow_url_include = Off.
  • Omezte file_uploads a velikost souborů (upload_max_filesize, post_max_size), max_input_vars a nastavte rozumné timeouty (max_execution_time, default_socket_timeout).
  • Na úrovni serveru zajistěte izolaci účtů (FPM pool pro každou aplikaci, chroot/kontejnery), kód nastavte jako read-only a oddělte adresáře var/, tmp/ s příznakem noexec.

Závislosti, dodavatelský řetězec a aktualizace

Composer je mocný nástroj, ale vyžaduje disciplínu:

  • Uzamkněte verze (composer.lock v repozitáři), sledujte bezpečnostní upozornění a pravidelně aktualizujte (Dependabot, Renovate).
  • Používejte pouze důvěryhodné balíčky, omezte jejich počet na minimum a auditujte skripty v composer.json (sekce scripts).
  • V produkci zapněte autoload-classmap authoritative pro vyšší výkon a determinismus.

Zabezpečení API: JWT, cookies a CORS

Při použití JWT v API dbejte na:

  • Krátkou dobu platnosti (minuty), podpis HS256/RS256 se správou klíčů, kontrolu audience/issuer a ověřování kid proti podvržení.
  • Nevkládejte do payloadu citlivá data; JWT je pouze base64url, nejde o šifrování.
  • CORS: explicitní Access-Control-Allow-Origin (bez *, pokud se používají přihlašovací údaje), povolené metody/hlavičky; nikdy nenastavujte Access-Control-Allow-Credentials: true spolu s *.

Výkon vs. bezpečnost: omezení počtu požadavků a ochrana proti hrubé síle

Implementujte ochranu proti zneužití:

  • Omezování počtu požadavků (token bucket, Redis) u citlivých endpointů (přihlášení, reset hesla, odesílání e-mailů).
  • Detekujte anomálie (neplatné tokeny, neobvyklé geografické oblasti), používejte šedé listiny a dynamickou captcha aktivujte až po překročení prahu.

Bezpečnostní testování a CI/CD

Začleňte zabezpečení do pipeline:

  • Statická analýza (PHPStan/Psalm) s bezpečnostními pravidly, lintování šablon (porušení CSP, neescapované bloky).
  • Skenerům SAST/DAST, auditu závislostí (roave/security-advisories) a unit/integration testům pro scénáře autorizace.
  • Kontrola tajných údajů (Git hooks, CI) a ochrana pre-commit; podepisování releasů, SBOM (CycloneDX).

Šablonovací systémy a bezpečnost v praxi

Upřednostňujte šablonovací systémy s automatickým escapováním (Twig/Latte/Blade). Zakazujte libovolné spouštění kódu v šablonách, oddělte prezentační a aplikační logiku a používejte komponenty namísto přímého výpisu pomocí raw echo. V e-mailových šablonách vždy escapujte a ověřujte URL.

Víceinstanční (multi-tenant) aplikace

Důsledně vynucujte tenant scoping v každém dotazu (WHERE tenant_id = ?), ověřujte přístupové tokeny na úrovni tenanta a izolujte úložiště i klíče cache (tenant:<id>:* ). Zabraňte insecure direct object references (IDOR) – nikdy nepoužívejte sekvenční ID bez kontroly vlastnictví.

Monitoring, audit a reakce na incidenty

Kromě logů sledujte metriky (latence, chybovost, 4xx/5xx), bezpečnostní události (přihlášení, změny oprávnění, administrace) a upozornění. Připravte si runbooky pro reset tokenů, rotaci klíčů a vynucené odhlášení. Pravidelně zálohujte a testujte obnovu.

Checklist minimálních opatření

  • Prepared statements všude; žádné dynamické SQL bez whitelistu.
  • Automatické escapování šablon + CSP s nonce.
  • Session: Secure, HttpOnly, SameSite; regenerace po přihlášení; CSRF tokeny.
  • Hesla: password_hash() (Argon2id/bcrypt), omezení počtu pokusů o přihlášení, MFA.
  • Nahrané soubory mimo webroot, validace MIME, nové názvy, žádné spouštění.
  • Bezpečná konfigurace PHP a webového serveru; logování bez tajných údajů.
  • Aktualizace závislostí, audit balíčků, SAST v CI.

Závěr: bezpečnost jako nepřetržitý proces

Bezpečnost PHP aplikací není jednorázový úkol, ale soustava návyků a automatizovaných kontrol. Kombinací kontextového escapování, striktní validace, minimálních oprávnění, bezpečné kryptografie, správně nastavených hlaviček a provozní disciplíny vytvoříte kód, který odolá běžným útokům a bude se lépe škálovat i auditovat. Standardizujte postupy v týmu, začleňte je do CI/CD a pravidelně je testujte v praxi.