Lyhyesti: PHP:n API-tietoturvassa korostuu viisi kohtaa: vain HTTPS, tunnistautuminen jokaisessa ei-julkisessa päätepisteessä, käyttöoikeuksien tarkistus jokaiselle yksittäiselle oliolle, tiukat rajat pyynnön menetelmälle, sisältötyypille ja koolle sekä ytimekkäät virheilmoitukset ilman sisäisiä yksityiskohtia. Lisäksi tulevat nopeusrajoitus ja loki tietoturvan kannalta olennaisista tapahtumista. PHP-tulkin omia aukkoja kuten PHP2Shelliä vastaan tämä ei auta; siihen tarvitaan PHP-päivitys.
Verkkosivuston takana oleva rajapinta
Moni yritys tarkisti verkkosivustonsa viikolla 21.10.2026 jälkeen. Niiden takana olevat rajapinnat olivat harvemmin listalla. Silti juuri siellä kulkevat arkaluonteiset tapahtumat: asiakasportaalin sovellus hakee laskuja, tavaranhallintajärjestelmä kirjoittaa varastosaldot verkkokauppaan, kumppani ilmoittaa tilauksia webhookilla. Usein nämä API:t rakennettiin nopeasti yhtä tarkoitusta varten, eikä niitä sen jälkeen katsottu koskaan uudelleen.
API:lla ei ole käyttöliittymää, joka tekisi virheet näkyviksi. Puuttuva käyttöoikeustarkistus ei kiinnitä arjessa kenenkään huomiota, kunhan kaikki asiakkaat kyselevät vain sen, mitä niiden kuuluu. Hyökkääjä sen sijaan kokeilee juuri sitä, mitä ei ole tarkoitettu.
Ensimmäinen askel on siksi kartoitus. Mitä päätepisteitä ylipäätään on? Usein löytyy vanhoja versioita kuten /api/v1/, joita ei koskaan kytketty pois siirryttäessä versioon /v2/, kehityksen testipäätepisteitä tai julkisesti haettavissa oleva rajapintakuvaus, joka luettelee sisäisiä toimintoja. Jokainen päätepiste, jota ei enää tarvita, tulisi kytkeä pois. Jokaisella, joka jää, tarvitaan vastuuhenkilö.
API-tietoturva PHP:ssä: perussäännöt
OWASP REST Security Cheat Sheet kokoaa yhteen hyväksi havaitut säännöt. PHP-projekteille ne voi kääntää lyhyeksi luetteloksi:
- Vain HTTPS. Tokeneita ja tunnuksia ei saa koskaan siirtää salaamattomina.
- Jokainen päätepiste tarkistaa itse. Tunnistautuminen voi tapahtua keskitetysti, päätös pääsystä tehdään päätepisteessä.
- Käyttöoikeus olioittain. Ei vain ”on kirjautunut” vaan ”saa käyttää juuri tätä tietuetta”.
- Määritelkää sallitut menetelmät. Mitä ei nimenomaisesti sallita, hylätään vastauksella 405.
- Tarkistakaa sisältötyyppi ja koko. Väärä tyyppi tuottaa 415, liian suuret pyynnöt 413.
- Validoikaa syötteet. Tyyppi, pituus, muoto ja arvoalue palvelinpuolella.
- Ei salaisuuksia URL-osoitteissa. Tokenit ja avaimet kuuluvat otsikoihin, ei kyselymerkkijonoon.
- Ytimekkäät virheet. Ei pinojälkiä, polkuja tai SQL-ilmoituksia asiakkaalle.
- Nopeusrajoitus. Liian monet pyynnöt vastataan 429:llä.
- Suojatkaa hallintapäätepisteet. Ei julkisesti saavutettavissa tai vain vahvalla kirjautumisella.
Olion käyttöoikeus: yleisin virhe
Esimerkki tekee ongelman ymmärrettäväksi. Päätepiste palauttaa laskuja osoitteessa /api/rechnungen/{id}. Tarkistetaan, onko kelvollinen token. Ei tarkisteta, kuuluuko lasku tokenin asiakkaalle. Joka nostaa oman laskunumeronsa yhdellä, näkee naapurin laskun.
Ratkaisu on yksinkertainen, ja se on silti toteutettava joka paikassa: kysely itse rajaa sallittuun alueeseen.
<?php
// Salli vain menetelmä GET
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
header('Allow: GET');
exit;
}
$kundeId = $auth->kundeId(); // tarkistetusta tokenista
$id = filter_var($routeId, FILTER_VALIDATE_INT);
if ($id === false) {
http_response_code(400);
exit;
}
// Käyttöoikeus on kyselyssä: vain omat laskut
$stmt = $pdo->prepare('SELECT nummer, betrag, datum FROM rechnungen WHERE id = ? AND kunde_id = ?');
$stmt->execute([$id, $kundeId]);
$rechnung = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$rechnung) {
http_response_code(404); // älä paljasta, onko tunnus olemassa
exit;
}
header('Content-Type: application/json');
echo json_encode($rechnung, JSON_THROW_ON_ERROR);
Paikkamerkeillä tehty kysely suojaa samalla SQL-injektiolta, katso SQL-injektion estäminen PHP:ssä. Miten PHP tarjoaa pyyntötiedot kuten menetelmän, otsikot ja rungon, selittää Superglobalit: $_GET, $_POST, $_FILES ja muut.
Tokenien oikea tarkistus
Monet API:t käyttävät JSON Web Tokeneita. OWASPin Cheat Sheet antaa niille selkeät säännöt: tokenien on oltava allekirjoitettuja, allekirjoittamattomat tokenit hylätään, ja tarkistuksen algoritmi määrätään palvelimella eikä oteta tokenista. Myös myöntäjä, kohderyhmä ja vanhenemisaika kuuluvat tarkistukseen. Käyttäkää siihen ylläpidettyä kirjastoa omien toteutusten sijaan.
Omien tokenien, esimerkiksi webhookeille tai kertakäyttölinkeille, on tultava kryptografisesti turvallisesta satunnaislukugeneraattorista ja ne on vertailtava vakioajassa. Miten se tehdään PHP:ssä, näyttää Turvalliset satunnaisluvut ja tokenit PHP:ssä.
Antakaa jokaiselle asiakkaalle ja kumppanille oma avain, jolla on täsmälleen tarvittavat oikeudet. Silloin vuotanut avain voidaan estää yksittäin keskeyttämättä kaikkia muita yhteyksiä.
Rajojen asettaminen: koko, tyyppi ja tahti
API:n tulisi ottaa vastaan vain se, mitä se odottaa. Se alkaa sisältötyypistä: päätepiste, joka käsittelee JSONia, hylkää kaiken muun. Pyynnön enimmäiskoko rajataan usealla tasolla, verkkopalvelimessa ja PHP:ssä asetuksella post_max_size. Tämä raja kuuluu myös siirtymäajan toimenpiteisiin, jotka php.net on maininnut PHP2Shellin yhteydessä. Miten se valitaan järkevästi, kuvaa post_max_size ja upload_max_filesize järkevästi rajattuina.
Nopeusrajoitus suojaa tunnisteiden läpikokeilulta ja ylikuormitukselta. Se voidaan toteuttaa verkkopalvelimessa, edessä olevassa välityspalvelimessa tai sovelluksessa. Tärkeää on, että rajat koskevat avainta tai käyttäjää eivätkä vain IP-osoitetta.
Suoraan selaimesta kutsuttaville API:ille tulee lisäksi CORS eli säännöt siitä, mitkä vieraat verkkosivustot saavat esittää pyyntöjä. Asettakaa nämä otsikot vain, jos tällaiset kutsut on todella tarkoitettu, ja nimetkää sallitut alkuperät yksitellen sen sijaan, että sallisitte jokaisen alkuperän. Jokeri, joka sallii kaikki verkkosivustot, on kirjautumista käyttävillä päätepisteillä lähes aina virhe.
Viimeisenä loki: epäonnistuneet kirjautumiset, hylätyt tokenit ja evätyt pääsyt kuuluvat lokiin, tokenit itse eivät. Ilman näitä merkintöjä hyökkäys API:a vastaan jää näkymättömäksi.
Miten PHP SOS auttaa konkreettisesti?
- Kartoitamme PHP-järjestelmiesi kaikki rajapinnat, myös unohdetut ja sisäiset, ja tarkistamme, mitkä ovat julkisesti saavutettavissa.
- Luemme käyttöoikeuslogiikan ja testaamme kohdennetusti, ovatko vieraat tietueet haettavissa.
- Asetamme koko-, tyyppi- ja tahtirajat verkkopalvelimeen ja PHP:hen ja sovitamme ne asiakkaidenne kanssa.
- Kattavaa ulkopuolelta tehtävää tarkistusta varten yhdistämme tämän tietoturva-auditointiin ja tunkeutumistestiin.
Yhteenveto: API on yhtä turvallinen kuin sen huolimattomin päätepiste. Joka tarkistaa käyttöoikeudet olioittain, asettaa selkeät rajat ja pitää virheet ytimekkäinä, sulkee yleisimmät aukot kauan ennen kuin kukaan etsii niitä kohdennetusti.
Usein kysytyt kysymykset
Riittääkö API-avain suojaksi?
Arkaluonteisille tiedoille ei. API-avain tunnistaa yleensä sovelluksen, ei käyttäjää, ja se luovutetaan helposti eteenpäin. OWASP REST Security Cheat Sheet neuvoo olemaan käyttämättä API-avaimia ainoana suojana arkaluonteisille resursseille.
Mikä on olion käyttöoikeus ja miksi se puuttuu niin usein?
Sillä tarkoitetaan tarkistusta, saako kirjautunut käyttäjä nähdä tai muuttaa juuri tämän tietueen. Se puuttuu usein, koska kehittäjät tarkistavat vain, onko joku ylipäätään kirjautunut. Silloin riittää muuttaa URL-osoitteessa oleva tunniste, jotta vieraat tiedot ovat haettavissa.
Suojaako hyvin suojattu API PHP2Shelliltä?
Ei. PHP2Shell on PHP-tulkissa ja vaikuttaa kohteena oleviin käyttötapoihin, ennen kuin koodinne edes toimii. Sitä vastaan auttaa vain PHP-päivitys ja uudelleenkäynnistys. Pyyntöjen kokorajat ovat silti järkeviä, ja ne kuuluvat myös php.netin siirtymäajan toimenpiteisiin.
Mitä tilakoodeja API:n tulisi palauttaa tietoturvavirheissä?
Yleisiä ovat 401 ilman kelvollista kirjautumista, 403 puuttuvasta käyttöoikeudesta, 405 kielletystä menetelmästä, 413 liian suuresta pyynnöstä, 415 väärästä sisältötyypistä ja 429 liian monesta pyynnöstä. Vastaus itse pidetään ytimekkäänä ilman sisäisiä yksityiskohtia.