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()abindValue()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žívejtepassword_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_uploadsa velikost souborů (upload_max_filesize,post_max_size),max_input_varsa 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říznakemnoexec.
Závislosti, dodavatelský řetězec a aktualizace
Composer je mocný nástroj, ale vyžaduje disciplínu:
- Uzamkněte verze (
composer.lockv 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(sekcescripts). - 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 nenastavujteAccess-Control-Allow-Credentials: truespolu 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.
