SQL-injektio

Mureakuha

Loikkaa: valikkoon, hakuun

SQL-injektio on suhteellisen yleinen hyökkäys tietokantaa käyttäviä, etenkin web-, sovelluksia vastaan. Käytännössä hyökkäys tapahtuu siten, että virheellisesti rakennettuun tietokantakyselyyn voidaan "injektoida" eli syöttää esimerkiksi kyselyiden osia. Tällä tavoin käyttäjä voi saada esille arkaluontoisia tietoja tai pahimmassa tapauksessa muokata tai päästä muokkaamaan tietokannan tietoja.

Sisällysluettelo

Esimerkki

Alla yksinkertainen esimerkki SQL-injektiosta. Oletetaan, että funktio suorita_lause ajaa SQL-kyselyn ja palauttaa tulokset. Muuttujat "user" ja "password" saadaan käyttäjältä eikä niihin tehdä minkäänlaisia muutoksia.

tulos = suorita_lause
(
  "SELECT * FROM users
     WHERE user     = '$user' AND
           password = '$password'"
);

Normaalisti sivua kutsutaan esim. argumenteilla user = kuha ja password = salainen, jolloin muodostuu kysely

SELECT * FROM users
   WHERE user     = 'kuha' AND
         password = 'salainen'

Hyökkääjä voi kuitenkin käyttää esimerkiksi argumenttiä user = kuha ja password = salainen' OR '1, jolloin muodostuukin kysely

SELECT * FROM users
   WHERE user     = 'kuha' AND
         password = 'salainen' OR '1'

joka valitsee kaikki kannassa olevat käyttäjät ja näin ollen päästää kirjautumaan ensimmäisellä vastaantulevalla käyttäjällä!

(Muista myös katsoa aiheeseen liittyvä sivu salasanojen turvallisesta tallennuksesta. Salasanojen tallennus kantaan selkokielisenä on huono idea.)

Suojautuminen

SQL-injektiolta suojautumisen tärkeimmät askeleet ovat erikoismerkkejen muuntaminen ja arvojen sulkeminen heittomerkkeihin (').

Erikoismerkkien muuntaminen

Kuten edellisessä esimerkissä esitettiin, ei pelkkä arvojen heitto- tai lainausmerkein ympäröiminen riitä, vaan tulee myös varmistaa, ettei itse arvo sisällä näitä merkkejä. Tietokannat käyttävät myös muita erikoismerkkejä, joiden pääsy kyselyyn saattaa olla haitallista. Esimerkiksi '%' ja '_' toimivat jokerimerkkeinä joidenkin operaattorien kanssa, joten on syytä tarkistaa, että nämäkin käsitellään, mikäli jokerien käyttö ei ole kaivattu tulos.

Itse muuntaminen tapahtuu useimmiten lisäämällä erikoismerkin eteen kenoviiva (\). Mikäli esimerkin password = salainen' OR '1 muutettaisiin ohjelmassa muotoon password = salainen\' OR \'1 saataisiin kysely

SELECT * FROM users
   WHERE user     = 'kuha' AND
         password = 'salainen\' OR \'1'

joka ei päästäisi hyökkääjää sisään ellei tunnuksen "kuha" salasana sattuimoisin olisi "salainen' OR '1".

(Huomio! Pelkästään esimerkissä käytetyn hipsun muuttaminen turvalliseen muotoon ei aina riitä ja siksi on hyvä aina käytettävä tietokannan mukana tulevia funktioita erikoismerkkien muuntamiseen mikäli se vain on mahdollista.)

Hakujen esikäsittely

Yleensä tietokantojen kirjastoissa tulee mukana funktioita tai luokkia merkkijonojen muunnoksiin. Arvojen manuaalinen käsittely on kuitenkin hieman virhealtista ja ennen kaikkea hidasta ja työlästä. Tämän vuoksi on hyvä käyttää menetelmää, jolla arvot muunnetaan automaattisesti oikeaan muotoon. Yleisin toteutus tälle on "hakujen esikäsittely" (query preparing). Tällöin pidetään itse kysely ja kyselyn arvot erillään siten, että itse kyselyyn ei tule lainkaan muuttujista tulevia arvoja.

Hakujen esikäsittely voi toimia esimerkiksi näin:

tulokset = suorita_haku
(
  'SELECT * FROM users
    WHERE user     = ? AND
          password = ?'

  $user, $password
);

Ylläolevassa koodissa funktio suorita_haku korvaa kysymysmerkit oikein käsitellyillä arvoilla, jotka on annettu argumentteina. Useissa tietokantarajapinnoissa tulee valmiiksi mukana vastaavankaltainen menetelmä hakujen valmistamiseen.

PHP

MySQL:ää ja PHP:tä käytettäessä tämä tulisi tehdä mysql_real_escape_string-funktiolla. Myös muille tietokannoille on vastaavanlaiset funktiot.

PHP5:lle on edistyneempi hakujen esikäsittelyä tukeva mysqli-kirjasto ja tietokantariippumaton PDO kirjasto. Myöskin PEARin DB-paketti on hyödyllinen. Sekin tukee hakujen esikäsittelyä ja toimii myös PHP:n vanhemmissa versioissa.

Henkilökohtaiset työkalut