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

Proč bezpečnost v PHP není jen o frameworku

PHP pohání významnou část webu a jeho bezpečnost stojí na třech pilířích: správný návrh (threat modeling a bezpečnostní architektura), bezpečná implementace (obrana na všech vrstvách: vstup → logika → výstup) a provozní disciplína (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) musí být považován za nedůvěryhodný. Aplikujte whitelist validace (formát, rozsah, délka, povolené znaky) a normalizaci (trim, canonicalizace) před dalším zpracováním. Nikdy nespoléhejte na klientskou validaci.

  • 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 string bez omezení.
  • Neakceptujte dodatečná 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á odlišná pravidla.
  • Zapněte autoescapová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-...').
  • Sanitizace rich textu přes whitelist (např. HTML Purifier) – nikdy nepouštějte syrové HTML.

SQL Injection a práce s databází

Veškeré dotazy sestavujte pomocí prepared statements (PDO, Doctrine DBAL, Eloquent) s parametrizací. Nikdy neinterpolujte vstup do SQL řetězce.

  • Používejte PDO::prepare() a bindValue() s odpovídajícími typy; deaktivujte emulované prepared statements (PDO::ATTR_EMULATE_PREPARES = false).
  • Pro ORM zajistěte, že query builder parametrizuje klauzule; dynamické názvy sloupců validujte podle whitelistu.
  • Rozdělte role DB uživatelů (např. jen SELECT pro reporting, minimální oprávnění pro aplikační uživatele).

CSRF ochrana a správa relací

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

  • Generujte kryptograficky silné tokeny (random_bytes(), bin2hex()) vázané na session; validujte jednorázově (rotace).
  • Nastavte cookies s atributy HttpOnly, Secure, SameSite=Lax/Strict dle kontextu.
  • Po přihlášení vždy regenerujte session ID (session_regenerate_id(true)) – prevence fixation útoků.
  • U API preferujte bearer tokeny v Authorization hlavičce; pro SPA zvažte double-submit token nebo SameSite strategii.

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

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

  • Hesla ukládejte pomocí password_hash() (preferovaně Argon2id nebo bcrypt) a ověřujte pomocí password_verify(). Používejte password_needs_rehash() pro migrační přehashování.
  • Implementujte rate limit pro přihlášení, uzamykání po několika neúspěšných pokusech, audit přihlášení a vícefaktorovou autentizaci (MFA) (TOTP/WebAuthn).
  • Autorizaci realizujte pomocí principu deny-by-default, RBAC/ABAC s kontrolami v kontrolerech i na úrovni databázových dotazů (scoped queries).
  • Pro bezpečné porovnání tokenů nebo otisků používejte hash_equals() (ochrana proti timing útokům).

Bezpečné nahrávání souborů a správa cest

Nahrané soubory představují vysoké riziko:

  • Ukládejte je mimo webroot a zpřístupňujte pouze přes kontroler; při veřejném servírování nastavte přísné hlavičky Content-Type a Content-Disposition.
  • Validujte MIME typ (server-side), velikost, typ souboru; generujte nové názvy a adresářovou strukturu.
  • Zabraňte RCE a path traversal: nikdy nepracujte s uživatelskými cestami přímo, používejte basename(), mapujte ID→cestu, blokujte .. a nulové bajty.
  • Obrázky a mediální soubory zpracovávejte přes bezpečné knihovny; nespouštějte externí binární soubory bez whitelistu parametrů.

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

Vyhněte se nebezpečným funkcím (eval, assert se stringem, unserialize na nedůvěryhodných datech). Pokud musíte deserializovat, používejte unserialize($data, ['allowed_classes' => false]) nebo raději JSON s explicitním mapováním. SOAP/RPC volání a webhooky validujte podepsanými požadavky a přísnými časovými limity.

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

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

  • Whitelist domén/hostitelů, zákaz interních IP rozsahů (169.254.0.0/16, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16, link-local IPv6).
  • DNS překlad po přesměrování a kontrola povolených schémat (https pouze).
  • U přesměrování z 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 zdrojový kód (např. env proměnné, secret manager), pravidelně je rotujte a omezte přístup. Pro generování náhodných dat používejte random_bytes(), nikoli mt_rand().

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

Správná sada HTTP hlaviček zvyšuje základní bezpečnost:

  • Strict-Transport-Security (HSTS) pro nucení HTTPS.
  • Content-Security-Policy (CSP) s nonce/hashy, 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 ochrana informací

V produkčním prostředí vždy vypněte výpis chyb do výstupu a logujte bezpečně:

  • display_errors = Off, log_errors = On, vlastní handler s korelací request-id.
  • Nikdy nelogujte citlivé informace (hesla, tokeny, klíče). Maskujte osobní údaje (PII) dle GDPR.
  • Uživatelům vracejte generické chybové stránky; detaily zaznamenávejte pouze do logů nebo nástrojů observability (Sentry, ELK, OpenTelemetry).

Konfigurace PHP a hardening prostředí

Bezpečné výchozí nastavení výrazně snižuje rizika:

  • expose_php = Off, allow_url_fopen = Off (pokud není potřeba), allow_url_include = Off.
  • Omezte file_uploads a velikost nahrávaných souborů (upload_max_filesize, post_max_size), počet vstupních proměnných (max_input_vars), adekvátní timeouty (max_execution_time, default_socket_timeout).
  • Na úrovni serveru zajistěte izolaci účtů (FPM pool na aplikaci, chroot/kontejnery), read-only režim kódu, oddělené adresáře var/, tmp/ s nastavením 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), monitorujte security advisories a pravidelně provádějte aktualizace (Dependabot, Renovate).
  • Používejte pouze důvěryhodné balíčky, volte minimální sadu a auditujte skripty v composer.json (sekce scripts).
  • V produkci zapněte autoload-classmap authoritative pro zlepšení výkonu a determinismu.

API bezpečnost: JWT, cookies a CORS

U API pracujících s JWT dbejte na:

  • Krátkou životnost tokenů (minuty), podpisy HS256/RS256 se správnou správou klíčů, validaci audience a issuer, kontrolu kid proti podvržení.
  • Nepřidávejte citlivá data do payloadu; JWT je pouze base64url kódování, nikoli šifrování.
  • CORS: explicitní Access-Control-Allow-Origin (nikoli * pro credentialed požadavky), povolené metody a hlavičky, nikdy neotevírejte Access-Control-Allow-Credentials: true s * jako originem.

Výkon vs. bezpečnost: rate limiting a antibrute-force

Implementujte ochrany proti zneužití:

  • Rate limiting (token bucket, Redis) na citlivé endpointy (přihlášení, reset hesla, odesílání e-mailů).
  • Detekce anomálií (neplatné tokeny, neobvyklé geografické polohy), šedé listiny a dynamická CAPTCHA jako další ochrana po překročení limitu.

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

Integrujte bezpečnostní kontroly do vývojové pipeline:

  • Static analysis (PHPStan/Psalm) s bezpečnostními pravidly, lintování šablon (kontrola CSP porušení, neescapovaných bloků).
  • SAST/DAST skenery, audit závislostí (roave/security-advisories), unit a integrační testy pro scénáře autorizace.
  • Secrets scanning (Git hooky, CI) a ochrany při pre-commit; podepisování releasů, SBOM (CycloneDX).

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

Preferujte šablonovací systémy s autoescapováním (Twig/Latte/Blade). Zakazujte arbitrary code execution v šablonách, oddělte prezentační a aplikační logiku, využívejte komponenty namísto zobrazování surových dat. U e-mailových šablon vždy escapujte a validujte URL.

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

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

Monitorování, audit a reakce na incidenty

Kromě logování provozujte metriky (latence, chybovost, 4xx/5xx), sledujte bezpečnostní události (přihlášení, změny práv, administrace) a nastavte alerty. Mějte připravené runbooky pro reset tokenů, rotaci klíčů a nucené odhlášení. Pravidelně provádějte zálohy a test obnovy dat.

Checklist minimálních opatření

  • Prepared statements všude; žádné dynamické SQL bez whitelistu.
  • Autoescape šablon + CSP s nonce.
  • Session: Secure, HttpOnly, SameSite; regenerace po přihlášení; CSRF tokeny.
  • Hesla: password_hash() (Argon2id/bcrypt), rate limit loginu, MFA.
  • Nahrávání souborů mimo webroot, validace MIME, nové názvy, zákaz spouštění souborů.
  • Bezpečná konfigurace PHP a webového serveru; logování bez tajemství.
  • Aktualizace závislostí, audit balíčků, bezpečnostní analýza v CI.

Závěr: bezpečnost jako kontinuální proces

<