SQL Injekció

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2021. december 19-én felülvizsgált verziótól ; az ellenőrzések 9 szerkesztést igényelnek .

Az SQL injekció ( angolul  SQL injekció /SQLi ) az egyik legelterjedtebb módja az adatbázisokkal együttműködő webhelyek és programok feltörésének, amely tetszőleges SQL -kód lekérdezésbe történő bevezetésén alapul .

Az SQL-befecskendezés a használt DBMS típusától és a befecskendezési feltételektől függően lehetővé teheti a támadó számára, hogy tetszőleges lekérdezést hajtson végre az adatbázisban ( például bármely tábla tartalmát beolvassa, adatokat töröljön, módosítson vagy hozzáadjon ), megszerezze a lehetőséget. helyi fájlok olvasásához és/vagy írásához, valamint tetszőleges parancsok végrehajtásához a támadott szerveren.

Az SQL-lekérdezésekben használt bemeneti adatok helytelen feldolgozása miatt SQL-befecskendezési típusú támadás lehetséges.

Az adatbázis-alkalmazások fejlesztőjének tisztában kell lennie az ilyen sérülékenységekkel, és lépéseket kell tennie az SQL-befecskendezés ellen.

A támadások típusai, például az SQL injekció

Az SQL injekción alapuló támadásoknak három fő osztálya van:

SQL Injection Attack Principle

Tegyük fel, hogy a szerverszoftver , miután megkapta az id bemeneti paramétert, egy SQL lekérdezés létrehozására használja. Tekintsük a következő PHP szkriptet:

$id = $_REQUEST [ 'azonosító' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = " . $id );

Ha egy 5-tel egyenlő id paramétert adnak át a szervernek (például: http://example.org/script.php?id=5 ), akkor a következő SQL lekérdezés kerül végrehajtásra:

SELECT * FROM news WHERE id_news = 5

De ha egy támadó a -1 VAGY 1=1 karakterláncot adja át id paraméterként (például így: http://example.org/script.php?id=-1+OR+1=1 ), akkor a a kérés végrehajtásra kerül:

SELECT * FROM news WHERE id_news = - 1 VAGY 1 = 1

Így a bemeneti paraméterek megváltoztatása SQL nyelvi konstrukciók hozzáadásával változást okoz az SQL lekérdezés végrehajtási logikájában (ebben a példában az adott azonosítójú hír helyett az adatbázisban lévő összes hír lesz kiválasztva, mivel az 1=1 kifejezés mindig igaz - a számításokat a diagram legrövidebb kontúrjával végezzük ).

Injektálás karakterlánc-paraméterekbe

Tegyük fel, hogy a szerverszoftver, miután kapott egy kérést, hogy a hírekben keressen adatokat a search_text paraméterrel, ezt használja a következő SQL lekérdezésben (itt a paraméterek idézőjelekkel vannak kiemelve):

$kereső_szöveg = $_REQUEST [ 'keresőszöveg' ]; $res = mysqli_query ( "SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('% $search_text %')" );

Egy olyan lekérdezéssel, mint a http://example.org/script.php?search_text=Test , a következő SQL lekérdezést kapjuk végrehajtandó:

SELECT id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( '%Test%' )

De ha egy idézet karaktert (amelyet a lekérdezésben használunk) beágyazunk a search_text paraméterbe, akkor drasztikusan megváltoztathatjuk az SQL lekérdezés viselkedését. Például a ' )+and+(news_id_author='1 ) érték átadásával search_text paraméterként meg fogjuk hívni a végrehajtandó lekérdezést:

SELECT id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( '%' ) és ( news_id_author = '1%' )

Az UNION használatával

Az SQL nyelv lehetővé teszi több lekérdezés eredményeinek kombinálását az UNION operátor használatával . Ez lehetőséget ad a támadónak, hogy jogosulatlan hozzáférést kapjon az adatokhoz.

Tekintsük a hírmegjelenítési szkriptet ( a megjelenítendő hír azonosítója az id paraméterben van átadva ):

$res = mysqli_query ( "SELECT id_news, header, body, author FROM news WHERE id_news = " . $_REQUEST [ 'id' ]);

Ha egy támadó megadja a -1 UNION SELECT 4 felhasználónevet, jelszót, 1 FROM admin paramétert id paraméterként , ez az SQL lekérdezést fogja végrehajtani.

SELECT id_news , header , body , author FROM news WHERE id_news = - 1 UNION SELECT 1 , felhasználónév , jelszó , 1 FROM adminisztrátor

Mivel a -1 azonosítójú hír biztosan nem létezik, a hírtáblából egyetlen rekord sem lesz kiválasztva, hanem az eredmény olyan rekordokat tartalmaz, amelyek az adminisztrációs táblából SQL injekció hatására illegálisan kerültek kiválasztásra.

Az UNION + group_concat() használatával

Egyes esetekben a hacker támadhat, de nem lát egynél több oszlopot. MySQL esetén a támadó használhatja a következő funkciót:

group_concat ( oszlop , szimbólum , oszlop )

amely több oszlopot egyesít egybe. Például a fenti példában a függvényhívás a következő lenne:

- 1 UNION SELECT group_concat ( felhasználónév , 0 x3a , jelszó ) adminisztrátortól _

A lekérdezés farka menekülő

A biztonsági rés által érintett SQL-lekérdezés gyakran olyan szerkezettel rendelkezik, amely megnehezíti vagy lehetetlenné teszi az union használatát. Például script:

$res = mysqli_query ( "Szerző KIVÁLASZTÁSA HÍREKBŐL WHERE id=" . $_REQUEST [ 'id' ] . " ÉS szerző LIKE ('a%')" );

csak akkor jeleníti meg a hírszerző nevét az átadott azonosítóval, ha a név a betűvel kezdődik, és az UNION operátor használatával nehéz a kódbefecskendezés.

Ilyen esetekben a támadók azt a módszert használják, hogy megjegyzés karakterekkel ( /* vagy -- a DBMS típusától függően) megszökjék a kérés egy részét.

Ebben a példában a támadó átadhatja az id paramétert -1 UNION SELECT jelszó FROM admin/* értékkel a szkriptnek , így végrehajtja a lekérdezést.

Szerző KIVÁLASZTÁSA HÍREKBŐL WHERE id =- 1 UNION SELECT jelszó FROM adminisztrátortól /* ÉS szerző LIKE ('a%' )

amelyben a lekérdezés része ( ÉS szerző LIKE ('a%') ) megjegyzésként van megjelölve, és nem befolyásolja a végrehajtást.

SQL lekérdezés felosztása

A ; szimbólum a parancsok elválasztására szolgál az SQL nyelvben ; ( pontosvessző ) ennek a karakternek a lekérdezésbe való beágyazásával a támadó több parancsot is végrehajthat egyetlen lekérdezésben, azonban nem minden SQL dialektus támogatja ezt a képességet.

Például, ha a szkript paramétereiben

$id = $_REQUEST [ 'azonosító' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = $id " );

a támadó pontosvesszőt tartalmazó konstrukciót ad át, például 12;INSERT INTO admin (felhasználónév, jelszó) VALUES ('HaCkEr', 'foo'); akkor egy lekérdezésben 2 parancs kerül végrehajtásra

SELECT * FROM news WHERE id_news = 12 ; INSERT INTO admin ( felhasználónév , jelszó ) VALUES ( 'HaCkEr' , 'foo' );

és egy jogosulatlan HaCkEr rekord hozzáadódik az adminisztrációs táblához.

SQL-injekciós támadási technikák

Támadásra sebezhető szkriptek keresése

Ebben a szakaszban a támadó megvizsgálja a kiszolgálói szkriptek viselkedését a bemeneti paraméterek manipulálásakor, hogy észlelje a rendellenes viselkedésüket. A manipuláció az összes lehetséges paraméterrel történik:

  • Az adatok a POST és GET metódusokon mentek keresztül
  • [HTTP Cookie] értékek
  • HTTP_REFERER (szkriptekhez)
  • AUTH_USER és AUTH_PASSWORD (hitelesítés használatakor)

Általános szabály, hogy a manipuláció egyetlen (ritkábban dupla vagy vissza) idézőjel behelyettesítésével jár a karakterparaméterekben.

Rendellenes viselkedés minden olyan viselkedés, amelyben az idézet helyettesítése előtt és után letöltött oldalak eltérőek (és nem jelenítik meg az érvénytelen paraméterformátumú oldalt).

A rendellenes viselkedés leggyakoribb példái a következők:

  • különféle hibaüzenetek jelennek meg;
  • adatkéréskor (például hír vagy terméklista) a kért adatok egyáltalán nem jelennek meg, bár az oldal megjelenik

stb. Nem szabad megfeledkezni arról, hogy vannak esetek, amikor a hibaüzenetek az oldal jelölésének sajátosságai miatt nem láthatók a böngészőben, bár a HTML kódban jelen vannak.

Tervezés A sor többi részének kommentálása Változat beszerzése Karakterlánc összefűzése
MySQL -- ..., /* ..., vagy# ... version() concat (string1, string2)
MS SQL -- ... @@version string1 + string2
Jóslat -- ...vagy/* ... select banner
from v$version
string1 || string2
vagyconcat (string1, string2)
MS Access NULL bájt beszúrása egy kérésbe:%00...
PostgreSQL -- ... SELECT version() string1 || string2,CONCAT('a','b')
Sybase -- ... @@version string1 + string2
IBM DB2 -- ... select versionnumber from sysibm.sysversions string1 || string2vagystring1 concat string2
Ingres -- ... dbmsinfo('_version') string1 || string2

Védelem olyan támadások ellen, mint az SQL injekció

Az ilyen típusú támadások elleni védelem érdekében gondosan ki kell szűrni a bemeneti paramétereket, amelyek értékeit az SQL-lekérdezés felépítéséhez kell használni.

Karakterlánc-paraméterek szűrése

Tegyük fel, hogy a kérést generáló kód ( Pascal programozási nyelvben ) így néz ki:

utasítás := 'SELECT * FROM users WHERE name = "' + userName + '";' ;

A kódbefecskendezés (egy idézőjellel kezdődő karakterlánc bezárása egy másik idézettel, mielőtt az az aktuális záró idézettel véget érne, hogy a lekérdezést két részre bontsa) lehetetlen volt, bizonyos DBMS -ek esetében, beleértve a MySQL -t is, minden karakterlánc-paramétert idézni kell. . Magában a paraméterben cserélje ki az idézőjeleket \-re, az aposztrófot \'-re, a fordított perjelet pedig \\-re (ezt hívják " kilépő speciális karaktereknek "). Ezt a következő kóddal teheti meg:

utasítás := 'SELECT * FROM users WHERE name = ' + QuoteParam ( userName ) + ';' ; function QuoteParam ( s : string ) : string ; { a bemeneten - egy karakterlánc; a kimenet egy karakterlánc idézőjelben, speciális karakterekkel helyettesítve } var i : integer ; cél : string_ _ begin Dest := '"' ; for i := 1 to long ( s ) do case s [ i ] of ' ' ' : Dest := Dest + '\ '' ' ; '"' : Dest := Cél + '\"' ; '\' : Cél := Cél + '\\' ; else Dest := Cél + s [ i ] ; end ; QuoteParam := Cél + '"' ; vége ;

PHP esetén a szűrés a következő lehet:

$query = "SELECT * FROM users WHERE user='" . mysqli_real_escape_string ( $user ) . "';" ;

Egész paraméterek szűrése

Vegyünk egy másik lekérdezést:

utasítás := 'SELECT * FROM felhasználók WHERE id = ' + id + ';' ;

Ebben az esetben a mezőnek idnumerikus típusa van, és legtöbbször nem idézzük. Ezért az "idézés" és a speciális karakterek escape szekvenciákkal való helyettesítése nem működik. Ilyenkor a típusellenőrzés segít; ha a változó idnem szám, akkor a lekérdezésnek egyáltalán nem szabad lefutnia.

Például a Delphiben a következő kód segít az ilyen injekciók ellen:

if TryStrToInt ( id , id_int ) then utasítás := Formátum ( 'SELECT * FROM users WHERE id =%0:d;' , [ id_int ]) ;

PHP esetén ez a módszer így néz ki:

$query = 'SELECT * FROM felhasználók WHERE id = ' . ( int ) $id ;

A bemeneti paraméterek csonkolása

Az SQL-lekérdezés végrehajtási logikájának módosításához kellően hosszú karakterláncok befecskendezése szükséges. Tehát a fenti példákban a beágyazott karakterlánc minimális hossza 8 karakter (“ 1 VAGY 1=1 ”). Ha egy érvényes paraméterérték maximális hossza kicsi, akkor az egyik védelmi módszer lehet a bemeneti paraméterértékek maximális csonkolása.

Például, ha ismert, hogy ida fenti példák mezője legfeljebb 9999 értéket vehet fel, akkor „levághatja az extra” karaktereket, és legfeljebb négyet hagyhat meg:

utasítás := 'SELECT * FROM felhasználók WHERE id = ' + LeftStr ( id , 4 ) + ';' ;

Paraméterezett lekérdezések használata

Számos adatbázis-kiszolgáló támogatja a paraméterezett lekérdezések (előkészített utasítások) küldését. Ebben az esetben a külső eredetű paraméterek a kéréstől külön-külön kerülnek elküldésre a szervernek, vagy a klienskönyvtár automatikusan kihagyja őket. Erre használják őket

Például

var sql , param : string begin sql := 'kiválasztás :szöveg értékként dualból' ; param := 'alpha' ; 1. lekérdezés . SQL . Szöveg : = sql 1. lekérdezés . ParamByName ( 'szöveg' ) . AsString := param ; 1. lekérdezés . nyitott ; ShowMessage ( Query1 [ 'érték' ]) ; vége ;
  • Perlben  - keresztül DBI::quotevagy DBI::prepare;
  • Java nyelven ,  az osztályon keresztül PreparedStatement;
  • in C#  - property SqlCommand.Parameters;
  • PHP -ben  - MySQLi (ha MySQL - lel dolgozik ), PDO.

Lásd még

Linkek