Aktuální situace: PHP2Shell. Dvě kritické zranitelnosti PHP (CVSS 9.2) umožňují spustit škodlivý kód bez přihlášení. Záplaty od 21. 10. 2026.Co nyní udělat →

Vestavěné bezpečnostní funkce PHP

PHP nabízí bezpečné stavební prvky pro hesla, náhodné hodnoty, escapování, kryptografii a relace. Kdo je důsledně používá, vyhne se nejčastějším chybám aplikací.

Stav 5 min čteníZnalosti o PHP

Stručně: PHP nabízí pro nejčastější bezpečnostní úkoly hotové, prověřené funkce: password_hash() pro hesla, random_bytes() a random_int() pro tokeny, htmlspecialchars() proti cross-site scriptingu, připravené dotazy s PDO proti SQL injection, hash_equals() pro bezpečná porovnání a rozšíření Sodium pro kryptografii. Kdo tyto stavební prvky důsledně používá, vyhne se většině zranitelností aplikací. Proti chybám v samotném interpretu PHP, jako u PHP2Shell, nepomáhají; tam pomůže jen aktualizace.

Proč vestavěné bezpečnostní funkce PHP?

Psát bezpečnostní kód vlastními silami je náchylné k chybám. Vlastní hash hesla, svépomocně sestavený generátor tokenů nebo vlastní filtr pro výstupy HTML často vypadají správně a přesto správné nejsou. Vestavěné funkce jsou zdokumentované, otestované a udržují se s aktualizacemi PHP.

Pro rozhodovatele z toho plyne: nezeptejte se své agentury nebo vývojového týmu, zda byly bezpečnostní funkce napsány ručně, ale zda se používají standardní funkce jazyka. Přehled podává tabulka.

Úkol Funkce Dostupné od Důležitá poznámka
Ukládání hesel password_hash(), password_verify() PHP 5.5 sloupec až 255 znaků; bcrypt ořezává na 72 bajtů
Náhodné tokeny random_bytes(), random_int() PHP 7.0 nikdy rand() nebo mt_rand() pro tajné hodnoty
Náhoda objektově Random\Randomizer PHP 8.2 stejná bezpečnost, flexibilnější rozhraní
Escapování výstupu HTML htmlspecialchars() odjakživa výchozí příznaky od 8.1 escapují i jednoduché uvozovky
Porovnání v konstantním čase hash_equals() PHP 5.6 uživatelský vstup jako druhý argument
Moderní kryptografie Sodium (sodium_*) PHP 7.2 místo vlastního šifrování
Tajemství ve stack trace #[\SensitiveParameter] PHP 8.2 hodnota se v trace neobjeví
Kontrola vstupů filter_var() PHP 5.2 kontroluje formát, nenahrazuje escapování

Hesla a tokeny

password_hash() vytvoří hash s přidanou solí, password_verify() jej ověří. S PASSWORD_DEFAULT PHP aktuálně používá bcrypt; od PHP 8.4 je výchozí nákladový faktor podle příručky 12 místo 10. Protože se výchozí algoritmus může změnit, příručka doporučuje sloupec v databázi s 255 znaky. U bcrypt se hesla po 72 bajtech ořezávají, což je třeba mít na paměti u velmi dlouhých hesel-vět.

<?php
// Registrace
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Přihlášení, včetně automatického vylepšení starých hashů
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // uložit znovu
    }
}

// Token pro odkaz na obnovení hesla
$token = bin2hex(random_bytes(32));

Pro porovnání tajných hodnot, například podpisu, je třeba použít hash_equals(). Běžné porovnání pomocí === může podle příručky prostřednictvím doby běhu prozradit, od kterého místa se dvě hodnoty liší. Podrobněji: Bezpečné ukládání hesel v PHP a bezpečná náhodná čísla a tokeny.

Escapování výstupů a bezpečné dotazy do databáze

Cross-site scripting vzniká, když se uživatelské vstupy dostanou do HTML bez filtrování. htmlspecialchars() převádí speciální znaky na entity HTML. Od PHP 8.1 jsou výchozími příznaky ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; dříve se jednoduché uvozovky nepřeváděly. Kdo musí podporovat starší verze, uvede příznaky výslovně.

SQL injection brání připravené dotazy. Hodnoty se přenášejí odděleně od textu SQL a dotaz nemohou změnit:

<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();

echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');

Podrobnosti najdete v článku Prevence cross-site scriptingu v PHP a na stránce o SQL injection.

Kontrola vstupů je druhý, samostatný krok. filter_var() zjistí, zda má hodnota platný formát, například e-mailovou adresu nebo celé číslo v povoleném rozsahu. To ale nenahrazuje escapování při výstupu ani připravený dotaz, protože i formálně platné hodnoty mohou obsahovat speciální znaky.

Tajemství držet mimo chybová hlášení

Nedoceněným únikem dat jsou stack trace. Pokud ve funkci nastane chyba, PHP zaprotokoluje řetězec volání včetně argumentů. Pokud tam je heslo nebo klíč API, skončí v logu. Od PHP 8.2 takové parametry označuje atribut #[\SensitiveParameter]; jejich hodnota se pak v trace objeví jen jako objekt SensitiveParameterValue.

<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... kontrola ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}

Podle poznámky v příručce atribut působí jen u konkrétní implementace, ne u metody rozhraní. Nastavte jej proto tam, kde kód skutečně běží.

Relace: bezpečná nastavení a nové standardy

Relace jsou častým cílem útoků. Ústřední jsou tři nastavení: session.use_strict_mode=1 odmítá ID relací, které server sám nevytvořil; session.cookie_httponly=1 brání přístupu ke cookie relace přes JavaScript; session.cookie_samesite=Lax ztěžuje odesílání spolu s požadavky z cizích stránek. Podle přijatého RFC se právě tyto tři hodnoty stanou s PHP 8.6 výchozími. Do té doby je nastavte sami, a i potom výslovně, aby konfigurace nezávisela na výchozích hodnotách.

session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1

Více v článku Zabezpečení relací v PHP.

Co vestavěné funkce nezajistí

Projekt PHP je ve své bezpečnostní politice jasný: PHP není sandbox. Obejití open_basedir nebo disable_functions, škodlivé vstupy do unserialize() a nekontrolované argumenty funkcí jako mysqli_query() se nepovažují za bezpečnostní zranitelnosti PHP. Pro provozovatele to znamená: tato nastavení jsou užitečné zpevnění, ale ne bezpečnostní hranice, a unserialize() s cizími daty nemá nic společného.

Druhý bod se týká PHP2Shell. CVE-2026-109618 a CVE-2026-109619 podle php.net umožňují spuštění kódu dříve nebo během toho, než běží vaše aplikace; u mod_php byl předveden exploit ještě předtím, než se vůbec spustí aplikační kód. Žádná funkce ve vašem kódu to nezachytí. Bezpečné programování a aktuální verze PHP jsou dvě oddělené povinnosti a obě musí být splněny.

Jak konkrétně pomáhá PHP SOS?

V bezpečnostním auditu aplikací PHP cíleně kontrolujeme:

  • Zacházení s hesly a tokeny: Používají se password_hash() a random_bytes(), nebo existují vlastní řešení?
  • Výstupy a dotazy: Kde se vstupy dostanou do HTML, SQL nebo příkazů shellu bez filtrování?
  • Konfigurace relací: Jsou nastaveny Strict Mode, HttpOnly, SameSite a Secure a nelze je přepsat?
  • Běh: Běží podporovaná verze PHP s opravami z 21. 10. 2026?

Časté dotazy

Jak se v PHP správně ukládají hesla?

Pomocí password_hash() a PASSWORD_DEFAULT, kontroluje se pomocí password_verify(). Sloupec v databázi by měl podle příručky pojmout až 255 znaků, protože se výchozí algoritmus může v budoucnu změnit.

Hodí se rand() pro tokeny?

Ne. Pro tokeny, klíče a odkazy pro obnovu hesla je třeba použít random_bytes() nebo random_int(). Podle příručky vracejí kryptograficky bezpečné náhodné hodnoty.

Od kdy je Sodium součástí PHP?

Rozšíření Sodium pro moderní kryptografii je součástí PHP od verze 7.2.0. Starší verze je mohly doplnit jen přes PECL.

Chrání tyto funkce před PHP2Shell?

Ne. Chrání před chybami ve vaší aplikaci. PHP2Shell sídlí v samotném interpretu a uzavře ho jen aktualizace PHP, následovaná restartem všech procesů PHP.

Mění se standardy relací v PHP 8.6?

Ano, podle přijatého RFC se session.use_strict_mode a session.cookie_httponly zapnou ve výchozím stavu a session.cookie_samesite se nastaví na Lax. Stávající konfigurace byste přesto měli nastavit sami výslovně.

Zdroje

Okamžitý kontakt

Každá hodina se počítá. Napište nám hned.

Stručně popište systém, verzi PHP a pozorování. Ozveme se, vyjasníme situaci a budeme pracovat na dálku, dokud nebude incident uzavřen a zdokumentován.

Okamžitá pomoc