Kort sagt: PHP når databaser via två utbredda gränssnitt: PDO (PHP Data Objects) arbetar med många databassystem via ett enhetligt gränssnitt, mysqli är skräddarsytt för MySQL och MariaDB. Med båda skyddar prepared statements, alltså frågor med platshållare, tillförlitligt mot SQL-injektion. Sedan PHP 8.0 (PDO) respektive 8.1 (mysqli) rapporterar båda fel som undantag som standard.
Så talar PHP med databaser
Nästan varje PHP-applikation lagrar sitt innehåll i en databas: sidor, beställningar, användarkonton, inställningar. PHP-skriptet upprättar för det en anslutning, skickar en fråga på språket SQL och bearbetar resultatet. Inloggningsuppgifterna står oftast i en konfigurationsfil på samma server.
För ledningen är det viktigt, eftersom databasen oftast innehåller företagets mest värdefulla data. Den som kan köra kod på webbservern kan som regel också läsa konfigurationsfilen och komma åt databasen med de uppgifterna.
PDO och mysqli i jämförelse
| Kännetecken | PDO | mysqli |
|---|---|---|
| Databaser | många, via drivrutiner som PDO_MYSQL, PDO_PGSQL, PDO_SQLITE, PDO_SQLSRV, PDO_OCI |
MySQL och MariaDB |
| Platshållare | namngivna (:name) och positionella (?) |
positionella (?) |
| Stil | objektorienterad | objektorienterad och procedurell |
| Fel som undantag | standard sedan PHP 8.0.0 | standard sedan PHP 8.1.0 |
| Kortform för frågor med parametrar | prepare() och execute() med array |
execute_query() sedan PHP 8.2.0 |
I praktiken avgör ofta ramverket eller CMS:et. Många har ett eget databaslager som internt använder PDO eller mysqli. Den som tar över en applikation kan med en enkel sökning i källkoden ta reda på vilket gränssnitt som används och var frågor uppstår:
# Var upprättar applikationen anslutningar, var uppstår frågor?
grep -rn --include='*.php' -E 'new PDO|new mysqli|mysqli_connect|->query\(' /var/www/app/src | head -50
Träffar med ->query( är inte automatiskt osäkra. De förtjänar dock en andra blick, eftersom värden där kan hamna direkt i SQL-texten i stället för att lämnas över via platshållare. Särskilt äldre projekt blandar båda stilarna, och kontrollen lönar sig före varje större uppdatering.
Prepared statements: det viktigaste mönstret
Vid ett prepared statement skickas frågan med platshållare till databasen och värdena lämnas över separat. Enligt PHP-manualen skyddar det mot SQL-injektion om all användarinmatning går via platshållare.
<?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";
}
Samma sak med mysqli i den kortform som finns sedan 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";
}
Två gränser bör utvecklare känna till. Platshållare får inte stå inom citattecken; vid LIKE-sökningar hör platshållartecknet % hemma i det överlämnade värdet. Och platshållare ersätter bara värden, inte tabell- eller kolumnnamn. Hur sådana specialfall löses säkert visar guiden Förhindra SQL-injektion i PHP.
Felhantering: undantag i stället för tysta fel
Tidigare arbetade båda gränssnitten som standard tyst: En misslyckad fråga gav false, och den som inte kontrollerade det fortsatte arbeta med tomma data. Det har ändrats:
- PDO: Sedan PHP 8.0.0 är
PDO::ERRMODE_EXCEPTIONstandard. Fel kastar enPDOException. - mysqli: Sedan PHP 8.1.0 är felrapporteringen satt till
MYSQLI_REPORT_ERRORochMYSQLI_REPORT_STRICT. Fel kastar enmysqli_sql_exception; tidigare var rapporteringen avstängd.
För säkerheten betyder det: Undantag måste fångas och loggas men får aldrig hamna i webbläsaren med SQL-text, tabellnamn eller inloggningsuppgifter. Hur man skiljer det rent åt beskrivs på sidan Fel och undantag i PHP.
Tilldela inloggningsuppgifter och rättigheter rätt
Databasen är bara så välskyddad som dess inloggningsuppgifter. Dessa regler har visat sig fungera:
- Egen användare per applikation: Använd aldrig databasens administratör för webbplatsen.
- Bara nödvändiga rättigheter: En webbplats behöver oftast läsa, skriva, ändra och radera i sin egen databas, men inga rättigheter i andra databaser eller serverfunktioner.
- Ingen fjärranslutning utan skäl: Databasen bör bara vara nåbar från webbservern, inte från internet.
- Inloggningsuppgifter utanför webbroten: Konfigurations- och
.env-filer får inte kunna hämtas via URL. Mer om detta i artikeln Skydda inloggningsuppgifter och .env-filer. - Krypterad anslutning vid åtskilda servrar: Ligger databasen på en annan dator bör anslutningen vara krypterad, så att inloggningsuppgifter och innehåll inte går i klartext genom nätet.
- Egna åtkomster för underhåll: Säkerhetskopiering, utvärderingar och administratörer får egna användare. Då går det att spåra i loggen vem som gjorde vad, och en åtkomst kan spärras utan att störa webbplatsen.
Databaser, PHP2Shell och skarpt läge
PHP2Shell berör inte själva databasen utan PHP-tolken: CVE-2026-109618 och CVE-2026-109619 möjliggör körning av skadlig kod utan inloggning. Lyckas det körs koden med PHP-processens rättigheter och kan därmed som regel läsa konfigurationsfilen med databasens inloggningsuppgifter. Prepared statements hjälper inte mot det, eftersom angreppet inte alls går via en SQL-fråga.
Skyldigheten är därför uppdateringen till PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35 och omstart av alla PHP-processer. Finns det tecken på ett lyckat angrepp hör nya databasinloggningar, en granskning av databasen efter insmugglat innehåll och en bedömning av anmälningsplikten enligt GDPR till. Här är en strukturerad incident response meningsfull.
Byt databaslösenord först efter saneringen av servern. Så länge skadlig kod körs kan den läsa ut även nya inloggningsuppgifter igen.
Hur hjälper PHP SOS konkret?
- Vi kontrollerar hur er applikation når databasen och om användare, rättigheter och nätverksåtkomst motsvarar miniminivån.
- Vi kontrollerar att konfigurations- och inloggningsfiler ligger utanför webbroten och inte är offentligt nåbara.
- Efter en incident förnyar vi inloggningsuppgifterna i rätt ordning och granskar databasen efter insmugglad kod.
- Vi dokumenterar resultaten så att dataskyddsombud och försäkringsgivare kan följa dem.
Vanliga frågor
Ska jag använda PDO eller mysqli?
För nya projekt är PDO oftast det flexiblare valet, eftersom det arbetar med många databaser via samma gränssnitt. mysqli är meningsfullt om ni uteslutande använder MySQL eller MariaDB och behöver deras specialfunktioner. Båda är säkra om prepared statements används konsekvent.
Kastar PDO automatiskt undantag vid fel?
Ja, sedan PHP 8.0.0 är PDO::ERRMODE_EXCEPTION standard. Tidigare var det det tysta läget, där fel bara kunde hämtas via errorCode() och errorInfo(). Äldre applikationer sätter ofta läget uttryckligen fortfarande.
Kan platshållare också ersätta tabell- eller kolumnnamn?
Nej. Platshållare står bara för värden. Tabell- och kolumnnamn, till exempel för en sortering, måste kontrolleras mot en fast lista över tillåtna namn innan de sätts in i frågan.
Måste jag byta databaslösenord efter PHP2Shell?
Själva uppdateringen kräver inte det. Finns det dock tecken på att servern har varit komprometterad gäller alla inloggningsuppgifter i konfigurationsfiler som kända. Då bör ni förnya dem efter saneringen.