Stručne: PHP pristupuje k databázam cez dve rozšírené rozhrania: PDO (PHP Data Objects) pracuje s mnohými databázovými systémami cez jednotné rozhranie, mysqli je šité na MySQL a MariaDB. Pri oboch spoľahlivo chránia pred SQL injection prepared statements, teda dopyty so zástupnými znakmi. Od PHP 8.0 (PDO), resp. 8.1 (mysqli) hlásia obe chyby štandardne ako výnimku.
Ako PHP komunikuje s databázami
Takmer každá aplikácia PHP ukladá svoj obsah do databázy: stránky, objednávky, používateľské kontá, nastavenia. Skript PHP na to nadviaže spojenie, pošle dopyt v jazyku SQL a spracuje výsledok. Prístupové údaje sú väčšinou v konfiguračnom súbore na tom istom serveri.
Pre vedenie firmy je to dôležité, pretože databáza obsahuje zvyčajne najcennejšie údaje podniku. Kto môže na webovom serveri vykonať kód, môže spravidla prečítať aj konfiguračný súbor a s týmito prístupovými údajmi pristupovať k databáze.
PDO a mysqli v porovnaní
| Vlastnosť | PDO | mysqli |
|---|---|---|
| Databázy | mnohé, cez ovládače ako PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL a MariaDB |
| Zástupné znaky | pomenované (:name) a pozičné (?) |
pozičné (?) |
| Štýl | objektovo orientovaný | objektovo orientovaný a procedurálny |
| Chyby ako výnimka | štandard od PHP 8.0.0 | štandard od PHP 8.1.0 |
| Skrátená forma dopytov s parametrami | prepare() a execute() s poľom |
execute_query() od PHP 8.2.0 |
V praxi často rozhoduje framework alebo CMS. Mnohé prinášajú vlastnú databázovú vrstvu, ktorá interne používa PDO alebo mysqli. Kto preberá aplikáciu, môže jednoduchým hľadaním v zdrojovom kóde zistiť, ktoré rozhranie sa používa a kde dopyty vznikajú:
# Kde aplikácia nadväzuje spojenia, kde vznikajú dopyty?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Nálezy s ->query( nie sú automaticky nebezpečné. Zaslúžia si však druhý pohľad, pretože tam sa môžu hodnoty dostať priamo do textu SQL namiesto odovzdania cez zástupné znaky. Práve staršie projekty miešajú oba štýly a kontrola sa oplatí pred každou väčšou aktualizáciou.
Prepared statements: najdôležitejší vzor
Pri prepared statement sa dopyt so zástupnými znakmi pošle databáze a hodnoty sa odovzdajú oddelene. Podľa príručky PHP to chráni pred SQL injection, ak všetky vstupy používateľa idú cez zástupné znaky.
<?php
declare(strict_types=1);
$pdo = new PDO(
'mysql:host=localhost;dbname=shop;charset=utf8mb4',
$dbUser,
$dbPass,
[PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE plz = :plz AND aktiv = :aktiv');
$stmt->execute(['plz' => $plz, 'aktiv' => 1]);
foreach ($stmt as $zeile) {
echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
To isté s mysqli v skrátenej forme, ktorá existuje od PHP 8.2:
<?php
$db = new mysqli('localhost', $dbUser, $dbPass, 'shop');
$ergebnis = $db->execute_query('SELECT id, name FROM kunden WHERE plz = ?', [$plz]);
foreach ($ergebnis as $zeile) {
echo htmlspecialchars($zeile['name'], ENT_QUOTES, 'UTF-8'), "\n";
}
Dve hranice by mali vývojári poznať. Zástupné znaky nesmú stáť v úvodzovkách; pri vyhľadávaní cez LIKE patria zástupné znaky % do odovzdanej hodnoty. A zástupné znaky nahrádzajú iba hodnoty, nie názvy tabuliek alebo stĺpcov. Ako takéto osobitné prípady bezpečne vyriešiť, ukazuje príručka Ako zabrániť SQL injection v PHP.
Spracovanie chýb: výnimky namiesto tichých chýb
Dávnejšie pracovali obe rozhrania štandardne potichu: zlyhaný dopyt vrátil false a kto to nekontroloval, pracoval ďalej s prázdnymi údajmi. To sa zmenilo:
- PDO: Od PHP 8.0.0 je
PDO::ERRMODE_EXCEPTIONštandardom. Chyby vyhadzujúPDOException. - mysqli: Od PHP 8.1.0 je hlásenie chýb nastavené na
MYSQLI_REPORT_ERRORaMYSQLI_REPORT_STRICT. Chyby vyhadzujúmysqli_sql_exception; predtým bolo hlásenie vypnuté.
Pre bezpečnosť to znamená: výnimky sa musia zachytávať a zaznamenávať, ale nikdy nesmú skončiť v prehliadači s textom SQL, názvami tabuliek alebo prístupovými údajmi. Ako to čisto oddeliť, opisuje stránka Chyby a výnimky v PHP.
Správne prideľovať prístupové údaje a práva
Databáza je chránená len tak dobre, ako jej prístupové údaje. Osvedčili sa tieto pravidlá:
- Vlastný používateľ pre každú aplikáciu: Nikdy nepoužívať administrátora databázy pre web.
- Len potrebné práva: Web zvyčajne potrebuje čítať, zapisovať, meniť a mazať vo svojej vlastnej databáze, ale nie práva na iné databázy alebo funkcie servera.
- Žiadne vzdialené spojenie bez dôvodu: Databáza by mala byť dostupná len z webového servera, nie z internetu.
- Prístupové údaje mimo webrootu: Konfiguračné súbory a súbory
.envnesmú byť dostupné cez URL. Viac v príspevku Ochrana prístupových údajov a súborov .env. - Šifrované spojenie pri oddelených serveroch: Ak databáza leží na inom počítači, spojenie by malo byť šifrované, aby prístupové údaje a obsah nešli sieťou v čitateľnej podobe.
- Vlastné prístupy pre údržbu: Zálohovanie, analýzy a správcovia dostanú vlastných používateľov. Tak sa dá v logu dohľadať, kto čo urobil, a prístup sa dá zablokovať bez rušenia webu.
Databázy, PHP2Shell a krízový prípad
PHP2Shell sa netýka samotnej databázy, ale interpretera PHP: CVE-2026-109618 a CVE-2026-109619 umožňujú spustenie škodlivého kódu bez prihlásenia. Ak sa to podarí, kód beží s právami procesu PHP a môže tak spravidla prečítať konfiguračný súbor s prístupovými údajmi k databáze. Prepared statements proti tomu nepomáhajú, pretože útok vôbec nejde cez dopyt SQL.
Povinná je preto aktualizácia na PHP 8.5.12, 8.4.27, 8.3.36 alebo 8.2.35 a reštart všetkých procesov PHP. Ak existujú náznaky úspešného útoku, patria k tomu nové prístupové údaje k databáze, kontrola databázy na votknutý obsah a posúdenie oznamovacej povinnosti podľa GDPR. Tu dáva zmysel štruktúrovaný Incident Response.
Heslá k databáze meňte až po vyčistení servera. Kým beží škodlivý kód, môže znova prečítať aj nové prístupové údaje.
Ako konkrétne pomáha PHP SOS?
- Kontrolujeme, ako vaša aplikácia pristupuje k databáze a či používatelia, práva a sieťový prístup zodpovedajú minimu.
- Overujeme, či konfiguračné súbory a súbory s prístupovými údajmi ležia mimo webrootu a nie sú verejne dostupné.
- Po incidente obnovujeme prístupové údaje v správnom poradí a kontrolujeme databázu na votknutý kód.
- Výsledky dokumentujeme tak, aby ich mohli sledovať zodpovední za ochranu údajov a poisťovne.
Časté otázky
Mám použiť PDO, alebo mysqli?
Pre nové projekty je PDO zvyčajne flexibilnejšou voľbou, pretože pracuje s mnohými databázami cez to isté rozhranie. mysqli dáva zmysel, ak používate výlučne MySQL alebo MariaDB a potrebujete ich špeciálne funkcie. Obe sú bezpečné, ak sa dôsledne používajú prepared statements.
Vyhadzuje PDO pri chybách automaticky výnimky?
Áno, od PHP 8.0.0 je štandardom PDO::ERRMODE_EXCEPTION. Predtým to bol tichý režim, v ktorom boli chyby dostupné len cez errorCode() a errorInfo(). Staršie aplikácie tento režim často ešte nastavujú výslovne.
Môžu zástupné znaky nahradiť aj názvy tabuliek alebo stĺpcov?
Nie. Zástupné znaky stoja len za hodnoty. Názvy tabuliek a stĺpcov, napríklad pre zoradenie, sa musia pred vložením do dopytu skontrolovať voči pevnému zoznamu povolených názvov.
Musím po PHP2Shell zmeniť heslo k databáze?
Samotná aktualizácia to nevyžaduje. Ak však existujú náznaky, že server bol kompromitovaný, všetky prístupové údaje v konfiguračných súboroch sa považujú za známe. Potom by ste ich mali po vyčistení obnoviť.