Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Validér og filtrér input i PHP med filter_var

Hvordan udviklere kontrollerer input i PHP med filter_var, filter_input_array og tilladelseslister, hvilke filtre der er forældede, og hvorfor validering ikke erstatter prepared statements og outputkodning.

Status 5 min. læsetidSikker udvikling

Kort sagt: Input i PHP validerer I med filter_var() eller filter_input_array() og klare regler pr. felt: type, område, længde og tilladte værdier. Det, der ikke passer, afvises, ikke stiltiende ombygget. Validering er vigtig for rene data og mindre angrebsflade, men erstatter hverken prepared statements mod SQL-injection eller kontekstrigtig kodning mod XSS.

Hvorfor "filtrér alt" ikke er et koncept

I mange ældre PHP-projekter findes i begyndelsen af hver fil en løkke, der sender alle værdier fra $_GET og $_POST gennem en rensefunktion. Det føles sikkert. I praksis fjerner det nogle gange for meget, f.eks. apostrofer i efternavne, og nogle gange for lidt, fordi den samme funktion skal gælde for SQL, HTML og filnavne på én gang.

Fornuftig validering arbejder anderledes: Den spørger for hvert felt, hvad der er tilladt dér. En bestillingsmængde er et helt tal mellem 1 og en øvre grænse. Et sorteringsfelt er en af tre faste værdier. En dato foreligger i et bestemt format og ligger efter en anden dato. Alt andet afvises.

OWASP skelner her mellem to niveauer: den syntaktiske kontrol af, om en værdi har den rigtige form, og den semantiske kontrol af, om den giver mening i sammenhængen. Begge hører hjemme på serveren; kontroller i browseren tjener kun brugervenligheden.

Hvilke filtre PHP medbringer

Filter-udvidelsen er som standard med i PHP. De vigtigste valideringsfiltre ifølge PHP-manualen:

Filter Kontrollerer Vigtige indstillinger og bemærkninger
FILTER_VALIDATE_INT helt tal min_range, max_range
FILTER_VALIDATE_FLOAT decimaltal decimal for skilletegnet
FILTER_VALIDATE_BOOL sandhedsværdi kan med FILTER_NULL_ON_FAILURE skelnes fra "falsk"
FILTER_VALIDATE_EMAIL form på en e-mailadresse beviser ikke, at postkassen findes
FILTER_VALIDATE_URL form på en URL kontrollér selv skemaet, ingen internationaliserede domæner
FILTER_VALIDATE_IP IP-adresse flag for private og reserverede områder
FILTER_VALIDATE_REGEXP eget mønster forankr mønstret med ^ og $

Rensefilteret FILTER_SANITIZE_STRING er forældet siden PHP 8.1. Den, der stadig bruger det, bør omstille valideringen til passende filtre og bruge htmlspecialchars() til output.

filter_var i PHP: kontrollér en formular ordentligt

Med filter_input_array() kan en hel formular kontrolleres i ét trin mod en definition. Ukendte felter overtages ikke:

<?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);
    // Udskriv fejlmeddelelse pr. felt, behandl ikke input
}

Bemærk de strikte sammenligninger med ===: En gyldig værdi 0 eller en tom streng må ikke forveksles med en fejl. Hvorfor løse sammenligninger er farlige her, forklarer Type juggling: Løse sammenligninger som sikkerhedsrisiko. Hvordan PHP overhovedet stiller forespørgselsdata til rådighed, beskriver Superglobals: $_GET, $_POST, $_FILES og co..

Faldgruber ved e-mail, URL og fri tekst

Nogle filtre gør mindre, end deres navn lader formode:

  1. URL'er: FILTER_VALIDATE_URL accepterer også andre skemaer end http og https. Kontrollér bagefter skemaet med parse_url() mod en fast liste. Hentes URL'en af serveren, gælder yderligere regler, se Forhindr Server-Side Request Forgery i PHP.
  2. E-mailadresser: Filteret kontrollerer formen, ikke ejerskabet. Den, der skal være sikker, sender et bekræftelseslink.
  3. Fri tekst: Navne, beskeder og adresser lader sig næppe fornuftigt begrænse på tegn. Kontrollér længde og tegnkodning, f.eks. med mb_check_encoding($wert, 'UTF-8'), og stol ved output på kodning.
  4. Regulære udtryk: Uden ^ og $ kontrollerer et mønster kun, om det forekommer et sted i teksten, ikke om hele værdien passer.
  5. Arrays i stedet for strenge: En angriber kan sende et array i stedet for en tekst. Uden typekontrol fører det til advarsler eller uventet adfærd.
Tip

Til faste valgværdier som sortering, sprog eller forsendelsesmåde er en tilladelsesliste med in_array($wert, $erlaubt, true) eller et match-udtryk enklere og strengere end ethvert regulært udtryk.

En anden hyppig fejl berører tal med betydning, f.eks. priser, mængder eller rabatter. At en værdi er et gyldigt tal, siger intet om, om den er tilladt i sammenhængen. En negativ mængde, en rabat over varens værdi eller en pris, der overtages fra formularen i stedet for fra databasen, er klassiske logikfejl. Priser, rettigheder og statusværdier hører derfor altid hjemme på serveren og aldrig i skjulte formularfelter.

JSON, webhooks og importer: Validering ud over formularer

Mange indgange er i dag ikke længere formularer, men JSON-forespørgsler fra apps, webhooks fra betalingstjenester eller importfiler fra leverandører. Også dér gælder: først indlæs sikkert, så kontrollér. OWASP råder til at begrænse størrelse og indlejringsdybde, før data overhovedet indlæses. I PHP overtager json_decode() med en maksimal dybde og JSON_THROW_ON_ERROR en del af det:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // højst 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;
}

Ved webhooks står spørgsmålet, om meddelelsen virkelig stammer fra den angivne tjeneste, før den indholdsmæssige kontrol. Tilbyder tjenesten en signatur, kontrollerer I den og sammenligner med hash_equals(). Ved importfiler kontrollerer I hver linje som en formular og afbryder rent ved fejl i stedet for at overtage halve datasæt.

Fejlmeddelelser bør nævne det berørte felt, men ikke returnere den afviste værdi ufiltreret. Ellers opstår der ved selve fejlmeddelelsen et nyt outputsted, som igen skal kodes.

Hvad validering ikke kan klare

Validering mindsker angrebsfladen, men er ifølge OWASP ikke hovedforsvaret mod injection. Et efternavn med apostrof er gyldigt og skal alligevel nå sikkert ind i en database. Det lykkes kun med prepared statements, som vejledningen Forhindr SQL-injection i PHP viser. Og en gyldig kommentartekst bliver først ufarlig gennem kontekstrigtig kodning ved output.

Den rigtige rækkefølge er altså: valider ved modtagelsen, parametrisér ved behandlingen, kod ved output. Dertil kommer størrelsesgrænser forud: Forespørgsler, der er langt for store, bør webserver og PHP slet ikke behandle fuldstændigt. Det tjener indstillinger som post_max_size, der efter PHP2Shell alligevel bør kontrolleres.

Hvordan hjælper PHP SOS konkret?

  • Vi registrerer alle indgange i jeres applikation: formularer, grænseflader, uploads, importer og webhooks.
  • Vi fastlægger pr. felt, hvad der er tilladt, og erstatter generelle rensefunktioner med klare kontroller.
  • Vi kontrollerer, om databaseadgange og output er sikret uafhængigt af valideringen.
  • Vi dokumenterer reglerne, så jeres team kan føre dem videre ved nye funktioner.

En systematisk kontrol beskriver ydelsen Sikkerhedsaudit og penetrationstest.

Ofte stillede spørgsmål

Hvad er forskellen mellem at validere og at rense?

Validering kontrollerer, om en værdi svarer til forventningerne, og afviser den ellers. Rensning ændrer værdien, f.eks. ved at tegn fjernes. Til sikkerhedsbeslutninger er afvisning næsten altid bedre, fordi en stiltiende ændret værdi kan skabe nye fejl.

Kan FILTER_SANITIZE_STRING stadig bruges?

Filteret er markeret som forældet siden PHP 8.1. PHP-manualen anbefaler i stedet htmlspecialchars() ved output. Eksisterende kode bør I omstille, fordi forældede funktioner kan bortfalde i fremtidige versioner.

Er FILTER_VALIDATE_URL nok til at gøre links sikre?

Nej. Filteret kontrollerer kun adressens form. Ifølge manualen behøver en gyldig URL ikke at begynde med http, så I må selv kontrollere skemaet mod en tilladelsesliste som https. Internationaliserede domænenavne afviser filteret.

Skal jeg også validere data fra min egen database?

Ved output anses de for ikke at være troværdige og kodes passende. En fornyet validering er fornuftig, hvis dataene oprindeligt kom udefra og nu bruges i en ny sammenhæng, f.eks. som filnavn eller del af en kommando.

Hjælper validering mod PHP2Shell?

Nej. PHP2Shell berører behandlingen af forespørgsler i PHP-fortolkeren, før jeres applikationskode overhovedet kører. Mod det hjælper kun PHP-opdateringen med efterfølgende genstart af alle PHP-processer.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp