Na kratko: PHP do podatkovnih zbirk dostopa prek dveh razširjenih vmesnikov: PDO (PHP Data Objects) prek enotnega vmesnika deluje z mnogimi sistemi podatkovnih zbirk, mysqli je prilagojen MySQL in MariaDB. Pri obeh pripravljeni stavki (prepared statements), torej poizvedbe z nadomestnimi znaki, zanesljivo ščitijo pred SQL injection. Od PHP 8.0 (PDO) oziroma 8.1 (mysqli) oba napake privzeto javljata kot izjemo.
Kako PHP komunicira s podatkovnimi zbirkami
Skoraj vsaka aplikacija PHP svoje vsebine shranjuje v podatkovno zbirko: strani, naročila, uporabniške račune, nastavitve. Skripta PHP za to vzpostavi povezavo, pošlje poizvedbo v jeziku SQL in obdela rezultat. Dostopni podatki praviloma stojijo v konfiguracijski datoteki na istem strežniku.
Za vodstvo je to pomembno, ker podatkovna zbirka praviloma vsebuje najdragocenejše podatke podjetja. Kdor lahko na spletnem strežniku izvede kodo, praviloma lahko prebere tudi konfiguracijsko datoteko in s temi dostopnimi podatki dostopa do podatkovne zbirke.
PDO in mysqli v primerjavi
| Značilnost | PDO | mysqli |
|---|---|---|
| Podatkovne zbirke | številne, prek gonilnikov, kot so PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL in MariaDB |
| Nadomestni znaki | imenovani (:name) in pozicijski (?) |
pozicijski (?) |
| Slog | objektno usmerjen | objektno usmerjen in proceduralen |
| Napake kot izjema | privzeto od PHP 8.0.0 | privzeto od PHP 8.1.0 |
| Kratka oblika za poizvedbe s parametri | prepare() in execute() s poljem |
execute_query() od PHP 8.2.0 |
V praksi pogosto odloča ogrodje ali CMS. Številni prinesejo lastno plast podatkovne zbirke, ki interno uporablja PDO ali mysqli. Kdor prevzame aplikacijo, lahko z enostavnim iskanjem po izvorni kodi ugotovi, kateri vmesnik se uporablja in kje nastajajo poizvedbe:
# Kje aplikacija vzpostavlja povezave, kje nastajajo poizvedbe?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Zadetki z ->query( niso samodejno nevarni. Zaslužijo pa drugi pogled, ker lahko tam vrednosti zaidejo neposredno v besedilo SQL, namesto da bi se predale prek nadomestnih znakov. Predvsem starejši projekti mešajo oba sloga in preverjanje se splača pred vsako večjo posodobitvijo.
Pripravljeni stavki: najpomembnejši vzorec
Pri pripravljenem stavku se poizvedba z nadomestnimi znaki pošlje podatkovni zbirki, vrednosti pa se predajo ločeno. Po priročniku PHP to ščiti pred SQL injection, če vsi uporabniški vnosi tečejo prek nadomestnih znakov.
<?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";
}
Isto z mysqli v kratki obliki, ki obstaja 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";
}
Razvijalci naj poznajo dve meji. Nadomestni znaki ne smejo stati v narekovajih; pri iskanjih z LIKE sodijo nadomestni znaki % v predano vrednost. In nadomestni znaki nadomeščajo samo vrednosti, ne imen tabel ali stolpcev. Kako take posebne primere varno rešite, kaže vodnik Preprečevanje SQL injection v PHP.
Obravnava napak: izjeme namesto tihih napak
Nekoč sta oba vmesnika privzeto delovala tiho: neuspela poizvedba je vrnila false, kdor tega ni preveril, je delal naprej s praznimi podatki. To se je spremenilo:
- PDO: od PHP 8.0.0 je
PDO::ERRMODE_EXCEPTIONprivzet. Napake vržejoPDOException. - mysqli: od PHP 8.1.0 je poročanje o napakah nastavljeno na
MYSQLI_REPORT_ERRORinMYSQLI_REPORT_STRICT. Napake vržejomysqli_sql_exception; prej je bilo poročanje izklopljeno.
Za varnost to pomeni: izjeme je treba prestreči in beležiti, a nikoli ne smejo z besedilom SQL, imeni tabel ali dostopnimi podatki končati v brskalniku. Kako to čisto ločite, opisuje stran Napake in izjeme v PHP.
Pravilno dodeljevanje dostopnih podatkov in pravic
Podatkovna zbirka je zaščitena le toliko kot njeni dostopni podatki. Obnesla so se ta pravila:
- Lasten uporabnik za vsako aplikacijo: za spletno stran nikoli ne uporabljajte skrbnika podatkovne zbirke.
- Samo potrebne pravice: spletna stran praviloma potrebuje branje, pisanje, spreminjanje in brisanje v svoji podatkovni zbirki, ne pa pravic na drugih podatkovnih zbirkah ali strežniških funkcijah.
- Brez oddaljene povezave brez razloga: podatkovna zbirka naj bo dosegljiva samo s spletnega strežnika, ne iz interneta.
- Dostopni podatki zunaj korena spleta: konfiguracijske datoteke in datoteke
.envne smejo biti dosegljive po URL. Več v prispevku Zaščita dostopnih podatkov in datotek .env. - Šifrirana povezava pri ločenih strežnikih: če podatkovna zbirka leži na drugem računalniku, naj povezava teče šifrirano, da dostopni podatki in vsebine ne potujejo po omrežju v čistem besedilu.
- Lastni dostopi za vzdrževanje: varnostno kopiranje, analize in skrbniki dobijo lastne uporabnike. Tako je v dnevniku mogoče slediti, kdo je kaj storil, in dostop je mogoče blokirati, ne da bi motili spletno stran.
Podatkovne zbirke, PHP2Shell in resen primer
PHP2Shell ne zadeva podatkovne zbirke same, ampak interpreter PHP: CVE-2026-109618 in CVE-2026-109619 omogočata izvajanje škodljive kode brez prijave. Če uspe, koda teče s pravicami procesa PHP in zato praviloma lahko prebere konfiguracijsko datoteko z dostopnimi podatki do podatkovne zbirke. Pripravljeni stavki tu ne pomagajo, ker napad sploh ne poteka prek poizvedbe SQL.
Obvezna je zato posodobitev na PHP 8.5.12, 8.4.27, 8.3.36 ali 8.2.35 in ponovni zagon vseh procesov PHP. Če obstajajo znaki uspešnega napada, sodijo zraven novi dostopni podatki do podatkovne zbirke, preverjanje podatkovne zbirke glede vnesenih vsebin in presoja obveznosti prijave po GDPR. Tu je smiseln strukturiran odziv na incident.
Gesla podatkovne zbirke spremenite šele po čiščenju strežnika. Dokler teče škodljiva koda, lahko nove dostopne podatke prebere znova.
Kako PHP SOS pomaga konkretno?
- Preverimo, kako vaša aplikacija dostopa do podatkovne zbirke in ali uporabniki, pravice in omrežni dostop ustrezajo minimumu.
- Preverimo, ali konfiguracijske datoteke in datoteke z dostopnimi podatki ležijo zunaj korena spleta in niso javno dosegljive.
- Po incidentu obnovimo dostopne podatke v pravilnem vrstnem redu in preverimo podatkovno zbirko glede vnesene kode.
- Rezultate dokumentiramo tako, da jih lahko preverijo pooblaščenci za varstvo podatkov in zavarovalnice.
Pogosta vprašanja
Ali naj uporabljam PDO ali mysqli?
Za nove projekte je PDO praviloma prožnejša izbira, ker prek istega vmesnika deluje s številnimi podatkovnimi zbirkami. mysqli je smiseln, če uporabljate izključno MySQL ali MariaDB in potrebujete njune posebne funkcije. Oba sta varna, če se pripravljeni stavki dosledno uporabljajo.
Ali PDO ob napakah samodejno vrže izjeme?
Da, od PHP 8.0.0 je PDO::ERRMODE_EXCEPTION privzet. Prej je bil tihi način, v katerem so bile napake dosegljive samo prek errorCode() in errorInfo(). Starejše aplikacije način pogosto še vedno izrecno nastavijo.
Ali nadomestni znaki lahko nadomestijo tudi imena tabel ali stolpcev?
Ne. Nadomestni znaki stojijo samo za vrednosti. Imena tabel in stolpcev, na primer za razvrščanje, je treba pred vstavitvijo v poizvedbo preveriti glede na trden seznam dovoljenih imen.
Ali moram po PHP2Shell spremeniti geslo podatkovne zbirke?
Samo posodobitev tega ne zahteva. Če pa obstajajo znaki, da je bil strežnik ogrožen, vsi dostopni podatki v konfiguracijskih datotekah veljajo za znane. Takrat jih po čiščenju obnovite.