TTY / Tietoturvallisuuden jatkokurssi / Harjoitustyö 2012 / Valmis

Sampo Tolvanen

PHP-hyökkäykset

1. Johdanto

PHP (Hypertext Processor) on suosittu, alkuperäisesti dynaamisten www-sivujen luontiin suunniteltu skriptikieli. Web-sovellusten tietoturva on tärkeää, sillä ne ovat usein yhteydessä suuriin tietokantoihin sekä ne voivat olla saatavissa suurelle määrälle käyttäjiä. Web-sovellusten yleisien tietoturva-asioiden lisäksi PHP-kielen ominaisuudet aiheuttavat lisätarpeita tietoturvasta huolehtimiseen. Työn tarkoituksena on antaa lukijalle kuva erilaisilla tasoilla olevista tietoturvauhkista, ja siitä miten niihin voi varautua.

2. Haavoittuvuustyypit

Suurin osa PHP-sovelluksia vastaan tehdyistä hyökkäyksistä perustuu käyttäjän syötteisiin. PHP-kielessä ohjelmoijan ei pääasiassa tarvitse hallita ohjelman muistia itse, mutta PHP:n sisältämät funktiot voivat siitä huolimatta sisältää haavoittuvuuksia jotka mahdollistavat puskurin ylivuodon. PHP:n kautta voi syntyä myös suoraan käyttäjiin vaikuttavia uhkia. PHP:n luomat keksit ja sessiot on mahdollista kaapata [1], jolloin esimerkiksi käyttäjän tietoa voi paljastua. PHP-ohjelmoijan on hyvä olla tietoinen haavoittuvuuksista, varsinkin jos käyttää vanhaa PHP-versiota. Mikäli käytössä on haavoittuva PHP:n versio, se on altis hyökkäyksille, koska myös hyökkääjät tarkastelevat haavoittuvuuksien listaa. Vanha ja haavoittuva PHP-versio on syytä päivittää uudempaan. Mikäli mahdollinen ulkoinen palveluntarjoaja ei toteuta päivitystoimenpiteitä, sivuston voi harkita sijoittavansa muualle. Tämä työ keskittyy käyttäjän syötteistä syntyviin tietoturvaongelmiin.

3. Vapaamuotoinen syöte

3.1. Syötteiden haavoittuvuus

Käyttäjä voi antaa PHP:lle syötettä lukuisilla eri tavoilla. Yleisimmät näistä ovat muuttujat $_GET ja $_POST [2]. Muuttuja $_GET saa tyypillisesti arvonsa lomakkeen tai selaimen osoiterivin kautta. Muuttujan $_POST on tarkoitus sisältää käyttäjän lähettämiä lomaketietoja. Ei tule kuitenkaan unohtaa, että muissakin käyttäjältä saaduissa tiedoissa, kuten selaimen versiossa voi olla vapaamuotoista syötettä. Yleisimpien tapojen joukossa hyökätä näitä muuttujia käyttäen ovat esimerkiksi tietokantasovellusten SQL-injektiot sekä XSS eli Cross Site Scripting. Yksi tärkeimmistä ohjeista on, että käyttäjän syötteeseen ei pidä luottaa. Syötteen tarkistaminen on erityisen tärkeää silloin, kun siitä muodostetaan suoritettavaa koodia. Myös esimerkiksi muuttujien alustus johonkin järkevään arvoon voi parantaa tietoturvaa. PHP on heikosti tyypitelty kieli, eli muuttujan tyyppi voi vaihtua kesken suorituksen. PHP:n suorituksen aikana tapahtuneita virheilmoituksia ei pidä myöskään tulostaa suoraan selaimeen, sillä ne voivat paljasta tietoa järjestelmän toiminnasta.

3.2. SQL-injektiot PHP-kielessä

SQL-injektioissa käyttäjä rikkoutuu syötteen avulla ulos SQL-kyselyn rakenteesta ja pääsee muokkaamaan kyselyä haluamakseen. SQL-injektioiden ehkäiseminen on yksinkertaista esimerkiksi käyttäen PHP:n mysqli- tai pdo-laajennusta [3,4]. PHP:n mysql-laajennuksen käyttämistä ei enää suositella. Uudemmat laajennukset mahdollistavat SQL-kyselyt muodostamisen käyttäen valmisteltuja lausekkeita (Prepared statements), joissa SQL-kyselyyn kirjoitetaan käyttäjän syötteiden sijaan merkkejä, jotka kertovat missä kohtaa kyselyä käyttäjän syötteiden tulee olla. Kyselyn suoritusvaiheessa syötteet sijoitetaan kyselyyn niille määritetyssä järjestyksessä. Seuraavassa koodiesimerkissä näytetään PDO-kysely.

<?php
//Määritellään kyselyn rakenne
$sth = $db->prepare('SELECT * FROM products WHERE category = ? AND price < ?');
//Suoritetaan kysely sijoittamalla ensin halutut arvot kyselyn rakenteeseen
$sth->execute(array('potato', '4')); 

Valmisteltuja lausekkeita hyödyntävän kirjaston käyttäminen ei kuitenkaan takaa SQL-injektioita mahdottomaksi, jos esimerkiksi olettaa jonkin tiedon olevan käyttäjän muokkaamattomissa ja syöttää sen suoraan kyselyyn.

3.3. Syötteiden käsittelytavat ja mallinejärjestelmät

Kaikki käyttäjältä saatava tulostettava syöte on käsiteltävä, jottei sivulle saa sisällytettyä käyttäjän kirjoittamaa HTML:ää eikä javascriptiä. XSS:n torjumiseen PHP:ssä voi käyttää esimerkiksi funktiota htmlspecialchars, joka muuttaa HTML-merkit entititeeteiksi eli merkkiviittauksiksi, jotka näkyvät käyttäjälle tulostettuina selaimessa. Laajoissa projekteissa kaiken käyttäjän syötteen ohjaaminen käsin tällaisen funktion kautta on kuitenkin työlästä ja virhealtista. Käyttäen mallinejärjestelmää, sivun rakenteen voi rakentaa erillistä merkintäkieltä käyttäen, jossa syötteet käsitellään automaattisesti. Seuraavassa yksinkertaisessa esimerkissä näytetään miten merkintäkieltä voi käyttää.

Username: {$username}
Description: {$userdescription}

Tulostusvaiheessa mallinejärjestelmälle syötetyt muuttujien arvot sijoitetaan oikeille kohdilleen.

4. Sivustolta vastaanotettavat lomakevastaukset

4.1. Odottamattomat merkit syötteessä

Sivujen suunnittelussa lomakkeiden tiedoille annetaan tietty rakenne, jossa käyttäjän syöttämä tieto halutaan vastaanottaa. PHP-ohjelmoija ei kuitenkaan voi olettaa, että vastaanotettujen tietojen rakenne pysyy samanlaisena kuin se on käyttäjälle annettu. Käyttäjä pystyy muokkaamaan lomakkeita haluamallaan tavalla. Web-selaimen rajoittavat toiminnot, kuten kenttien pituuden rajoittaminen tai javascript, eivät ole pakollisia. HTML-lomakkeita voi muokata helposti selaimessa käyttämässä erillisiä lisäosia. Kaikki näistä hyökkäyksistä voidaan kuitenkin ehkäistä kirjoittamalla koodi huolellisesti ja tarkastamalla syötteen tyyppi. Esimerkiksi HTML:n text-tyyppiseen input-elementtiin saa kirjoitettua rivinvaihtoja vaihtamalla elementin tyyppi tai käyttämällä käyttöjärjestelmän leikepöytää. Esimerkiksi seuraavanlaista sähköpostin lähettämiseen tarkoitettua lomaketta voidaan käyttää roskapostin lähettämiseen.

<?php
if ($_POST['sendmail']) {
  //Haetaan halutut tiedot käyttäjän syötteistä
  //Loput tiedot määritetään koodissa itse
  $fromname = $_POST['fromname'];
  $from = $_POST['from'];
  $to = 'repicient@somemail.xxx';
  $subject = 'the subject';
  $message = 'hello';
  $headers = 'From: ' . $fromname . "\r\n" .
   'Reply-To: ' . $from ."\r\n" .
   'X-Mailer: PHP/' . phpversion();
  //Lähetetään sähköposti parametrien mukaisesti
  mail($to, $subject, $message, $headers);
}

Käyttäjä voi injektoida tällä tavoin haluamiaan headereita. $_POST['from']:n sisältö voisi olla esimerkiksi
sender@othermail.xxx
Cc: victim@anothermail.xxx”
Hyökkäys on luonteeltaan yksinkertainen. PHP-ohjelmoijalle voi kuitenkin syntyä harhakuvitelma selaimen mahdollisuuksien perusteella. Tässä tapauksessa käyttäjän syötteen voisi vielä tarkastaa säännöllisellä lausekkeella (Regular expression), jotta käyttäjän syöte on halutussa muodossa.

4.2. Odottamattomat syötteen tietorakenteet

Odotetun tekstimuotoisen datan sijasta palvelimelle voidaan lähettää syötteenä taulukkomuotoista dataa. Hyökkäystä varten voi kirjoittaa erillisen skriptin tai tavallinen tekstikenttä voidaan esimerkiksi muuttaa taulukkomuotoiseksi multiple select -elementiksi selaimessa. Seuraavaa PHP:llä toteutettua flatfile-tietokantaa vastaan voidaan toteuttaa hyökkäys.

<?php

if ($_POST['form']) {
  //Tarkistetaan että syöte on maksimissaan tietyn pituinen, tässä esimerkissä 99 merkkiä
  if (strlen($_POST['somecolumn']) < 100) {
      //sisällytetään messages.php nykyiseen koodiin. Sisällytetty koodi sijoittaa tietoa muuttujaan $data
      include 'data/messages.php';
      //Lisätään uusi rivi tietokantaan
      $data[] = array("somecolumn" => $_POST['somecolumn']);
      //Määritellään messages.php:n tuleva sisältö
      //var_export -funktio palauttaa funktion sisällön tallennettavassa muodossa
      $file = '<?php \n' . '$data = ' . var_export($data, true) . ';';
      //Avataan tiedosto messages.php kirjoitustilaan
      $f = fopen(”data/messages.php”, ”w”);
      //Kirjoitetaan tiedostoon haluttu sisältö
      fwrite($f, $file);
      //Suljetaan tiedosto
      fclose($f);
  }
}

Hyökkäyksen seurauksena voi aiheutua se, että viestit näyttävä sivu saa aikaan jokainen kerta noticen, kun käsillään taulukkoa vaikka oletuksena tiedon piti olla tekstiä. Lisäksi funktio strlen ei laske tekstin pituutta toivotulla tavalla, vaan kertoo merkkijonon ”Array” pituuden, eli viisi merkkiä. Tällä tavoin hyökkääjä voi aiheuttaa Denial of Service -hyökkäyksen, koska dataa voi tallentaa tietorakenteeseen nopeasti PHP:n post_max_size -direktiivin määrittämän rajan mukaisen määrän tietoa, joka on oletuksena 8 megatavua [5]. Tämän ongelman voi ratkaista testaamalla, onko saatu syöte taulukkomuotoinen.

4.3. Odottamattomat arvot ja pääsynhallinta

Injektioiden ja rakenteen muokkaamisen lisäksi lomakkeen arvoja voidaan muokata pääsynvalvonnan kiertämiseen. Esimerkiksi foorumiohjelmistossa voi olla moderaattoreille suunnattu toiminto, jossa moderaattori voi siirtää useita keskusteluaiheita kerralla keskustelualueelta toiselle. Käyttäjälle näytetään lista keskusteluaiheen otsikoista, joista käyttäjä valitsee haluamansa, sekä myös alueen johon aiheet siirretään. Tässä välissä käyttäjä muokkaa monivalintaelementin id-arvoja sellaisia aiheita vastaaviksi, joihin hänellä ei ole näkyvyyttä eikä lukuoikeutta. Mikäli PHP-sovellus ei erikseen tarkista jokaisen siirrettävän aiheen oikeuksia, käyttäjä voi näin onnistua saamaan itselleen tietoa, johon hänen ei pitäisi päästä käsiksi.

5. PHP:n file upload -toiminnallisuus

5.1. Upload-toiminnon erityisyys tietoturvauhkana

PHP-kielessä on mahdollisuus tallentaa palvelimelle käyttäjän lähettämiä tiedostoja. Huolimattomasti tehdyn tiedostonlähettämislomakkeen avulla voi kuitenkin auheuttaa vakavia tietoturvaongelmia, kuten mahdollisuuden päästä suorittamaan koodia tai aiheuttaa denial of service -hyökkäyksen. PHP:n manuaalin antamat ohjeet eivät ole riittäviä, jotta pystyisi rakentamaan turvallisen tiedostojen lähettämiseen tarkoitetun lomakkeen. Esimerkiksi tiedostojen siirtämiseen käytettävän funktion koodiesimerkeissä [6] esiintyy oikeastaan kaikki puutteet, mitä tiedostojenlähetyslomakkeessa voi esiintyä.

5.2. Käyttäjän tiedostojen päätyminen suoritettavaksi

Mikäli upload-lomakkeella lähetettyjen tiedostojen tulee olla vapaasti selattavissa kansiorakenteessa, tiedostot eivät saa olla suoritettavissa. Käyttäjälle ei pidä sallia lähettää Apache-palvelimelle .htaccess -tiedostoa, sillä tällöin käyttäjä voi päästä suorittamaan koodia, vaikka tiedoston pääte ei olisikaan PHP-suoritettavien tiedostopäätteiden listassa. Joissakin PHP-konfiguraatioissa myös tuplatiedostopäätteiset tiedostot voivat päätyä suoritettaviksi. Ongelman ratkaisuna on tarkistaa tiedostonimi säännöllisellä lausekkeella, joka varmistaa että tiedostonimessä on ainoastaan sallittuja merkkejä ja tiedostopääte on sallittujen joukossa. PHP:n upload-komento ylikirjoittaa tiedoston, mikäli se on jo valmiiksi olemassa.

Lisäksi tulee olla tarkkana miten tiedostoja sisällyttää näytettävälle sivulle. Esimerkiksi PHP:n funktiot include ja require suorittavat kohdetiedostossa olevan PHP-koodin tiedostopäätteestä huolimatta. Sen sijaan esimerkiksi funktio readfile ei koskaan suorita PHP-koodia. Palvelimelle ladattavan tiedoston ei kuitenkaan välttämättä tarvitse olla tiedostopäätteeltään tietynlainen, jotta käyttäjä pääsisi suorittamaan palvelimella haluamaansa koodia. Löydettyään remote file inclusion -pohjaisen tietoturva-aukon, hyökkääjä pääsee ajamaan koodia tiedostopäätteestä huolimatta.

5.3. Tiedostojen sisältämästä datasta aiheutuvat tietoturvaongelmat

Koodia voi upottaa moniin tiedostoihin niin että tiedostoa voi käyttää sen alkuperäisessä käyttöyhteydessä. Esimerkiksi jpg-kuvan exif-tageihin voi upottaa PHP-koodia niin, että se pysyy tekstimuotoisena [7]. Kenttiin on mahdollista sisällyttää myös HTML:ää tai javascript-koodia, joka voi tulla suoritetuksi, jos kentän sisältö tulostetaan selaimessa, eikä ohjelmoija ole ohjannut tulostetta esimerkiksi htmlspecialchars-funktion läpi. Tiedoston mime-tyyppi on myös väärennettävissä käyttäjän puolelta. Kuvatiedostojen tarkastamiseen saatetaan joskus käyttää PHP:n getimagesize-funktiota, joka ei kuitenkaan yksinään takaa tiedoston turvallisuutta, sillä kuva voi toimia tavallisesti siihen upotetusta koodista huolimatta.

6. Päätelmät / yhteenveto

PHP-kieleen liittyvien tietoturvauhkien torjunnassa käyttäjän syötteen tarkistaminen ja käsittely ovat etusijalla, sillä moni uhkista aiheutuu alun perin odottamattoman syötteen takia. PHP:n ominaisuuksista on tärkeää olla tietoinen, jotta uhkiin ylipäätään osaa varautua. Kaikki tietoturvauhkat eivät suinkaan välttämättä aiheudu ohjelmoijan kirjoittamasta koodista, jos ohjelmistoylläpito laiminlyödään. Moni PHP:ssä esiintyvistä tietoturvauhkista on mahdollinen myös muiden dynaamisia web-sivuja tuottavien ohjelmointi- ja skriptikielien tapauksessa.

7. Lähteet

SivuTiedotLaajennettu edit

Vaativuus Jatko
Valmius Valmisteilla
Tyyppi Ydin
Luokitus Uhkat
Mitä Luottamuksellisuus
Miltä Ihmisetön uhka
Missä Organisaatio
Kuka Titu-ammattilainen
Milloin Ennakolta
Miksi Hyvä tapa
Print version |  PDF  | History: r4 < r3 < r2 < r1 | 
Topic revision: r4 - 07 Dec 2012 - 19:41:21 - SampoTolvanen?
 

TUTWiki

Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TUTWiki? Send feedback