Trumpai: PHP kreipiasi į duomenų bazes per dvi paplitusias sąsajas: PDO (PHP Data Objects) su daugeliu duomenų bazių sistemų dirba per vieningą sąsają, mysqli pritaikytas MySQL ir MariaDB. Su abiem nuo SQL injekcijos patikimai saugo parengtos užklausos (prepared statements), t. y. užklausos su vietos žymekliais. Nuo PHP 8.0 (PDO) arba 8.1 (mysqli) abu klaidas pagal numatymą praneša kaip išimtis (exception).
Kaip PHP kalbasi su duomenų bazėmis
Beveik kiekviena PHP programa savo turinį saugo duomenų bazėje: puslapius, užsakymus, naudotojų paskyras, nustatymus. PHP skriptas tam užmezga ryšį, išsiunčia užklausą SQL kalba ir apdoroja rezultatą. Prieigos duomenys dažniausiai yra konfigūracijos faile tame pačiame serveryje.
Vadovybei tai svarbu, nes duomenų bazėje dažniausiai yra vertingiausi įmonės duomenys. Kas gali vykdyti kodą žiniatinklio serveryje, paprastai gali perskaityti ir konfigūracijos failą bei su tais prieigos duomenimis kreiptis į duomenų bazę.
PDO ir mysqli palyginimas
| Požymis | PDO | mysqli |
|---|---|---|
| Duomenų bazės | daug, per tvarkykles, tokias kaip PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL ir MariaDB |
| Vietos žymekliai | pavadinti (:name) ir pozicinis (?) |
pozicinis (?) |
| Stilius | objektinis | objektinis ir procedūrinis |
| Klaidos kaip išimtys | numatytasis nuo PHP 8.0.0 | numatytasis nuo PHP 8.1.0 |
| Trumpoji forma užklausoms su parametrais | prepare() ir execute() su masyvu |
execute_query() nuo PHP 8.2.0 |
Praktikoje dažnai nusprendžia karkasas ar CMS. Daugelis turi savą duomenų bazės sluoksnį, kuris viduje naudoja PDO arba mysqli. Kas perima programą, paprasta pirminio kodo paieška gali nustatyti, kuri sąsaja naudojama ir kur kuriamos užklausos:
# Kur programa užmezga ryšius, kur kuriamos užklausos?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Radiniai su ->query( automatiškai nėra nesaugūs. Bet jie nusipelno antro žvilgsnio, nes ten reikšmės gali patekti tiesiai į SQL tekstą, užuot buvusios perduotos per vietos žymeklius. Būtent senesni projektai maišo abu stilius, ir patikra atsiperka prieš kiekvieną didesnį atnaujinimą.
Parengtos užklausos: svarbiausias šablonas
Parengtos užklausos atveju užklausa su vietos žymekliais išsiunčiama duomenų bazei, o reikšmės perduodamos atskirai. Pasak PHP vadovo, tai saugo nuo SQL injekcijos, jei visi naudotojo įvedimai eina per vietos žymeklius.
<?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";
}
Tas pats su mysqli trumpąja forma, kuri egzistuoja nuo 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";
}
Kūrėjai turėtų žinoti dvi ribas. Vietos žymekliai negali būti kabutėse; LIKE paieškose pakaitos simboliai % priklauso perduodamai reikšmei. Ir vietos žymekliai pakeičia tik reikšmes, o ne lentelių ar stulpelių pavadinimus. Kaip tokius ypatingus atvejus išspręsti saugiai, parodo vadovas SQL injekcijos PHP prevencija.
Klaidų tvarkymas: išimtys vietoj tylių klaidų
Anksčiau abi sąsajos pagal numatymą dirbo tyliai: nepavykusi užklausa grąžindavo false, o kas to netikrino, toliau dirbo su tuščiais duomenimis. Tai pasikeitė:
- PDO: nuo PHP 8.0.0 numatytasis yra
PDO::ERRMODE_EXCEPTION. Klaidos metaPDOException. - mysqli: nuo PHP 8.1.0 pranešimas nustatytas į
MYSQLI_REPORT_ERRORirMYSQLI_REPORT_STRICT. Klaidos metamysqli_sql_exception; anksčiau pranešimas buvo išjungtas.
Saugumui tai reiškia: išimtis reikia pagauti ir registruoti, bet jokiu būdu jos negali patekti į naršyklę su SQL tekstu, lentelių pavadinimais ar prieigos duomenimis. Kaip tai tvarkingai atskirti, aprašo puslapis Klaidos ir išimtys PHP.
Prieigos duomenys ir teisės: kaip suteikti teisingai
Duomenų bazė apsaugota tiek, kiek apsaugoti jos prieigos duomenys. Pasiteisino šios taisyklės:
- Atskiras naudotojas kiekvienai programai: svetainei niekada nenaudokite duomenų bazės administratoriaus.
- Tik reikalingos teisės: svetainei dažniausiai reikia skaityti, rašyti, keisti ir trinti savo duomenų bazėje, bet ne teisių į kitas duomenų bazes ar serverio funkcijas.
- Be nuotolinio ryšio be priežasties: duomenų bazė turėtų būti pasiekiama tik iš žiniatinklio serverio, o ne iš interneto.
- Prieigos duomenys už žiniatinklio šaknies: konfigūracijos ir
.envfailai neturi būti pasiekiami per URL. Daugiau straipsnyje Prieigos duomenų ir .env failų apsauga. - Šifruotas ryšys atskiriems serveriams: jei duomenų bazė yra kitame kompiuteryje, ryšys turėtų būti šifruotas, kad prieigos duomenys ir turinys neitų per tinklą atviru tekstu.
- Atskiros prieigos priežiūrai: atsarginėms kopijoms, ataskaitoms ir administratoriams skiriami atskiri naudotojai. Taip žurnale galima atsekti, kas ką padarė, o prieigą galima užblokuoti netrikdant svetainės.
Duomenų bazės, PHP2Shell ir kritinis atvejis
PHP2Shell liečia ne pačią duomenų bazę, o PHP interpretatorių: CVE-2026-109618 ir CVE-2026-109619 leidžia vykdyti kenkėjišką kodą be prisijungimo. Jei tai pavyksta, kodas veikia su PHP proceso teisėmis ir todėl paprastai gali perskaityti konfigūracijos failą su duomenų bazės prieigos duomenimis. Parengtos užklausos čia nepadeda, nes ataka apskritai nevyksta per SQL užklausą.
Todėl privaloma atnaujinti iki PHP 8.5.12, 8.4.27, 8.3.36 ar 8.2.35 ir iš naujo paleisti visus PHP procesus. Jei yra požymių, kad ataka pavyko, reikia naujų duomenų bazės prieigos duomenų, duomenų bazės patikros dėl įterpto turinio ir pranešimo pareigos pagal BDAR įvertinimo. Čia prasminga struktūruota incidentų valdymo (Incident Response) pagalba.
Duomenų bazės slaptažodžius keiskite tik išvalę serverį. Kol veikia kenkėjiškas kodas, jis gali iš naujo nuskaityti ir naujus prieigos duomenis.
Kaip PHP SOS padeda konkrečiai?
- Tikriname, kaip jūsų programa kreipiasi į duomenų bazę ir ar naudotojai, teisės ir tinklo prieiga atitinka būtiną minimumą.
- Kontroliuojame, ar konfigūracijos ir prieigos failai yra už žiniatinklio šaknies ir nėra viešai pasiekiami.
- Po incidento atnaujiname prieigos duomenis teisinga eilės tvarka ir tikriname duomenų bazę dėl įterpto kodo.
- Rezultatus dokumentuojame taip, kad duomenų apsaugos pareigūnai ir draudikai galėtų juos atsekti.
Dažni klausimai
Ar naudoti PDO, ar mysqli?
Naujiems projektams PDO dažniausiai yra lankstesnis pasirinkimas, nes su daugeliu duomenų bazių dirba per tą pačią sąsają. mysqli prasmingas, kai naudojate tik MySQL ar MariaDB ir jums reikia jų ypatingų funkcijų. Abu saugūs, jei nuosekliai naudojamos parengtos užklausos.
Ar PDO klaidos atveju automatiškai meta išimtis?
Taip, nuo PHP 8.0.0 PDO::ERRMODE_EXCEPTION yra numatytasis. Anksčiau buvo tylusis režimas, kuriame klaidas buvo galima gauti tik per errorCode() ir errorInfo(). Senesnės programos režimą dažnai vis dar nustato aiškiai.
Ar vietos žymekliai gali pakeisti ir lentelių ar stulpelių pavadinimus?
Ne. Vietos žymekliai pakeičia tik reikšmes. Lentelių ir stulpelių pavadinimai, pavyzdžiui, rūšiavimui, prieš įterpiant į užklausą turi būti patikrinti pagal fiksuotą leistinų pavadinimų sąrašą.
Ar po PHP2Shell turiu keisti duomenų bazės slaptažodį?
Vien atnaujinimas to nereikalauja. Tačiau jei yra požymių, kad serveris buvo pažeistas, visi konfigūracijos failuose esantys prieigos duomenys laikomi žinomais. Tuomet juos po išvalymo reikėtų atnaujinti.