SQL-in­jek­ci­jas rada būtisku ap­drau­dē­ju­mu relāciju datubāzu modeļiem un tajos esošajai kon­fi­den­ciā­la­jai in­for­mā­ci­jai. Tāpēc ir absolūti ne­pie­cie­ša­ma vi­s­ap­tve­ro­ša aiz­sar­dzī­ba pret šiem ne­at­ļau­tiem ārējiem piekļuves mē­ģi­nā­ju­miem, kurus padara ie­spē­ja­mus drošības ie­vai­no­ja­mī­bas.

Kas ir SQL injekcija?

SQL injekcija ir uzbrukuma veids, kas izmanto drošības ie­vai­no­ja­mī­bu relatīvo datubāzu sistēmās, kuras lieto SQL vaicājumu valodu lietotāja ievadīto datu apstrādei. Uzbrucējs izmanto lietotāju ievadītos datus, kas nav pareizi attīrīti un satur īpašus simbolus, piemēram, dubultos defises, pēdiņas vai se­mi­ko­lo­nu. Šiem simboliem ir īpašas funkcijas SQL in­ter­pre­ta­to­rā, un tie ļauj ārēji manipulēt ar iz­pil­dā­ma­jām komandām. SQL in­jek­ci­jas bieži saistās ar PHP un ASP lie­to­jum­prog­ram­mām, kas balstās uz no­ve­co­ju­šām saskarnēm. Daudzos šādos gadījumos ievadītie dati netiek pienācīgi attīrīti, padarot tos par galveno uzbrukuma mērķi.

Stra­tē­ģis­ki ie­vie­to­jot funkciju simbolus, neatļauts lietotājs var ievadīt papildu SQL komandas un manipulēt ar datu bāzes ie­rak­stiem, lai lasītu, mainītu vai dzēstu datus. Smagākos gadījumos uzbrucēji var pat iegūt piekļuvi sistēmas komandu rindai, kas ļautu viņiem pārņemt pilnīgu kontroli pār datu bāzes serveri.

SQL in­jek­ci­jas piemērs, kas parāda, kā darbojas uzbrukums datu bāzei

Tā kā ne­aiz­sar­gā­tus datubāzes serverus var ātri iden­ti­fi­cēt un SQL in­jek­ci­jas uz­bru­ku­mus ir sa­lī­dzi­no­ši viegli veikt, šī metode joprojām ir viena no visplašāk iz­man­to­ta­jām metodēm ki­ber­no­ziedz­nie­ku vidū visā pasaulē. Uzbrucēji izmanto dažādas stra­tē­ģi­jas, iz­man­to­jot gan nesen atklātus, gan jau sen zināmus drošības trūkumus lie­to­jum­prog­ram­mās, kas ie­sais­tī­tas datu pār­val­dī­bas procesā. Lai labāk izprastu, kā SQL injekcija darbojas praksē, aplūkosim divas iz­pla­tī­tas uzbrukuma metodes kā piemērus.

1. piemērs: Piekļuve, iz­man­to­jot nepareizi attīrītu lietotāja ievadīto in­for­mā­ci­ju

Lai piekļūtu datu bāzei, lie­to­tā­jiem parasti vispirms ir jā­au­ten­ti­fi­cē­jas. Šim nolūkam parasti izmanto skriptus, kas parāda pie­teik­ša­nās veidlapu ar laukiem lie­to­tājvār­dam un parolai. Lietotāji aizpilda formu, un skripts pēc tam pārbauda, vai datu bāzē ir at­bil­sto­ši ieraksti. Pēc no­klu­sē­ju­ma datu bāzē var būt tabula ar nosaukumu users un kolonnām username un password. Tipiskā tīmekļa lie­to­jum­prog­ram­mā at­tie­cī­gās skripta rindas datu bāzes piekļuvei (iz­man­to­jot Python līdzīgu psei­do­ko­du) var iz­ska­tī­ties šādi:

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

Tagad uzbrucējs var manipulēt ar paroles lauku, iz­man­to­jot SQL injekciju, piemēram, ievadot password' OR 1='1, kas izraisa šādu SQL vaicājumu:

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

Tas uz­bru­cē­jam nodrošina pilnīgu piekļuvi visai lietotāju tabulai datu bāzē, jo paroles no­sa­cī­jums vienmēr iz­vēr­tē­jas kā patiesība (1='1'). Ja uzbrucējs piesakās kā ad­mi­nis­tra­tors, viņš var brīvi mainīt jebkuru ierakstu datu bāzē. Tāpat var manipulēt arī ar lie­to­tājvār­da lauku.

2. piemērs: Datu izgūšana, ma­ni­pu­lē­jot ar iden­ti­fi­ka­to­riem

In­for­mā­ci­jas izgūšana no datu bāzes pēc iden­ti­fi­ka­to­ra ir praktiska un izplatīta metode, taču tā arī rada iespējamu risku SQL in­jek­ci­jas uz­bru­ku­miem. Piemēram, tīmekļa serveris, iz­man­to­jot URL adresē nosūtīto iden­ti­fi­ka­to­ra in­for­mā­ci­ju, zina, kādu in­for­mā­ci­ju tam jāizgūst no datu bāzes. At­bil­sto­šais PHP skripts izskatās šādi:

<?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);
    }
?>
php

Pa­re­dzē­tais URL atbilst paraugam .../script.php?id=22. Šajā gadījumā tiktu izgūts tabulas ieraksts ar ID „22”. Ja ne­at­ļau­tai personai ir iespēja manipulēt ar šo URL un tā vietā nosūta pie­pra­sī­ju­mu, piemēram, .../script.php?id=22+OR+1=1, rezultātā iz­pil­dī­tais vaicājums izraisīs visu tabulas rindu izgūšanu:

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

Kā no­ziedz­nie­ki atrod ne­aiz­sar­gā­tas datu bāzes sistēmas?

Principā jebkura tīmekļa vietne vai tīmekļa lie­to­jum­prog­ram­ma, kas izmanto SQL datu bāzes bez sa­ga­ta­vo­tiem vai­cā­ju­miem (prepared sta­te­ments) vai citiem aiz­sar­dzī­bas pa­sā­ku­miem, var būt ne­aiz­sar­gā­ta pret SQL in­jek­ci­jām. Atklātās ie­vai­no­ja­mī­bas tīmeklī ilgi nepaliek ne­pa­ma­nī­tas. Patiesībā ir tīmekļa vietnes, kas publicē at­jau­ni­nā­tus sarakstus ar zi­nā­ma­jiem drošības trūkumiem — un pat izskaidro, kā uzbrucēji var izmantot Google meklēšanu, lai atrastu at­bil­sto­šus tīmekļa projektus. Ja tīmekļa vietne atgriež de­ta­li­zē­tus SQL kļūdu ziņojumus, ki­ber­no­ziedz­nie­ki var izmantot šos ziņojumus, lai iden­ti­fi­cē­tu po­ten­ciā­los ie­vai­no­ja­mī­bas punktus. Piemēram, apostrofa pie­vie­no­ša­na URL galam, kas ietver ID parametru, jau var atklāt vājumu, kā parādīts šajā piemērā:

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

Ne­aiz­sar­gā­ta tīmekļa vietne atgriež kļūdas ziņojumu šādā formā:

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

Līdzīgas metodes var izmantot arī, lai iegūtu kolonnu skaitu, tabulu un kolonnu no­sau­ku­mus, SQL versiju vai pat lie­to­tājvār­dus un paroles. Turklāt ir pieejami dažādi rīki, kas spēj au­to­ma­ti­zēt gan uzlaužamo vietu mek­lē­ša­nas procesu, gan SQL in­jek­ci­jas uzbrukumu izpildi.

Kā pasargāt savu datu bāzi no SQL-in­jek­ci­jas

Ir dažādas metodes, ko varat izmantot, lai novērstu SQL in­jek­ci­jas uz­bru­ku­mus savai datu bāzes sistēmai. Jums jā­pie­vēr­šas visām ie­sais­tī­ta­jām sa­stāv­da­ļām – gan serverim un at­se­viš­ķām lie­to­jum­prog­ram­mām, gan datu bāzes pār­val­dī­bas sistēmai.

1. solis: Au­to­mā­tis­ko datu ievadi no lie­to­jum­prog­ram­mām

Ap­strā­dā­jot datus no ārējām vai ie­bū­vē­ta­jām lie­to­jum­prog­ram­mām, ir būtiski pārbaudīt un filtrēt ie­snieg­tās vērtības, lai novērstu SQL-in­jek­ci­jas.

1. Pārbaudīt datu tipus

Katram ievades laukam jāatbilst pa­re­dzē­ta­jam datu tipam. Piemēram, ja ir ne­pie­cie­ša­ma skait­lis­ka ievade, vienkārša pārbaude PHP varētu iz­ska­tī­ties šādi:

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

Līdzīgas pārbaudes būtu jāievieš arī attiecībā uz teksta virknēm, datumiem vai citiem spe­ci­fis­kiem formātiem.

2. Filtrēt īpašos simbolus

Īpašie simboli var radīt drošības risku, jo īpaši SQL vai HTML vidē. Droša pieeja ir izmantot htmlspecialchars() HTML ievadei un PDO::quote() SQL vai­cā­ju­miem.

3. Iz­vai­rie­ties no kļūdu ziņojumu pa­rā­dī­ša­nas

Jā­iz­vai­rās no tiešiem kļūdu zi­ņo­ju­miem, kuros tiek atklātas tehniskas detaļas par datu bāzi vai sistēmu. Tā vietā jāparāda vispārīgs ziņojums, piemēram:

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

4. Iz­man­to­jiet sa­ga­ta­vo­tus vai­cā­ju­mus

Viens no vi­s­efek­tī­vā­ka­jiem veidiem, kā novērst SQL in­jek­ci­jas, ir sa­ga­ta­vo­to izteikumu iz­man­to­ša­na. Šajā pieejā SQL komandas un parametri tiek nosūtīti atsevišķi, tādējādi ļaun­prā­tīgs kods nevar tikt izpildīts. Šeit ir īss īs­te­no­ju­ma piemērs PHP, iz­man­to­jot PDO (PHP Data Objects):

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

Datu bāzes pār­val­dī­bas sistēma au­to­mā­tis­ki nodrošina, ka ievadītie dati tiek ap­strā­dā­ti droši.

2. solis: No­dro­ši­niet vi­s­ap­tve­ro­šu servera aiz­sar­dzī­bu

SQL injekciju novēršanā būtiska nozīme ir arī tā servera drošībai, kurā darbojas jūsu datubāzes pār­val­dī­bas sistēma. Viens no gal­ve­na­jiem pa­sā­ku­miem ir ope­rē­tājsis­tē­mas drošības pa­stip­ri­nā­ša­na, ievērojot šādus ie­tei­ku­mus:

  • In­sta­lē­jiet vai ak­ti­vi­zē­jiet tikai tās lie­to­jum­prog­ram­mas un pa­kal­po­ju­mus, kas ir ne­pie­cie­ša­mi datu bāzes darbībai.
  • Dzēst visus ne­iz­man­to­tos vai ne­va­ja­dzī­gos lietotāju kontus.
  • No­dro­ši­niet, ka visi at­tie­cī­gie sistēmas un prog­ram­ma­tū­ras at­jau­ni­nā­ju­mi tiek instalēti ne­ka­vē­jo­ties.
  • Pie­mē­ro­jiet minimālo pri­vi­lē­ģi­ju principu, lai no­dro­ši­nā­tu, ka lie­to­tā­jiem un pa­kal­po­ju­miem tiek pie­šķir­tas tikai minimālās ne­pie­cie­ša­mās atļaujas.

Atkarībā no jūsu tīmekļa projekta drošības prasībām, jums vajadzētu apsvērt papildu aiz­sar­dzī­bas pasākumus:

  • Iebrukuma at­klā­ša­nas sistēmas (IDS) un iebrukuma no­vēr­ša­nas sistēmas (IPS): Šīs sistēmas izmanto dažādas at­klā­ša­nas metodes, lai sav­lai­cī­gi iden­ti­fi­cē­tu uz­bru­ku­mus, izsūtītu brī­di­nā­ju­mus un — ja tiek izmantota IPS — au­to­mā­tis­ki uzsāktu pret­pa­sā­ku­mus.
  • Lie­to­jum­prog­ram­mu slāņa vārteja (ALG): ALG uzrauga un filtrē datplūsmu starp lie­to­jum­prog­ram­mām un tīmekļa pār­lūkprog­ram­mām tieši lie­to­jum­prog­ram­mu līmenī.
  • Tīmekļa lie­to­jum­prog­ram­mu ugunsmū­ris (WAF): WAF īpaši aizsargā tīmekļa lie­to­jum­prog­ram­mas no SQL in­jek­ci­jas un starplap­ju skriptē­ša­nas (XSS), bloķējot vai attīrot aiz­do­mī­gus pie­pra­sī­ju­mus.
  • Zero Trust pieeja: Šis modernais drošības modelis nodrošina, ka katrs piekļuves mē­ģi­nā­jums — ne­at­ka­rī­gi no tā izcelsmes — tiek pār­bau­dīts un au­ten­ti­fi­cēts, pirms tiek piešķirta piekļuve.
  • Ugunsmūra noteikumi un tīkla seg­men­tā­ci­ja: Tie ir būtiski, lai ilgter­mi­ņā sa­ma­zi­nā­tu uzbrukumu risku.
  • Regulāras IT drošības revīzijas un ie­kļū­ša­nas testi: Tie palīdz agrīnā stadijā atklāt un novērst ie­vai­no­ja­mī­bas.

3. solis: Datubāzes drošības pa­stip­ri­nā­ša­na un droša koda iz­man­to­ša­na

Tāpat kā ope­rē­tājsis­tē­mai, arī datu bāzei ir jā­at­brī­vo­jas no visām ne­va­ja­dzī­ga­jām sa­stāv­da­ļām un jāuztur at­jau­ni­nā­ta. Izdzēsiet visas ne­va­ja­dzī­gās sa­gla­bā­tās pro­ce­dū­ras un at­spē­jo­jiet visus ne­iz­man­to­tos pa­kal­po­ju­mus un lietotāju kontus. Iz­vei­do­jiet īpašu datu bāzes kontu, kas paredzēts vienīgi tīmekļa piekļuvei, un pie­šķi­riet tam tikai minimālās ne­pie­cie­ša­mās atļaujas.

Ņemot vērā sa­ga­ta­vo­to vaicājumu iz­man­to­ša­nu, tiek stingri ieteikts ne­iz­man­tot mysql PHP moduli (kas tika izņemts no PHP 7). Tā vietā iz­vē­lie­ties mysqli vai PDO, lai no­dro­ši­nā­tu labāku drošību un saderību. Drošs mysqli vaicājums varētu iz­ska­tī­ties šādi:

$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();
php

Paroles nekad nedrīkst glabāt tieši datu bāzē vai izgūt nešifrētā veidā. Tā vietā iz­man­to­jiet hašēšanas metodi, piemēram, password_hash(), kopā ar password_verify(), lai droši aiz­sar­gā­tu piekļuves datus. Droša īs­te­no­ša­na varētu iz­ska­tī­ties šādi:

$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.";
}
php

Kāda saistība ir bobby galdiem ar SQL injekciju?

Tīmekļa vietne bobby-tables.com izmanto xkcd tīmekļa komiksu, lai ar humoru ilustrētu nedrošas lietotāju ievadīto datu radītos draudus datu bāzēs. Komiksā māte saņem zvanu no sava dēla (mīļi saukta par Little Bobby Tables) skolas. Zvanītājs jautā, vai viņas dēla vārds patiešām ir Robert'); DROP TABLE Students;--, uz ko viņa atbild ap­stip­ri­no­ši. Zva­nī­ša­nas iemesls drīz kļūst skaidrs: mē­ģi­nā­jums ievadīt vārdu Robert skolēnu datu bāzē izraisīja visu skolēnu tabulu dzēšanu. Māte nav pārāk saprotoša — viņa vienkārši cer, ka skola ir guvusi mācību un turpmāk pārbaudīs datu bāzes ievadi.

Komikss skaidri parāda ka­tas­tro­fā­lās sekas, kas var rasties, ja datubāzes lie­to­jum­prog­ram­mās netiek pienācīgi pār­bau­dī­ti un attīrīti lietotāju ievadītie dati.

Go to Main Menu