Aktuellt läge: PHP2Shell. Två kritiska PHP-sårbarheter (CVSS 9,2) tillåter skadlig kod utan inloggning. Patchar sedan den 21 oktober 2026.Vad som bör göras nu →

Förhindra SQL-injektion i PHP

Så utesluter utvecklare tillförlitligt SQL-injektion i PHP-applikationer med Prepared Statements, vitlistor och minimala databasrättigheter.

Aktualitet 5 min läsningGuider

Kort sagt: SQL-injektion i PHP förhindrar ni tillförlitligt genom att aldrig bygga in värden i SQL-texter utan alltid lämna över dem via Prepared Statements med platshållare. För kolumn- och tabellnamn, som inte går att lämna över som platshållare, gäller en fast vitlista. Dessutom begränsar en databasanvändare med minimala rättigheter skadan om en sårbarhet trots allt finns kvar.

Varför SQL-injektion inte får tappas ur sikte efter PHP2Shell

I oktober 2026 handlar mycket om PHP2Shell, två kritiska sårbarheter i PHP-tolken, åtgärdade sedan den 21 oktober 2026 i PHP 8.5.12, 8.4.27, 8.3.36 och 8.2.35. Många team har under de dagarna uppdaterat servrar och startat om processer. Det är rätt och brådskande.

En aktuell PHP-nivå säger dock ingenting om den egna koden. SQL-injektion hör sedan år till de vanligaste svagheterna i webbapplikationer och förs i OWASP Top 10 under kategorin injektion. Den som ändå planerar säkerhetskontroller bör ta med databasåtkomsterna i den egna applikationen direkt.

Det goda beskedet: SQL-injektion är en av få svagheter som går att utesluta nästan helt med en enkel, konsekvent tillämpad regel.

Hur uppstår SQL-injektion i PHP?

SQL-injektion uppstår när en applikation behandlar användarindata som en del av ett SQL-kommando i stället för som rena data. Typiskt är att sätta ihop en fråga av textbitar och variabler. Kan en besökare bestämma innehållet i en sådan variabel kan besökaren under vissa omständigheter ändra kommandots betydelse.

Följderna sträcker sig från att läsa ut andras kunduppgifter via att ändra priser eller rättigheter till att radera hela tabeller. Beroende på databas och rättigheter kan en sårbarhet också ge åtkomst bortom databasen. Berörs personuppgifter kan en anmälningsskyldighet enligt GDPR uppstå.

Indata är inte bara formulärfält. Även URL-parametrar, cookies, HTTP-headers, uppladdade filer, svar från främmande gränssnitt och redan lagrade data från den egna databasen räknas som ej tillförlitliga.

Prepared Statements med PDO och mysqli

Prepared Statements skickar SQL-kommandot och värdena åtskilda till databasen. Värdena tolkas aldrig som en del av kommandot. Med PDO ser en säker fråga ut så här:

<?php
$pdo = new PDO($dsn, $benutzer, $passwort, [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES   => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$stmt = $pdo->prepare('SELECT id, name, email FROM kunden WHERE id = :id AND status = :status');
$stmt->execute([
    'id'     => (int) $_GET['id'],
    'status' => 'aktiv',
]);
$kunde = $stmt->fetch();

Alternativet PDO::ATTR_EMULATE_PREPARES => false ser till att databasen använder äkta Prepared Statements, i den mån drivrutinen stöder det. Med mysqli gäller samma princip:

<?php
$stmt = $mysqli->prepare('SELECT id, name FROM produkte WHERE kategorie = ? AND preis <= ?');
$stmt->bind_param('sd', $kategorie, $maxPreis);
$stmt->execute();
$ergebnis = $stmt->get_result();

Även listor för IN (...) går att återge säkert genom att skapa en egen platshållare för varje värde och lämna över värdena separat.

<?php
$ids = array_map('intval', $ausgewaehlteIds);
$platzhalter = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT id, name FROM produkte WHERE id IN ($platzhalter)");
$stmt->execute($ids);

Specialfall: kolumnnamn, sortering och rå SQL

Platshållare fungerar bara för värden, inte för tabellnamn, kolumnnamn eller sorteringsriktningar. Just här uppstår i praktiken många sårbarheter, till exempel vid sorterbara tabeller eller filter. Lösningen är en fast lista med tillåtna värden:

<?php
$erlaubteSpalten = ['name' => 'name', 'preis' => 'preis', 'datum' => 'erstellt_am'];
$spalte   = $erlaubteSpalten[$_GET['sort'] ?? ''] ?? 'name';
$richtung = (($_GET['dir'] ?? '') === 'desc') ? 'DESC' : 'ASC';

$stmt = $pdo->query("SELECT id, name, preis FROM produkte ORDER BY $spalte $richtung");

Ramverk och CMS har egna verktyg med sig. I WordPress sköter $wpdb->prepare() den uppgiften, i Laravel och Symfony frågebyggarna och ORM:erna. Så snart ni använder rå SQL där, till exempel via funktioner med ”raw” i namnet, gäller reglerna i det här avsnittet igen. Anvisningar om Laravel finns under Säkra Laravel-applikationer.

Tips

Sök riktat i koden efter SQL-texter där variabler sätts in. En enkel början är en sökning efter query( och ->raw i kombination med $_GET, $_POST eller $_REQUEST.

Spåra SQL-injektion i befintlig kod

I ny programvara går regeln att hålla från början. Svårare är det i applikationer som vuxit under flera år. Där lönar sig en systematisk sökning efter ställen där SQL-texter sätts ihop med variabler:

# SQL-kommandon där variabler sätts in
grep -rnE "(SELECT|INSERT|UPDATE|DELETE)[^;]*\\\$[a-zA-Z_]" src/ --include="*.php" | head -50
# Direkt användning av förfrågningsdata i frågefunktioner
grep -rnE "(query|exec|raw)\s*\(.*\\\$_(GET|POST|REQUEST|COOKIE)" src/ --include="*.php"

Alla träffar är inte sårbarheter, till exempel när variabeln bara innehåller ett fast tabellnamn. Varje fyndplats bör dock en gång granskas medvetet och vid behov ställas om till Prepared Statements. Verktyg för statisk kodanalys hjälper till att varaktigt upptäcka sådana mönster i bygg-pipelinen, så att nya fel inte ens går i drift.

Begränsa skadan: rättigheter, felmeddelanden, kontroll

Säker kod är det första försvaret. Fler nivåer begränsar skadan om en sårbarhet ändå förbises:

  • Minimala rättigheter: Webbplatsens databasanvändare behöver oftast bara SELECT, INSERT, UPDATE och DELETE på den egna databasen, inga rättigheter att skapa användare eller komma åt andra databaser.
  • Inga felmeddelanden utåt: display_errors = Off i php.ini. Databasfel hör hemma i loggen, inte i webbläsaren.
  • Separation per applikation: Varje webbplats får en egen databasanvändare.
  • Håll beroenden aktuella: Sårbarheter finns också i bibliotek, som guiden composer audit visar.
  • Låt granska: Kodgranskning och automatiserad analys hittar många ställen, ett penetrationstest visar vad som faktiskt nås utifrån.
-- Exempel: databasanvändare bara med nödvändiga rättigheter
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY '<starkes Passwort>';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop_app'@'localhost';

En närliggande svaghet gäller utmatningen av data i webbläsaren. Hur ni skyddar den förklarar guiden Förhindra cross-site scripting i PHP.

Hur hjälper PHP SOS konkret?

  • Vi granskar systematiskt er applikations databasåtkomster efter osäkra frågor.
  • Vi prioriterar fynd efter nåbarhet och berörda uppgifter och visar konkreta rättelser.
  • Vi sätter databasrättigheter och felhantering på en säker nivå.
  • Vi testar på nytt efter rättelsen och dokumenterar resultatet.

En oberoende granskning beskriver tjänsten Säkerhetsgranskning och penetrationstest.

Vanliga frågor

Räcker det att behandla indata med addslashes eller real_escape_string?

Nej, det är felbenäget. Escaping beror på teckenuppsättning och sammanhang och glöms lätt bort på något ställe. Prepared Statements skiljer principiellt kommando och data åt och är därför den rekommenderade vägen.

Skyddar en ORM automatiskt mot SQL-injektion?

I stor utsträckning, så länge ni använder ORM:ets frågefunktioner. Så snart ni skriver rå SQL eller sätter in värden i sorteringar och kolumnnamn gäller samma regler som utan ORM.

Hjälper en Web Application Firewall mot SQL-injektion?

En WAF kan fånga upp kända mönster och ge tid. Den ersätter dock inte säker kod, eftersom regler som bygger på förfrågningsdata går att kringgå och ibland träffar legitim indata.

Stänger PHP-uppdateringen mot PHP2Shell även sårbarheter för SQL-injektion?

Nej. PHP2Shell berör PHP-tolken. SQL-injektion är ett fel i applikationskoden och finns kvar oavsett vilken PHP-version som körs.

Källor

Direktkontakt

Varje timme räknas. Skriv till oss nu.

Beskriv kort system, PHP-version och observation. Vi hör av oss, klarlägger läget och arbetar på distans tills incidenten är avslutad och dokumenterad.

Direkthjälp