Ohjeen toimivuus tarkistettu 1/2014. Ohjetta ei enää päivitetä (1/2016).
Erilaisista tietovuodoista ja -murroista uutisoidessa puhutaan usein myös ns SQL-injektiosta, esim ”Tietomurto toteutettiin SQL-injektion avulla”. SQL-injektio on yleinen hyökkäystapa esimerkiksi tietyntyyppisiä nettisivuja vastaan. Ohessa on kuvattuna erittäin yksinkertainen ja pelkistetty esimerkki, miten kyseinen hyökkäys tehdään.
En tarjoa valmiita ohjeita miten SQL-injektio pitäisi estää, koska se on niin tapausriippuvaista. Pääsääntönä voidaan kuitenkin sanoa, että kaikki käyttäjältä tulevat syötteet pitää ns sanitoida, eli niistä pitää poistaa kaikki ylimääräiset merkit.
Alla on selostettuna SQL-injektion demo, jota voit testata omassa testiympäristössäsi.
Mikäli halut vain tietää mitä SQL-injektiossa todella tapahtuu, niin hyppää suoraan kohtaan 6!
Tämä ohje on tarkoitettu vain kertomaan ja demoamaan tietoteknisten toteutusten heikkouksia. Mikäli testaat ohjeita käytännössä, niin toteuta testit vain omassa verkossasi omilla laitteillasi! Sivuston ylläpito ei ole vastuussa mahdollisista seurauksista, joita demon testaamisesta saattaa aiheutua.
SQL injektio testiympäristö
Parhaiten ja helpoiten testaaminen onnistuu virtuaalikonetta käyttäen. Tässä ohjeessa ei kerrota miten tarvittavat ohjelmat asennetaan tai konfiguroidaan. Ohje ei myöskään sisällä mitään ylimääräisiä tietoja esimerkiksi HTML- tai PHP-tekniikoista. (Vinkki: virtuaalikoneeksi Virtualbox, siihen käyttöjärjestelmäksi Debian ja sitten vain asetukset kuntoon LAMP-ohjeen mukaisesti.)
Esimerkkiä varten tarjolla on myös muutama erittäin pelkistetty tiedosto, jotka nopeuttavat alkuvalmisteluja. Sijoita HTML- ja PHP-tiedostot testipalvelimelle ns www-juureen (wwwroot), eli sinne mistä palvelin oletuksena webbisivutiedostoja hakee. SQL tiedostot voit tallentaa vaikkapa kotikansioosi. HUOM! Tiedostot ovat nyt .txt päätteisiä, tallenna ne oikeilla päätteillä testipalvelimellesi.
luo_taulu.sql
lisaa_tiedot.sql
index.html
kirjautuminen.php
kirjautuminen_onnistui.php
Etene seuraavasti:
1. Testipalvelimen ohjelmistot
Tässä esimerkissä on käytetty Debian Linuxia ja siihen on asennettu Apache webserveri, MySQL-tietokanta sekä tuki PHP-skriptikielelle. Voit käyttää haluamiasi webserveri tai tietokantaohjelmia, mutta annetut esimerkkitiedostot on tehty tätä ympäristöä varten. Kyseiset ohjelmistot ovat erittäin yleisiä ja helppokäyttöisiä, joten ne on siksi valittu tähän esimerkkiin.
Olettaen että käytät testissä mainittuja ohjelmistoja, niin tässä vaiheessa pitää olla asennettuna ja toiminnassa Apache, MySQL sekä PHP.
2. MySQL tietokannan ja taulun luominen
Kirjaudutaan ensin MySQL:ään ja luodaan sinne uusi tietokanta nimeltä ”tunnukset”.
Huom! Esimerkissä on käytetty root käyttäjää vain ja ainoastaan yksinkertaisuuden nimissä, älä siis käytä sitä normaalissa tuotantoympäristössä!
Komennossa oleva -u tarkoittaa käyttäjää (root) ja -p mahdollistaa salasanan syöttämisen komennon jälkeen.
matti@debian:~$ mysql -u root -p
<anna salasana käyttäjälle mysql root>
mysql> CREATE DATABASE tunnukset;
<CTRL+D poistutaan MySQL komentoriviltä>
Seuraavaksi luodaan ”tunnukset” tietokantaan uusi taulu luo_taulu.sql skriptillä.
matti@debian:~$ mysql -u root -p tunnukset < luo_taulu.sql
luo_taulu.sql sisältää tarvittavat SQL-komennot taulun lisäämiseksi.
Katso tarkemmat lisätiedot skriptin kommenteista.
Lisätään juuri luotuun tauluun vielä hieman sisältöä(käyttäjätunnuksia) lisaa_tiedot.sql skriptillä:
matti@debian:~$ mysql -u root -p tunnukset < lisaa_tiedot.sql
3. Muut tiedostot
Kirjautumislomake index.html
Tässä tiedostossa ei ole mitään muokattavaa, laita tämä tiedosto ns wwwroot kansioon testipalvelimella.Eli sinne josta webserveri hakee näytettäviä nettisivutiedostoja.
kirjautuminen_onnistui.php
Tässäkään tiedostossa ei ole mitään muokattavaa. Aseta samaan paikkaan kuin index.html
kirjautuminen.php
Tästä tiedostosta on muokattava seuraavia kohtia:
Root on käyttäjä jolla otetaan yhteys MySQL tietokantaan. Tunnusta root (MySQL root käyttäjä) on käytetty tässä tietoturvattomasti vain esimerkkinä, älä käytä sitä oikeissa tuotantopalvelimissa. Salasana on MySQL root käyttäjän salasana.
mysql_connect("localhost", "root", "salasana")
Seuraavaksi määritellään mihin tietokantaan MySQL ottaa yhteyden. Tässä siis sama tietokanta kuin kohdassa 2.
mysql_select_db("tunnukset")
Nyt kun kaikki tiedostot on muokattu toimiviksi, niin avaa index.html tiedosto testipalvelimen webserveriltä. Jos tiedosto on asetettu esimerkiksi oletusasetuksien määrittämään wwwroot hakemistoon, niin sivun pitäisi aueta kun testipalvelimeen ottaa yhtettä web-selaimella. Jos testipalvelimessa on graafinen käyttöliittymä, niin käytä sen web-selainta ja mene osoitteeseen localhost, joka siis viittaa koneeseen itseensä.
Kirjautumissivun pitäisi nyt aueta.
4. Kirjautumissivun testaus
Koita kirjautua jollain lisaa_tiedot.sql tiedostossa olleilla tunnuksilla, esim Ville ja salasana Viltsu123
Mikäli kaikki on ok, niin kirjautumissivun pitäisi etsiä käyttäjätunnusta ja salasanaa ”tunnukset” tietokannasta. Jos kirjautuminen toimii, aukeaa kirjautuminen_onnistui.php sivu, jossa on teksti ”Tervetuloa!”. Epäonnistuneesta kirjautumisesta ilmoitetaan myös erikseen.
Virheilmoituksista tai muissa ongelmista voi ottaa yhteyttä esim. kommenttien kautta tai sähköpostilla.
5. SQL injektion toteuttaminen
Mikäli olet todennut, että kirjautuminen toimii normaalisti oikeilla käyttäjätunnuksilla ja ilmoittaa virheestä väärillä tunnuksilla, niin koitappa seuraavaa:
Käyttäjätunnus: ”Ville’ — ”
Salasana: ”EnTiedä”
Syötä tiedot ilman hipsuja ””, ja huomaa välilyönti kahden viivan (– ) perässä. Mikäli kirjautuminen toimii onnistuneesti myös näillä tunnuksilla, niin olet onnistuneesti toteuttanut SQL injektion.
6. Mitä injektiossa tapahtuu?
Huonosti toteutettu kirjautumisen käsittelyskripti kirjautuminen.php tekee seuraavan SQL kyselyn tietokannalle:
SELECT * FROM ktunnukset WHERE kayttajanimi='$kayttajatunnus' AND salasana='$salasana'
Muuttujat $kayttajatunnus ja $salasana saadaan suoraan kirjautumislomakkeesta (index.html).
Käyttäessä tunnusta Ville ja salasanaa Viltsu123 näyttää kysely MySQL näkökulmasta tältä:
mysql> SELECT * FROM ktunnukset WHERE kayttajanimi='Ville' AND salasana='Viltsu123';
Tämä kysely löytää luonnollisesti tietokannan taulusta kohdan nro 3, jossa on Villen tiedot. Tämä tarkoittaa sitä, että hänellä on lupa kirjautua kyseisillä tunnuksilla.
Jos käyttäjän syötettä (esim käyttäjätunnus) ei käsitellä millään tavalla, voi käyttäjä syöttää kenttään mitä haluaa. Tässä tapauksessa hyökkääjä on saanut selville käyttäjätunnuksen Ville, mutta hän ei tiedä Villen salasanaa. Koska järjestelmä on toteutettu heikosti, pystyy hyökkääjä käyttämään apunaan SQL-injektiota ja saa sen avulla pääsyn järjestelmään.
Nyt hyökkääjä syöttää kohdassa 5. mainitut tiedot, jolloin SQL-kysely näyttääkin tältä:
SELECT * FROM ktunnukset WHERE kayttajanimi='Ville' -- ' AND salasana='EnTiedä';
— tarkoittaa tässä tapauksessa kommentoinnin alkua. Eli — jälkeisiä komentoja käsitelläänkin pelkkinä kommentteina, eli niitä ei huomioida!
Toisin sanoen SQL kysely on nyt tällainen:
SELECT * FROM ktunnukset WHERE kayttajanimi='Ville';
Kysely etsii tietokannasta Ville nimistä käyttäjää ja sehän löytyy riviltä 3. Tiedot siis täsmää ja käyttäjä pääsee kirjautumaan tietämättä Villen salasanaa!
7. Yhteenveto
SQL-injektion ideana on siis hyödyntää huonosti toteutettua www-sovellusta. Jos käyttäjän antamia syötteitä ei käsitellä oikein, niin hyökkäys järjestelmään on pahimmillaan yhtä helppoa kuin yllä demotussa esimerkissä.