# Mikä on SQL-injektio?

SQL-injektiot muodostavat merkittävän uhan relaatiotietokantamalleille ja niissä oleville arkaluonteisille tiedoille. Siksi kattava suojaus näitä luvattomia ulkoisia pääsyyrityksiä vastaan – jotka ovat mahdollisia tietoturva-aukkojen vuoksi – on ehdottoman välttämätöntä.

## Mikä on SQL-injektio?

SQL-injektio on hyökkäystyyppi, jossa hyödynnetään tietoturva-aukkoa relaatiotietokantajärjestelmissä, jotka käyttävät [SQL-kyselykieltä](https://www.ionos.com/fi-fi/digitalguide/palvelin/osaaminen/mikae-on-sql/) käyttäjän syöttämien tietojen käsittelyyn. Hyökkääjä hyödyntää käyttäjän syötteitä, joita **ei** ole **suojattu asianmukaisesti** ja jotka sisältävät **erikoismerkkejä**, kuten kaksoisviivoja, lainausmerkkejä tai puolipisteitä. Näillä merkeillä on erityisiä toimintoja SQL-tulkkissa, ja niiden avulla suoritettavia komentoja voidaan manipuloida ulkoisesti. SQL-injektiot liittyvät usein PHP- ja ASP-sovelluksiin, jotka perustuvat vanhentuneisiin rajapintoihin. Monissa näistä tapauksista syötettä ei puhdisteta riittävästi, mikä tekee siitä erinomaisen kohteen hyökkäyksille.

Lisäämällä strategisesti toimintomerkkejä luvaton käyttäjä voi syöttää järjestelmään ylimääräisiä SQL-komentoja ja manipuloida tietokantatietueita **lukeakseen, muokatakseen tai poistaakseen tietoja**. Pahimmissa tapauksissa hyökkääjät voivat jopa päästä **käsiksi järjestelmän komentoriville**, minkä seurauksena he voivat saada täyden hallinnan tietokantapalvelimesta.

## Esimerkki SQL-injektiosta, joka havainnollistaa tietokantahyökkäyksen toimintaperiaatetta

Koska haavoittuvat tietokantapalvelimet voidaan tunnistaa nopeasti ja SQL-injektiohyökkäykset ovat suhteellisen helppoja toteuttaa, tämä menetelmä on edelleen yksi maailmanlaajuisesti yleisimmin käytetyistä tekniikoista kyberrikollisten keskuudessa. Hyökkääjät käyttävät **erilaisia strategioita** ja hyödyntävät sekä äskettäin löydettyjä että jo pitkään tunnettuja tietoturva-aukkoja tietojenhallintaprosessiin liittyvissä sovelluksissa. Jotta voimme paremmin ymmärtää, miten SQL-injektio toimii käytännössä, tarkastellaan esimerkkinä kahta yleistä hyökkäysmenetelmää.

### Esimerkki 1: Pääsy huonosti suojatun käyttäjän syötteen kautta

Tietokantaan pääsemiseksi käyttäjien on yleensä ensin tunnistettava itsensä. Tätä varten käytetään yleisesti skriptejä, jotka tuottavat **kirjautumislomakkeen**, jossa on kentät käyttäjätunnukselle ja salasanalle. Käyttäjät täyttävät lomakkeen, ja **skripti tarkistaa sitten**, onko tietokannassa vastaavia tietueita. Oletusarvoisesti tietokanta saattaa sisältää taulukon nimeltä `users`, jossa on sarakkeet `username` ja `password`. Tyypillisessä verkkosovelluksessa tietokantaan pääsyä koskevat skriptirivit (Python-tyyppistä pseudokoodia käyttäen) saattavat näyttää tältä:

```python
uname = request.POST['username']
passwd = request.POST['password']
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"
database.execute(sql)
```

Hyökkääjä voi nyt **manipuloida salasanakenttää SQL-injektion avulla**, esimerkiksi syöttämällä `password' OR 1='1`, mikä tuottaa seuraavan SQL-kyselyn:

```python
sql = "SELECT id FROM users WHERE username='' AND password='password' OR 1='1'"
```

Tämä antaa hyökkääjälle täyden pääsyn tietokannan koko käyttäjätaulukkoon, koska **salasanakriteeri täyttyy aina** (`1='1'`). Jos hyökkääjä kirjautuu sisään **järjestelmänvalvojana**, hän voi vapaasti muokata mitä tahansa tietokannan tietueita. Vaihtoehtoisesti **käyttäjätunnuskenttää** voidaan manipuloida samalla tavalla.

### Esimerkki 2: Tietojen poiminta tunnisteiden muokkaamisen avulla

Tietojen hakeminen tietokannasta tunnisteen perusteella on käytännöllinen ja yleinen menetelmä, mutta se avaa myös mahdollisen portin SQL-injektiolle. Esimerkiksi verkkopalvelin tietää URL-osoitteessa lähetetyn tunnisteen perusteella, mitkä tiedot sen tulee hakea tietokannasta. Vastaava **PHP-skripti** näyttää tältä:

```php
<?php
    $mysqli = new mysqli("localhost", "username", "password", "database");
    $id = intval($_GET['id']);
    $result = $mysqli->query("SELECT * FROM table WHERE id=$id");
    while ($row = $result->fetch_assoc()) {
        echo print_r($row, true);
    }
?>
```

Odotettu URL noudattaa mallia `.../script.php?id=22`. Tässä tapauksessa haettaisiin **taulukon rivi**, jonka tunniste on ”22”. Jos luvaton henkilö pääsee muokkaamaan tätä URL-osoitetta ja lähettää sen sijaan pyynnön, kuten `.../script.php?id=22+OR+1=1`, tuloksena oleva kysely aiheuttaa sen, että **taulukon kaikki rivit** haetaan:

```sql
SELECT * FROM table WHERE id=22 OR 1=1;
```

## Miten rikolliset löytävät haavoittuvia tietokantajärjestelmiä?

Periaatteessa mikä tahansa verkkosivusto tai verkkosovellus, joka käyttää SQL-tietokantoja ilman esivalmisteltuja kyselyitä (prepared statements) tai muita suojatoimenpiteitä, voi olla alttiina SQL-injektioille. Löydetyt haavoittuvuudet eivät pysy kauan piilossa internetissä. Itse asiassa on olemassa verkkosivustoja, jotka julkaisevat ajantasaisia luetteloita tunnetuista tietoturva-aukkoista – ja jopa selittävät, kuinka hyökkääjät voivat käyttää Google-hakuja löytääkseen vastaavia verkkoprojekteja. Jos verkkosivusto palauttaa yksityiskohtaisia SQL-virheilmoituksia, kyberrikolliset voivat käyttää näitä viestejä tunnistaakseen mahdollisia haavoittuvuuksia. Esimerkiksi apostrofin lisääminen URL-osoitteen loppuun, joka sisältää ID-parametrin, voi jo paljastaa heikkouden, kuten seuraavassa esimerkissä on esitetty:

```none
[DomainName].com/news.php?id=5’
```

Haavoittuva verkkosivusto palauttaa virheilmoituksen seuraavassa muodossa:

`Query failed: You have an error in your SQL syntax…`

Samanlaisia menetelmiä voidaan käyttää myös sarakkeiden lukumäärän, taulukko- ja sarakkeenimien, SQL-version tai jopa käyttäjätunnusten ja salasanojen selvittämiseen. Lisäksi on olemassa erilaisia työkaluja, joilla voidaan **automatisoida sekä tietojen keräämisprosessi että SQL-injektiohyökkäysten toteuttaminen**.

## Kuinka suojata tietokantaasi SQL-injektiolta

Tietokantajärjestelmääsi kohdistuvia SQL-injektiohyökkäyksiä voidaan estää monin eri tavoin. Sinun tulee huomioida kaikki asiaan liittyvät osatekijät – palvelin ja yksittäiset sovellukset sekä tietokannan hallintajärjestelmä.

### Vaihe 1: Seuraa sovelluksista tulevia automaattisia syötteitä

Kun käsitellään ulkoisista tai sisäänrakennetuista sovelluksista tulevia syötteitä, on ehdottomasti tarkistettava ja suodatettava lähetetyt arvot SQL-hyökkäysten estämiseksi.

**1. Tarkista tietotyypit**

Jokaisen syötteen on vastattava odotettua tietotyyppiä. Jos esimerkiksi vaaditaan numeerista syötettä, yksinkertainen validointi PHP:ssä voisi näyttää tältä:

```php
if (filter_var($input, FILTER_VALIDATE_INT) === false) {
    throw new InvalidArgumentException("Invalid input");
}
```

Vastaavia tarkistuksia tulisi toteuttaa merkkijonojen, päivämäärien tai muiden erityisten muotojen osalta.

**2. Suodata erikoismerkit**

Erikoismerkit voivat aiheuttaa tietoturva-aukkoja, etenkin SQL- tai HTML-yhteyksissä. Turvallinen tapa on käyttää `htmlspecialchars()` HTML-syötteissä ja `PDO::quote()` SQL-kyselyissä.

**3. Vältä virheilmoitusten näyttämistä**

Tietokannan tai järjestelmän teknisiä yksityiskohtia paljastavia suoria virheilmoituksia tulisi välttää. Sen sijaan tulisi näyttää yleinen viesti, kuten:

```php
echo "An error occurred. Please try again later.";
error_log("Unexpected error encountered. See system log for details.");
```

**4. Käytä valmiita lauseita**

Yksi tehokkaimmista tavoista estää SQL-injektiot on käyttää **valmiita lauseita**. Tässä menetelmässä SQL-komennot ja parametrit lähetetään erikseen, joten haitallista koodia ei voida suorittaa. Tässä on esimerkki toteutuksesta PHP:llä PDO:ta (PHP Data Objects) käyttäen:

```php
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $user_id, PDO::PARAM_INT);
$stmt->execute();
```

Tietokannan hallintajärjestelmä varmistaa automaattisesti, että syötetyt tiedot käsitellään turvallisesti.

### Vaihe 2: Varmista palvelimen kattava suojaus

Myös sen palvelimen tietoturva, jolla tietokantajärjestelmäsi toimii, on ratkaisevassa asemassa SQL-injektioiden torjunnassa. Keskeinen toimenpide on **käyttöjärjestelmän suojaaminen** noudattamalla seuraavia parhaita käytäntöjä:

- Asenna tai ota käyttöön vain ne sovellukset ja palvelut, jotka ovat välttämättömiä tietokannan toiminnalle.
- Poista kaikki käyttämättömät tai tarpeettomat käyttäjätilit.
- Varmista, että kaikki tarvittavat järjestelmä- ja ohjelmistopäivitykset asennetaan viipymättä.
- Sovella vähimmäisoikeuksien periaatetta varmistaaksesi, että käyttäjille ja palveluille myönnetään vain välttämättömät vähimmäisoikeudet.

Verkkoprojektisi turvallisuusvaatimusten mukaan sinun tulisi harkita seuraavia lisäsuojatoimenpiteitä:

- **[Tunkeutumisen havaitsemisjärjestelmät (IDS)](https://www.ionos.com/fi-fi/digitalguide/palvelin/turvallisuus/tunkeutumisen-havaitsemisjaerjestelmae-ids/) ja [tunkeutumisen estojärjestelmät (IPS)](https://www.ionos.com/fi-fi/digitalguide/palvelin/turvallisuus/tunkeutumisenestojaerjestelmae-ips/)**: Nämä järjestelmät käyttävät erilaisia havaitsemismenetelmiä **hyökkäysten varhaiseen tunnistamiseen**, hälytysten lähettämiseen ja – IPS-järjestelmän ollessa käytössä – vastatoimenpiteiden automaattiseen käynnistämiseen.
- **Sovelluskerroksen yhdyskäytävä (ALG)**: ALG valvoo ja suodattaa sovellusten ja verkkoselainten välistä liikennettä suoraan sovellustasolla.
- **Verkkosovellusten palomuuri (WAF)**: WAF suojaa erityisesti verkkosovelluksia SQL-injektiolta ja sivustojen väliseltä skriptaukselta (XSS) estämällä tai puhdistamalla epäilyttävät pyynnöt.
- **Zero Trust -lähestymistapa**: Tämä moderni tietoturvamalli varmistaa, että jokainen pääsyyritys – sen alkuperästä riippumatta – tarkistetaan ja todennetaan ennen kuin pääsy myönnetään.
- **Palomuurisäännöt ja verkon segmentointi**: Nämä ovat välttämättömiä hyökkäyspinnan minimoimiseksi pitkällä aikavälillä.
- **Säännölliset IT-tietoturvatarkastukset ja [tunkeutumistestit](https://www.ionos.com/fi-fi/digitalguide/palvelin/osaaminen/tunkeutumistestaus-kattava-verkkotarkastus/)**: Nämä auttavat havaitsemaan ja korjaamaan haavoittuvuudet varhaisessa vaiheessa.

### Vaihe 3: Suojaa tietokanta ja käytä turvallista koodia

Aivan kuten käyttöjärjestelmänkin, myös tietokannasta tulisi poistaa kaikki tarpeettomat osat ja pitää se ajan tasalla. Poista kaikki tarpeettomat tallennetut menettelyt ja poista käytöstä kaikki käyttämättömät palvelut ja käyttäjätilit. Luo **erillinen tietokantatili**, joka on tarkoitettu yksinomaan verkkokäyttöön, ja myönnä sille vain välttämättömät käyttöoikeudet.

Valmiiden lauseiden käytön mukaisesti on erittäin suositeltavaa **olla käyttämättä** `mysql` (joka poistettiin PHP 7:stä). Valitse sen sijaan `mysqli` tai PDO, jotta varmistat paremman tietoturvan ja yhteensopivuuden. Turvallinen `mysqli` voisi näyttää tältä:

```php
$mysqli = new mysqli("localhost", "username", "password", "database");
if ($mysqli->connect_error) die("Connection failed");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$stmt->bind_result($hashedPassword);
if ($stmt->fetch() && password_verify($_POST['password'], $hashedPassword)) {
    echo "Login successful";
} else {
    echo "Invalid login credentials";
}
$stmt->close();
$mysqli->close();
```

Salasanoja ei saa koskaan tallentaa suoraan tietokantaan tai hakea selväkielisenä. Sen sijaan kannattaa käyttää hajautusmenetelmää, kuten `password_hash()`, yhdessä `password_verify()` kanssa käyttäjätunnusten suojaamiseksi turvallisesti. Turvallinen toteutus voisi näyttää tältä:

```php
$mysqli = new mysqli("localhost", "username", "password", "database");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if ($row && password_verify($_POST['password'], $row['password'])) {
    echo "Login successful!";
} else {
    echo "Incorrect username or password.";
}
```

## Mitä yhteistä bobby-pöydillä on SQL-injektion kanssa?

Verkkosivusto [bobby-tables.com](https://bobby-tables.com/ "Bobby Tables website") käyttää xkcd-verkkosarjakuvia havainnollistaakseen humoristisesti **tietokantoihin syötettävien** suojaamattomien **käyttäjätietojen** vaaroja. Sarjakuvassa äiti saa puhelun poikansa (jota kutsutaan hellästi nimellä Little Bobby Tables) koulusta. Soittaja kysyy, onko pojan nimi todella `Robert'); DROP TABLE Students;--`, mihin äiti vastaa myöntävästi. Soiton syy selviää pian: yritys syöttää nimi Robert oppilasrekisteriin johti **koko oppilastietokannan poistumiseen**. Äiti ei ole kovin myötätuntoinen – hän toivoo vain, että koulu on oppinut läksynsä ja puhdistaa jatkossa tietokantaan syötettävät tiedot.

Sarjakuva tuo selvästi esiin ne katastrofaaliset seuraukset, joita voi aiheutua siitä, ettei käyttäjän syöttämiä tietoja tarkisteta ja puhdisteta asianmukaisesti tietokantasovelluksissa.


This is a markdown version of: [https://www.ionos.com/fi-fi/digitalguide/palvelin/turvallisuus/sql-injektio-perusteet-ja-suojatoimenpiteet/](https://www.ionos.com/fi-fi/digitalguide/palvelin/turvallisuus/sql-injektio-perusteet-ja-suojatoimenpiteet/) for AI/LLM consumption.