# Syötteiden validointi ja suodatus PHP:ssä filter_varilla

> Syötteet PHP:ssä filter_varilla ja filter_input_arraylla: luvut, sähköposti, URL, bool, sallittujen luettelot ja rajat. Koodiesimerkkien kanssa.

Lähde: https://phpsos.de/fi/blog/eingaben-validieren-php/  
Tilanne: 25.10.2026  
Palveluntarjoaja: PHP SOS, PHP-hätäapu ja palvelimen tietoturva. Pikaapu WhatsAppilla: https://wa.me/491736494914?text=Hei%20PHP%20SOS%2C%20tarvitsemme%20apua%20PHP-palvelimemme%20kanssa.%20Yritys%3A%20%E2%80%A6%20Verkkosivusto%3A%20%E2%80%A6

**Lyhyesti:** Syötteet validoitte PHP:ssä funktiolla `filter_var()` tai `filter_input_array()` ja selkeillä säännöillä kenttäkohtaisesti: tyyppi, alue, pituus ja sallitut arvot. Mikä ei sovi, hylätään eikä muokata äänettömästi. Validointi on tärkeää siistien tietojen ja pienemmän hyökkäyspinnan kannalta, mutta ei korvaa SQL-injektiota vastaan valmisteltuja lauseita eikä XSS:ää vastaan asiayhteyden mukaista koodausta.

## Miksi ”suodata kaikki” ei ole konsepti

Monen vanhemman PHP-projektin jokaisen tiedoston alussa on silmukka, joka ajaa kaikki `$_GET`- ja `$_POST`-arvot puhdistusfunktion läpi. Se tuntuu turvalliselta. Käytännössä se poistaa välillä liikaa, esimerkiksi heittomerkit sukunimistä, ja välillä liian vähän, koska saman funktion pitäisi toimia samanaikaisesti SQL:lle, HTML:lle ja tiedostonimille.

Järkevä validointi toimii toisin: se kysyy jokaisesta kentästä, mikä siellä on sallittua. Tilausmäärä on kokonaisluku väliltä 1 ja yläraja. Lajittelukenttä on yksi kolmesta kiinteästä arvosta. Päivämäärä on tietyssä muodossa ja toisen päivämäärän jälkeen. Kaikki muu hylätään.

OWASP erottaa tässä kaksi tasoa: **syntaktisen** tarkistuksen, onko arvolla oikea muoto, ja **semanttisen** tarkistuksen, onko se asiayhteydessä järkevä. Molemmat kuuluvat palvelimelle; selaimessa tehtävät tarkistukset palvelevat vain käytettävyyttä.

## Mitä suodattimia PHP tarjoaa

Suodatinlaajennus kuuluu PHP:n vakiotoimitukseen. Tärkeimmät validointisuodattimet PHP-käsikirjan mukaan:

| Suodatin | Tarkistaa | Tärkeät asetukset ja huomautukset |
|---|---|---|
| `FILTER_VALIDATE_INT` | kokonaisluku | `min_range`, `max_range` |
| `FILTER_VALIDATE_FLOAT` | desimaaliluku | `decimal` erottimelle |
| `FILTER_VALIDATE_BOOL` | totuusarvo | asetuksella `FILTER_NULL_ON_FAILURE` erotettavissa arvosta ”epätosi” |
| `FILTER_VALIDATE_EMAIL` | sähköpostiosoitteen muoto | ei todista, että postilaatikko on olemassa |
| `FILTER_VALIDATE_URL` | URL-osoitteen muoto | skeema tarkistettava itse, ei kansainvälistettyjä verkkotunnuksia |
| `FILTER_VALIDATE_IP` | IP-osoite | liput yksityisille ja varatuille alueille |
| `FILTER_VALIDATE_REGEXP` | oma kuvio | ankkuroikaa kuvio merkeillä `^` ja `$` |

Puhdistussuodatin `FILTER_SANITIZE_STRING` on vanhentunut PHP 8.1:stä alkaen. Joka käyttää sitä vielä, kannattaa siirtää validointi sopiviin suodattimiin ja käyttää tulosteessa funktiota `htmlspecialchars()`.

## filter_var PHP:ssä: lomakkeen siisti tarkistus

Funktiolla `filter_input_array()` koko lomakkeen voi tarkistaa yhdellä kertaa määritelmää vasten. Tuntemattomia kenttiä ei oteta mukaan:

```php
<?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);
    // Tulosta virheilmoitus kentittäin, älä käsittele syötteitä
}
```

Huomatkaa tiukat vertailut `===`: kelvollista arvoa `0` tai tyhjää merkkijonoa ei saa sekoittaa epäonnistumiseen. Miksi löyhät vertailut ovat tässä vaarallisia, selittää [Type juggling: löyhät vertailut tietoturvariskinä](https://phpsos.de/fi/blog/type-juggling-php/). Miten PHP ylipäätään tarjoaa pyyntötiedot, kuvaa [Superglobalit: $_GET, $_POST, $_FILES ja muut](https://phpsos.de/fi/php/superglobals/).

## Sudenkuopat sähköpostissa, URL-osoitteissa ja vapaissa teksteissä

Jotkin suodattimet tekevät vähemmän kuin niiden nimi antaa ymmärtää:

1. **URL-osoitteet:** `FILTER_VALIDATE_URL` hyväksyy myös muita skeemoja kuin http ja https. Tarkistakaa skeema sen jälkeen funktiolla `parse_url()` kiinteää luetteloa vasten. Jos palvelin hakee URL-osoitteen, pätevät lisäsäännöt, katso [Server-Side Request Forgeryn estäminen PHP:ssä](https://phpsos.de/fi/blog/ssrf-in-php/).
2. **Sähköpostiosoitteet:** Suodatin tarkistaa muodon, ei omistajuutta. Joka tarvitsee varmuuden, lähettää vahvistuslinkin.
3. **Vapaa teksti:** Nimiä, viestejä ja osoitteita ei voi järkevästi rajata merkkien perusteella. Tarkistakaa pituus ja merkistökoodaus, esimerkiksi funktiolla `mb_check_encoding($wert, 'UTF-8')`, ja luottakaa tulosteessa koodaukseen.
4. **Säännölliset lausekkeet:** Ilman merkkejä `^` ja `$` kuvio tarkistaa vain, esiintyykö se jossain kohtaa tekstiä, ei sitä, sopiiko koko arvo.
5. **Taulukot merkkijonojen sijaan:** Hyökkääjä voi lähettää tekstin sijaan taulukon. Ilman tyyppitarkistusta se johtaa varoituksiin tai odottamattomaan käytökseen.

> **Vinkki:**
> Kiinteille valinta-arvoille kuten lajittelulle, kielelle tai toimitustavalle sallittujen luettelo funktiolla `in_array($wert, $erlaubt, true)` tai `match`-lausekkeella on yksinkertaisempi ja tiukempi kuin mikään säännöllinen lauseke.

Toinen yleinen virhe koskee merkityksellisiä lukuja, kuten hintoja, määriä tai alennuksia. Se, että arvo on kelvollinen luku, ei kerro, onko se asiayhteydessä sallittu. Negatiivinen määrä, tavaran arvoa suurempi alennus tai hinta, joka otetaan lomakkeesta tietokannan sijaan, ovat klassisia logiikkavirheitä. Hinnat, oikeudet ja tilat kuuluvat siksi aina palvelimelle eivätkä koskaan piilotettuihin lomakekenttiin.

## JSON, webhookit ja tuonnit: validointi lomakkeiden ulkopuolella

Monet syötteet eivät nykyään ole lomakkeita vaan sovellusten JSON-pyyntöjä, maksupalvelujen webhookeja tai toimittajien tuontitiedostoja. Niissäkin pätee: lukekaa ensin turvallisesti, tarkistakaa sitten. OWASP neuvoo rajaamaan koon ja sisäkkäisyyden syvyyden ennen kuin tietoja ylipäätään luetaan. PHP:ssä `json_decode()` enimmäissyvyydellä ja `JSON_THROW_ON_ERROR`-asetuksella hoitaa osan tästä:

```php
<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // enintään 64 kt
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;
}
```

Webhookeissa ennen sisällön tarkistusta on kysymys, tuleeko viesti todella ilmoitetulta palvelulta. Jos palvelu tarjoaa allekirjoituksen, tarkistakaa se ja vertailkaa funktiolla `hash_equals()`. Tuontitiedostoissa tarkistakaa jokainen rivi kuin lomake ja keskeyttäkää virheessä siististi sen sijaan, että otettaisiin vastaan osittaisia tietueita.

Virheilmoitusten tulisi nimetä kyseinen kenttä, mutta ei palauttaa hylättyä arvoa suodattamattomana. Muuten virheilmoitukseen syntyy uusi tulostekohta, joka on koodattava uudelleen.

## Mitä validointi ei voi tehdä

Validointi pienentää hyökkäyspintaa, mutta OWASPin mukaan se ei ole pääpuolustus injektiota vastaan. Heittomerkillinen sukunimi on kelvollinen ja sen on silti päästävä turvallisesti tietokantaan. Se onnistuu vain valmistelluilla lauseilla, kuten opas [SQL-injektion estäminen PHP:ssä](https://phpsos.de/fi/ratgeber/sql-injection-php/) osoittaa. Ja kelvollisesta kommenttitekstistä tulee vaaratonta vasta tulosteen asiayhteyden mukaisella koodauksella.

Oikea järjestys on siis: validoi vastaanotettaessa, parametrisoi käsiteltäessä, koodaa tulostettaessa. Lisäksi kokorajat kuuluvat ennen niitä: aivan liian suuria pyyntöjä verkkopalvelimen ja PHP:n ei pitäisi edes käsitellä kokonaan. Siihen palvelevat asetukset kuten `post_max_size`, jotka PHP2Shellin jälkeen kannattaa joka tapauksessa tarkistaa.

## Miten PHP SOS auttaa konkreettisesti?

- Kartoitamme sovelluksenne kaikki syötteet: lomakkeet, rajapinnat, uploadit, tuonnit ja webhookit.
- Määrittelemme kenttäkohtaisesti, mikä on sallittua, ja korvaamme yleiset puhdistusfunktiot selkeillä tarkistuksilla.
- Tarkistamme, ovatko tietokantakutsut ja tulosteet suojattu validoinnista riippumatta.
- Dokumentoimme säännöt niin, että tiiminne voi jatkaa niitä uusien toimintojen yhteydessä.

Järjestelmällisen tarkistuksen kuvaa palvelu [tietoturva-auditointi ja tunkeutumistesti](https://phpsos.de/fi/leistungen/sicherheitsaudit-penetrationstest/).


## Usein kysytyt kysymykset

**Mitä eroa on validoinnilla ja puhdistuksella?**  
Validointi tarkistaa, vastaako arvo odotuksia, ja hylkää sen muuten. Puhdistus muuttaa arvoa, esimerkiksi poistamalla merkkejä. Tietoturvapäätöksissä hylkääminen on lähes aina parempi, koska äänettömästi muutettu arvo voi aiheuttaa uusia virheitä.

**Onko FILTER_SANITIZE_STRING vielä käyttökelpoinen?**  
Suodatin on merkitty vanhentuneeksi PHP 8.1:stä alkaen. PHP-käsikirja suosittelee sen sijaan funktiota htmlspecialchars() tulosteessa. Olemassa oleva koodi kannattaa muuttaa, koska vanhentuneet funktiot voivat poistua tulevista versioista.

**Riittääkö FILTER_VALIDATE_URL linkkien turvaamiseen?**  
Ei. Suodatin tarkistaa vain osoitteen muodon. Käsikirjan mukaan kelvollisen URL-osoitteen ei tarvitse alkaa http:llä, joten skeema on tarkistettava itse sallittujen luetteloa vasten, esimerkiksi https. Kansainvälistetyt verkkotunnukset suodatin hylkää.

**Pitääkö myös oman tietokannan tiedot validoida?**  
Tulosteessa niitä ei pidetä luotettavina, ja ne koodataan asianmukaisesti. Uusi validointi on järkevä, jos tiedot ovat alun perin tulleet ulkopuolelta ja niitä käytetään nyt uudessa yhteydessä, esimerkiksi tiedostonimenä tai komennon osana.

**Auttaako validointi PHP2Shelliä vastaan?**  
Ei. PHP2Shell koskee pyyntöjen käsittelyä PHP-tulkissa, ennen kuin sovelluskoodinne edes toimii. Sitä vastaan auttaa vain PHP-päivitys ja kaikkien PHP-prosessien uudelleenkäynnistys.

## Lähteet

- [PHP-käsikirja: suodatinvakiot](https://www.php.net/manual/de/filter.constants.php)
- [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
