SQL Injection je sigurnosni propust u web aplikacijama gdje napadači ubacuju štetan SQL kod putem korisničkog unosa. To im može omogućiti pristup osjetljivim podacima, promjenu sadržaja baze podataka ili čak preuzimanje kontrole nad sustavom. Važno je znati o SQL Injection kako bi web aplikacije bile sigurne.
SQL Injection (SQLi) je sigurnosna ranjivost koja se javlja kada napadač može manipulirati upitima baze podataka web aplikacije umetanjem zlonamjernog SQL koda u korisnička polja za unos. Ovi umetnuti upiti mogu manipulirati temeljnom bazom podataka kako bi dohvatili izmjenu ili brisanje osjetljivih podataka. U nekim slučajevima napadači mogu čak eskalirati privilegije stječući potpunu kontrolu nad bazom podataka ili poslužiteljem.

Primjer iz stvarnog svijeta:
Godine 2019. došlo je do povrede podataka Capital One zbog pogrešno konfigurirane web aplikacije koja je omogućila napadaču da iskoristi ranjivost SQL injekcije. To je rezultiralo curenjem osobnih podataka više od 100 milijuna klijenata, uključujući imena, adrese i kreditne rezultate.
Sigurnosna razina SQL injekcije
DVWA pruža četiri sigurnosne razine za SQL Injection kako bi pomogla učenicima da vide kako različite zaštite utječu na napade:
1. Niska sigurnost
Aplikacija uzima vaš unos i izravno ga stavlja u SQL upit bez filtriranja.
$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';- Ulazak
':Razbija upit i tjera bazu podataka da izbacuje pogrešku otkrivajući da je ranjiva. - Ulazak
1' OR '1'='1:Prevari upit da uvijek bude istinit tako da se svi korisnici vrate. - Ulazak
1' UNION SELECT user password FROM users--:Pridružuje se drugom upitu za dohvaćanje skrivenih podataka poput korisničkih imena i lozinki.
2. Srednja sigurnost
Aplikacija primjenjuje osnovnu dezinfekciju unosa pomoću funkcija kao što suaddslashes()pobjeći'.
$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';Kako može biti napad:
Jednostavan'injekcija više neće raditi (jer postaje').
Ali napadači i dalje mogu zaobići pomoću numeričke injekcije (budući da brojevima nisu potrebni navodnici).
Primjer:
arraylist.sort
1 OR 1=1Ovo i dalje vraća sve zapise.
3. Visoka sigurnost
Aplikacija koristi pripremljene izjave (parametrizirane upite) za sigurno rukovanje korisničkim unosom.
$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);Napad:
Pokušaji poput' OR 1=1iliUNION SELECTviše ne radi.
Upit tretira sav unos kao podatke, a ne kao SQL kod.
Vrste SQL injekcije
Postoje različite vrste SQL injekcije
1. SQL ubacivanje temeljeno na pogreškama
SQL ubacivanje temeljeno na pogrešci vrsta je unutarpojasnog SQL ubacivanja gdje napadač namjerno uzrokuje da baza podataka generira poruku o pogrešci. Napadač zatim analizira ovu poruku o pogrešci kako bi dobio vrijedne informacije o strukturi baze podataka poput naziva tablica i naziva stupaca koji se mogu koristiti za daljnje preciznije napade.
Kako to radi
Ovaj napad cilja na aplikacije koje otkrivaju pogreške sirove baze podataka umjesto da prikazuju generičke poruke. Ubacivanjem zlonamjernog unosa koji razbija SQL sintaksu, napadači pokreću te pogreške i dobivaju vrijedne tragove o strukturi baze podataka.
ymail
- Identificirajte ranjivi unos: Napadač pronalazi polje za unos kao što je traka za pretraživanje ili URL parametar koji izravno komunicira s bazom podataka bez odgovarajuće sanacije unosa.
- Ubaci zlonamjerni korisni teret: Napadač ubacuje poseban znak (poput jednog navodnika
') ili funkcija za koju se zna da uzrokuje pogrešku baze podataka. - Analizirajte pogrešku: Baza podataka koja ne može obraditi neispravan upit vraća detaljnu poruku o pogrešci. Ova poruka može otkriti ključne informacije kao što su:
- Sustav baze podataka (npr. MySQL Oracle SQL Server).
- Verzija baze podataka.
- Izvršava se puni SQL upit.
- Specifične sintaktičke pogreške koje se mogu koristiti za razumijevanje naziva tablica ili stupaca.
- Pročistite napad: Koristeći informacije prikupljene iz poruke o pogrešci, napadač može poboljšati svoj sadržaj kako bi izvukao više podataka kao što su korisnička imena i lozinke.
Primjer:
Korak 1: Postavite svoje okruženje
- Pokrenite DVWA. Obično mu se pristupa navigacijom na URL poput
http://localhost/dvwau vašem pregledniku.
- Prijavite se na DVWA sa zadanim vjerodajnicama:
admin/password.
- Idite na karticu Sigurnost DVWA i postavite razinu sigurnosti na nisku. To će osigurati lako iskorištavanje ranjivosti.
Korak 2: Identificirajte ranjivost
Stranica SQL Injection ima jednostavan okvir za unos u koji možete unijeti korisnički ID. Pozadinski upit vjerojatno je nešto poputSELECT * FROM users WHERE id = 'user_input'
- Unesite važeći ID poput
1u okvir za unos i kliknite na 'Pošalji'. Trebali biste vidjeti detalje za korisnika s ID-om 1.
Izvor SQL injekcije
PHP $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?> - Sada pokušajte prekinuti upit. Unesite jedan navodnik
'u polje za unos i pošaljite.
Upit postaje:
SELECT * FROM users WHERE id = ''';Ovdje baza podataka vidi dodatni citat i ne zna kako ispuniti upit.
zamijeni niz u Javi
Umjesto da vam pokaže podatke o korisniku, aplikacija će vratiti SQL pogrešku (nešto poput 'Imate pogrešku u svojoj SQL sintaksi...')
To se zove SQL ubacivanje na temelju pogreške jer:
- Napadač šalje nevažeći unos (
') - Baza podataka javlja pogrešku
- Ta pogreška propušta korisne informacije o bazi podataka (kao što je vrsta baze podataka, broj stupaca, struktura itd.)
2. SQL injekcija temeljena na uniji
SQL Injection temeljen na uniji je tehnika u kojoj napadači koristeUNIONoperator za kombiniranje rezultata dva ili višeSELECTizjave u jedan skup rezultata. To im može omogućiti izvlačenje informacija iz drugih tablica u bazi podataka. TheUNIONoperator se može koristiti samo ako:
- Oba upita imaju isti broj stupaca
- Stupci imaju slične vrste podataka
- Stupci su u istom redoslijedu
Operator UNION : TheUNIONkoristi se za kombiniranje skupa rezultata od dva ili višeSELECTizjave.
- Svaki
SELECTizjava unutarUNIONmoraju imati isti broj stupaca - Stupci moraju imati slične tipove podataka
- Stupci moraju biti u istom redoslijedu
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2Primjer:
Korak 1: Prvo moramo pronaći broj stupaca postojeće tablice na web-mjestu za ubacivanje SQL injekcije temeljene na UNION-u:
Stranica SQL Injection ima jednostavan okvir za unos u koji možete unijeti korisnički ID. Pozadinski upit vjerojatno je nešto poput
SELECT * FROM users WHERE id = 'user_input'Sada pokušajte prekinuti upit. Unesite jedan navodnik'u polje za unos i pošaljite.
Ako je aplikacija ranjiva, dobit ćete detaljnu poruku o pogrešci. Moglo bi izgledati otprilike ovako:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
Korak 2: KoristiteUNIONKljučna riječ za otkrivanje broja stupaca
Za korištenjeUNIONključna riječ (uobičajen sljedeći korak) trebate znati broj stupaca u izvornom upitu. To možete saznati pomoćuORDER BYklauzula
ime grada u SAD-u
- Pokušajte poredati rezultate po stupcima
1:1 ORDER BY 1.
- Pošalji. Trebalo bi raditi.
Izvor SQL injekcije
PHP if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?> - Povećaj broj:
1 ORDER BY 2. Pošalji. Trebalo bi raditi.
- Nastavite povećavati dok se ne pojavi pogreška. Na primjer
1 ORDER BY 4može vam dati:Unknown column '4' in 'order clause' - To znači da upit ima 3 stupca.
3. SQL ubrizgavanje na slijepo
Slijepo SQL ubrizgavanje događa se kada napadači ne mogu vidjeti rezultate upita izravno na web stranici. Umjesto toga, oni zaključuju informacije iz suptilnih promjena u ponašanju aplikacije ili vremenu odgovora. Iako sporiji i zamorniji od klasičnog SQLi-ja, može biti jednako učinkovit.
Umjesto da povrati podatke, napadač dolazi do informacija promatrajući ponašanje web stranice. To se obično radi na jedan od dva načina:
- Slijepi SQLi temeljen na Booleovim vrijednostima: Napadač ubacuje SQL upit koji vraća a pravi ili lažno proizlaziti. Odgovor web aplikacije mijenja se ovisno o tome je li upit točan ili netočan. Na primjer, stranica može prikazati drugačiju poruku ili prikazati drugačiji izgled.
- Vremenski slijepi SQLi: Napadač ubacuje SQL upit koji navodi bazu podataka da izvrši dugotrajnu radnju (poput
SLEEP()funkcija) ako je ispunjen uvjet. Napadač promatra vrijeme koje je potrebno da se stranica učita kako bi utvrdio je li ubačeno stanje istinito ili lažno.
Primjer:
Zamislite stranicu za prijavu na koju unosite korisničko ime i lozinku. Aplikacija konstruira SQL upit ovako:
SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'Slijepa SQL injekcija uključivala bi manipuliranjeuser_inputpolje za postavljanje pitanja bazi podataka.
Umjesto izravnog odgovora napadač bi mogao pokušati nešto poput ovoga:
user_input = 'admin' AND 1=1; --Ako se stranica učitava normalno, napadač to zna1=1je a pravi izjava.
user_input = 'admin' AND 1=2; --Ako stranica prikazuje pogrešku ili se ponaša drugačije, napadač to zna1=2je a lažno izjava.
Korištenjem niza ovih istinito/netočnih pitanja napadač može sustavno pogađati i izvlačiti informacije jedan po jedan znak. Proces se može automatizirati da pogodi sve, od naziva tablica do korisničkih lozinki.
Utjecaj napada SQL injekcijom
- Neovlašteni pristup osjetljivim podacima : Napadači mogu dohvatiti osobne financijske ili povjerljive informacije pohranjene u bazi podataka.
- Problemi s integritetom podataka : Napadači mogu modificirati izbrisati ili oštetiti kritične podatke koji utječu na funkcionalnost aplikacije.
- Eskalacija privilegija : Napadači mogu zaobići mehanizme provjere autentičnosti i dobiti administrativne privilegije.
- Zastoj usluge : SQL ubacivanje može preopteretiti poslužitelj uzrokujući degradaciju performansi ili pad sustava.
- Oštećenje ugleda : Uspješan napad može ozbiljno naštetiti ugledu organizacije što dovodi do gubitka povjerenja kupaca.
Sprječavanje napada SQL injekcijom
Postoji nekoliko najboljih praksi za sprječavanje napada SQL injekcijom:
1. Koristite pripremljene izjave i parametrizirane upite
Pripremljene izjave i parametrizirani upiti osiguravaju da se korisnički unosi tretiraju kao podaci, a ne kao dio SQL upita. Ovaj pristup eliminira rizik od ubacivanja SQL-a.
Primjer u PHP-u (koristeći MySQLi):
$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();2. Upotrijebite pohranjene procedure
Pohranjene procedure su unaprijed definirani SQL upiti pohranjeni u bazi podataka. Ovi postupci mogu spriječiti ubacivanje SQL-a jer ne izrađuju dinamički SQL upite.
put postavljen u Javi
Primjer:
CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;3. Provjera valjanosti unosa na bijelu listu
Osigurajte da su korisnički unosi potvrđeni prije upotrebe u SQL upitima. Dopustite samo određene znakove i uzorke kao što je alfanumerički unos za polja kao što su korisnička imena ili adrese e-pošte.
4. Koristite ORM okvire
Okviri objektno-relacijskog preslikavanja (ORM) poput Hibernacija ili Okvir entiteta može pomoći u sprječavanju ubacivanja SQL-a automatskim rukovanjem generiranjem upita sprječavajući konstrukciju dinamičkog upita.
5. Ograničite privilegije baze podataka
Korisnicima dodijelite minimalne potrebne dozvole za bazu podataka. Osigurajte da aplikacije mogu izvoditi samo potrebne radnje (npr. SELECT INSERT) i ograničite dopuštenja poput DROP TABLE ili ALTER.
6. Rješavanje pogrešaka
Konfigurirajte bazu podataka i aplikaciju da korisniku ne prikazuju detaljne poruke o pogrešci. Umjesto toga interno bilježite pogreške i prikazujte generičke poruke o pogreškama krajnjim korisnicima.