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 →

Validera och filtrera inmatning i PHP med filter_var

Hur utvecklare kontrollerar inmatning i PHP med filter_var, filter_input_array och tillåtelselistor, vilka filter som är föråldrade och varför validering inte ersätter prepared statements och utdatakodning.

Aktualitet 5 min läsningSäker utveckling

Kort sagt: Inmatning i PHP validerar ni med filter_var() eller filter_input_array() och tydliga regler per fält: typ, intervall, längd och tillåtna värden. Det som inte passar avvisas, det byggs inte tyst om. Validering är viktig för rena data och mindre angreppsyta men ersätter varken prepared statements mot SQL-injektion eller kontextanpassad kodning mot XSS.

Varför ”filtrera allt” inte är något koncept

I många äldre PHP-projekt finns i början av varje fil en loop som skickar alla värden från $_GET och $_POST genom en saneringsfunktion. Det känns säkert. I praktiken tar den ibland bort för mycket, till exempel apostrofer i efternamn, och ibland för lite, eftersom samma funktion ska gälla för SQL, HTML och filnamn samtidigt.

Meningsfull validering fungerar annorlunda: Den frågar för varje fält vad som är tillåtet. En beställd mängd är ett heltal mellan 1 och en övre gräns. Ett sorteringsfält är ett av tre fasta värden. Ett datum föreligger i ett bestämt format och ligger efter ett annat datum. Allt annat avvisas.

OWASP skiljer här mellan två nivåer: den syntaktiska kontrollen av om ett värde har rätt form och den semantiska kontrollen av om det är rimligt i sammanhanget. Båda hör hemma på servern; kontroller i webbläsaren tjänar bara användbarheten.

Vilka filter PHP har med sig

Filtertillägget ingår i PHP som standard. De viktigaste valideringsfiltren enligt PHP-manualen:

Filter Kontrollerar Viktiga alternativ och anmärkningar
FILTER_VALIDATE_INT heltal min_range, max_range
FILTER_VALIDATE_FLOAT decimaltal decimal för skiljetecknet
FILTER_VALIDATE_BOOL sanningsvärde med FILTER_NULL_ON_FAILURE skiljbart från ”falskt”
FILTER_VALIDATE_EMAIL formen på en e-postadress bevisar inte att postlådan finns
FILTER_VALIDATE_URL formen på en URL kontrollera schemat själv, inga internationaliserade domäner
FILTER_VALIDATE_IP IP-adress flaggor för privata och reserverade områden
FILTER_VALIDATE_REGEXP eget mönster förankra mönstret med ^ och $

Saneringsfiltret FILTER_SANITIZE_STRING är föråldrat sedan PHP 8.1. Den som fortfarande använder det bör ställa om valideringen till lämpliga filter och använda htmlspecialchars() vid utmatning.

filter_var i PHP: kontrollera ett formulär rent

Med filter_input_array() går det att kontrollera ett helt formulär i ett steg mot en definition. Okända fält tas då inte med:

<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // Skriv ut felmeddelande per fält, bearbeta inte inmatningen
}

Observera de strikta jämförelserna med ===: Ett giltigt värde 0 eller en tom sträng får inte förväxlas med ett misslyckande. Varför lösa jämförelser är farliga här förklarar Type juggling: lösa jämförelser som säkerhetsrisk. Hur PHP över huvud taget tillhandahåller förfrågningsdata beskriver Superglobals: $_GET, $_POST, $_FILES med flera.

Fallgropar med e-post, URL och fri text

Vissa filter gör mindre än namnet låter påskina:

  1. URL:er: FILTER_VALIDATE_URL accepterar även andra scheman än http och https. Kontrollera schemat därefter med parse_url() mot en fast lista. Hämtas URL:en av servern gäller ytterligare regler, se Förhindra Server-Side Request Forgery i PHP.
  2. E-postadresser: Filtret kontrollerar formen, inte ägandet. Den som måste vara säker skickar en bekräftelselänk.
  3. Fri text: Namn, meddelanden och adresser går knappast att begränsa meningsfullt till vissa tecken. Kontrollera längd och teckenkodning, till exempel med mb_check_encoding($wert, 'UTF-8'), och förlita er vid utmatning på kodning.
  4. Reguljära uttryck: Utan ^ och $ kontrollerar ett mönster bara om det förekommer någonstans i texten, inte om hela värdet passar.
  5. Arrayer i stället för strängar: En angripare kan skicka en array i stället för en text. Utan typkontroll leder det till varningar eller oväntat beteende.
Tips

För fasta urvalsvärden som sortering, språk eller fraktsätt är en tillåtelselista med in_array($wert, $erlaubt, true) eller ett match-uttryck enklare och strängare än varje reguljärt uttryck.

Ett ytterligare vanligt fel gäller tal med betydelse, till exempel priser, mängder eller rabatter. Att ett värde är ett giltigt tal säger ingenting om huruvida det är tillåtet i sammanhanget. En negativ mängd, en rabatt över varuvärdet eller ett pris som hämtas från formuläret i stället för från databasen är klassiska logikfel. Priser, behörigheter och statusvärden hör därför alltid hemma på servern och aldrig i dolda formulärfält.

JSON, webhooks och importer: validering bortom formulär

Många ingångar är i dag inte längre formulär utan JSON-förfrågningar från appar, webhooks från betaltjänster eller importfiler från leverantörer. Även där gäller: läs först in säkert, kontrollera sedan. OWASP råder att begränsa storlek och nästlingsdjup innan data över huvud taget läses in. I PHP tar json_decode() med ett maximalt djup och JSON_THROW_ON_ERROR hand om en del av det:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // högst 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}

Vid webhooks kommer före den innehållsliga kontrollen frågan om meddelandet verkligen kommer från den angivna tjänsten. Erbjuder tjänsten en signatur kontrollerar ni den och jämför med hash_equals(). Vid importfiler kontrollerar ni varje rad som ett formulär och avbryter rent vid fel i stället för att ta över halva datapost.

Felmeddelanden bör ange det berörda fältet men inte returnera det avvisade värdet ofiltrerat. Annars uppstår en ny utmatningsplats i själva felmeddelandet, som återigen måste kodas.

Vad validering inte kan åstadkomma

Validering minskar angreppsytan, men den är enligt OWASP inte det främsta försvaret mot injektion. Ett efternamn med apostrof är giltigt och måste ändå ta sig säkert in i en databas. Det lyckas bara med prepared statements, som guiden Förhindra SQL-injektion i PHP visar. Och en giltig kommentartext blir ofarlig först genom kontextanpassad kodning vid utmatning.

Rätt ordning är alltså: validera vid mottagandet, parametrisera vid bearbetningen, koda vid utmatningen. Dessutom hör storleksgränser dit i förväg: Förfrågningar som är alldeles för stora bör webbserver och PHP inte ens bearbeta fullständigt. Dit hör inställningar som post_max_size, som efter PHP2Shell ändå bör kontrolleras.

Hur hjälper PHP SOS konkret?

  • Vi registrerar alla ingångar i er applikation: formulär, gränssnitt, uppladdningar, importer och webhooks.
  • Vi fastställer per fält vad som är tillåtet och ersätter generella saneringsfunktioner med tydliga kontroller.
  • Vi kontrollerar om databasåtkomster och utmatningar är säkrade oberoende av valideringen.
  • Vi dokumenterar reglerna så att ert team kan föra dem vidare vid nya funktioner.

En systematisk granskning beskriver tjänsten säkerhetsaudit och penetrationstest.

Vanliga frågor

Vad är skillnaden mellan att validera och att sanera?

Validering kontrollerar om ett värde motsvarar förväntningarna och avvisar det annars. Sanering ändrar värdet, till exempel genom att tecken tas bort. För säkerhetsbeslut är avvisande nästan alltid bättre, eftersom ett i tysthet ändrat värde kan ge nya fel.

Går FILTER_SANITIZE_STRING fortfarande att använda?

Filtret är markerat som föråldrat sedan PHP 8.1. PHP-manualen rekommenderar i stället htmlspecialchars() vid utmatning. Befintlig kod bör ni ställa om, eftersom föråldrade funktioner kan försvinna i framtida versioner.

Räcker FILTER_VALIDATE_URL för att göra länkar säkra?

Nej. Filtret kontrollerar bara adressens form. Enligt manualen behöver en giltig URL inte börja med http, därför måste ni själva kontrollera schemat mot en tillåtelselista som https. Internationaliserade domännamn avvisar filtret.

Måste jag också validera data från min egen databas?

Vid utmatning räknas de som inte betrodda och kodas på lämpligt sätt. En ny validering är rimlig när datan ursprungligen kom utifrån och nu används i ett nytt sammanhang, till exempel som filnamn eller del av ett kommando.

Hjälper validering mot PHP2Shell?

Nej. PHP2Shell gäller hanteringen av förfrågningar i PHP-tolken innan er applikationskod över huvud taget körs. Mot det hjälper bara PHP-uppdateringen med efterföljande omstart av alla PHP-processer.

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