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.
Az SQL injekción alapuló támadásoknak három fő osztálya van:
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 = 5De 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 ).
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 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átorMivel 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.
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 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.
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.
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:
Á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:
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 |
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.
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 ) . "';" ;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 ;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 ) + ';' ;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 ;