SQL-injektion ( engelsk SQL-injektion /SQli ) är ett av de vanligaste sätten att hacka webbplatser och program som fungerar med databaser , baserat på införandet av godtycklig SQL -kod i en fråga .
SQL-injektion, beroende på vilken typ av DBMS som används och villkoren för injektion, kan göra det möjligt för en angripare att köra en godtycklig fråga till databasen ( till exempel läsa innehållet i alla tabeller , ta bort, ändra eller lägga till data ), få möjligheten att läsa och/eller skriva lokala filer och utföra godtyckliga kommandon på den attackerade servern.
En attack av typen SQL-injektion kan vara möjlig på grund av felaktig bearbetning av indata som används i SQL-frågor.
En databasapplikationsutvecklare bör vara medveten om sådana sårbarheter och vidta åtgärder för att motverka SQL-injektion.
Det finns tre huvudklasser av attacker baserade på SQL-injektion:
Låt oss säga att serverprogramvaran , efter att ha fått indataparametern id, använder den för att skapa en SQL-fråga. Tänk på följande PHP- skript:
$id = $_REQUEST [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = " . $id );Om en id-parameter lika med 5 skickas till servern (till exempel: http://example.org/script.php?id=5 ), kommer följande SQL -fråga att köras:
VÄLJ * FRÅN nyheter WHERE id_news = 5Men om en angripare skickar strängen -1 ELLER 1=1 som id-parameter (till exempel så här: http://example.org/script.php?id=-1+OR+1=1 ), då begäran kommer att verkställas:
VÄLJ * FRÅN nyheter WHERE id_news = - 1 ELLER 1 = 1Att ändra inmatningsparametrarna genom att lägga till SQL-språkkonstruktioner till dem orsakar en förändring i SQL-frågeexekveringslogiken (i detta exempel, istället för nyheter med en given identifierare, kommer alla nyheter i databasen att väljas, eftersom uttrycket 1=1 är alltid sant - beräkningar utförs med den kortaste konturen i diagrammet ).
Anta att serverprogramvaran, efter att ha fått en begäran om att söka efter data i nyheterna med parametern search_text, använder den i följande SQL-fråga (här är parametrarna escaped med citattecken):
$search_text = $_REQUEST [ 'söktext' ]; $res = mysqli_query ( "SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('% $search_text %')" );Genom att göra en fråga som http://example.org/script.php?search_text=Test , får vi följande SQL-fråga att köras:
SELECT id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( ' %Test%' )Men genom att bädda in ett citattecken (som används i frågan) i parametern search_text kan vi drastiskt ändra beteendet hos SQL-frågan. Till exempel, genom att skicka värdet ' )+and+(news_id_author='1 ) som parametern search_text , anropar vi frågan som ska köras:
VÄLJ id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( ' %' ) och ( news_id_author = '1%' )SQL-språket låter dig kombinera resultaten av flera frågor med UNION- operatorn . Detta ger en angripare möjlighet att få obehörig åtkomst till data.
Låt oss överväga nyhetsvisningsskriptet ( identifieraren för nyheterna som ska visas skickas i id-parametern ):
$res = mysqli_query ( "VÄLJ id_news, header, body, author FROM news WHERE id_news = " . $_REQUEST [ 'id' ]);Om en angripare skickar -1 UNION SELECT 4 användarnamn, lösenord,1 FROM admin som id-parameter kommer detta att göra att SQL-frågan körs
SELECT id_news , header , body , author FROM news WHERE id_news = - 1 UNION SELECT 1 , användarnamn , lösenord , 1 FROM adminEftersom nyheter med identifierare -1 verkligen inte existerar kommer inga poster att väljas från nyhetstabellen, men resultatet kommer att inkludera poster som olagligt valdes från admintabellen som ett resultat av SQL-injektion.
I vissa fall kan en hackare attackera men kan inte se mer än en kolumn. När det gäller MySQL kan en angripare använda funktionen:
group_concat ( kol , symbol , kol )som kombinerar flera kolumner till en. Till exempel, för exemplet ovan, skulle funktionsanropet vara:
- 1 UNION SELECT group_concat ( användarnamn , 0 x3a , lösenord ) FRÅN adminOfta har SQL-frågan som påverkas av denna sårbarhet en struktur som gör det svårt eller omöjligt att använda union. Till exempel skript:
$res = mysqli_query ( "VÄLJ författare FRÅN nyheter WHERE id=" . $_REQUEST [ 'id' ] . " OCH författare LIKE ('a%')" );visar nyhetsförfattarens namn med den godkända id-identifieraren endast om namnet börjar med bokstaven a och kodinjektion med UNION-operatorn är svårt.
I sådana fall använder angripare metoden att undkomma en del av begäran med kommentarstecken ( /* eller -- beroende på typen av DBMS).
I det här exemplet kan en angripare skicka id-parametern med värdet -1 UNION SELECT-lösenord FROM admin/* till skriptet och på så sätt exekvera frågan
VÄLJ författare FRÅN nyheter WHERE id =- 1 UNION VÄLJ lösenord FRÅN admin /* OCH författare LIKE ('a%')i vilken del av frågan ( OCH författare GILLAR ('a%') ) är markerad som en kommentar och påverkar inte körningen.
Symbolen ; används för att separera kommandon i SQL - språket ; ( semikolon ) genom att bädda in det här tecknet i en fråga kan en angripare köra flera kommandon i en enda fråga, men alla SQL-dialekter stöder inte denna funktion.
Till exempel om i skriptparametrarna
$id = $_REQUEST [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = $id " );angriparen skickar en konstruktion som innehåller ett semikolon, till exempel 12;INSERT INTO admin (användarnamn, lösenord) VÄRDEN ('HackEr', 'foo'); då kommer 2 kommandon att köras i en fråga
SELECT * FROM news WHERE id_news = 12 ; INSERT INTO admin ( användarnamn , lösenord ) VÄRDEN ( 'HackEr' , 'foo' );och en obehörig hackerpost kommer att läggas till i administratörstabellen.
I detta skede undersöker angriparen beteendet hos serverskript vid manipulering av inmatningsparametrar för att upptäcka deras avvikande beteende. Manipulation sker med alla möjliga parametrar:
Som regel handlar manipulation om att ersätta ett enda (sällan dubbelt eller bakåt) citat i teckenparametrarna.
Onormalt beteende är alla beteenden där sidorna som hämtats före och efter offertbytet är olika (och inte visar sidan med ogiltiga parameterformat).
De vanligaste exemplen på anomalt beteende är:
etc. Man bör komma ihåg att det finns fall då felmeddelanden, på grund av detaljerna i sidmarkeringen, inte är synliga i webbläsaren, även om de finns i dess HTML-kod.
Design | Kommenterar resten av raden | Hämta version | Strängsammansättning |
---|---|---|---|
MySQL | -- ..., /* ..., eller# ... | version() | concat (string1, string2) |
MS SQL | -- ... | @@version | string1 + string2 |
Orakel | -- ...eller/* ... | select banner from v$version |
string1 || string2 ellerconcat (string1, string2) |
MS Access | Injicera en NULL-byte i en begäran:%00... | ||
PostgreSQL | -- ... | SELECT version() | string1 || string2,CONCAT('a','b') |
Sybase | -- ... | @@version | string1 + string2 |
IBM DB2 | -- ... | select versionnumber from sysibm.sysversions | string1 || string2ellerstring1 concat string2 |
Ingres | -- ... | dbmsinfo('_version') | string1 || string2 |
För att skydda mot denna typ av attack är det nödvändigt att noggrant filtrera ingångsparametrarna, vars värden kommer att användas för att bygga SQL-frågan.
Låt oss anta att koden som genererar begäran (i Pascals programmeringsspråk ) ser ut så här:
statement := 'SELECT * FROM users WHERE name = "' + användarnamn + '";' ;För att göra kodinjektion (att stänga en sträng som börjar med ett citat med ett annat citat innan det slutar med det aktuella avslutande citatet för att dela upp frågan i två delar) var det omöjligt, för vissa DBMS , inklusive MySQL , krävs det att alla strängparametrar citeras . I själva parametern, ersätt citattecken med \", apostrof med \', snedstrecket med \\ (detta kallas " escapende specialtecken "). Detta kan göras med följande kod:
statement := 'SELECT * FROM users WHERE name = ' + QuoteParam ( användarnamn ) + ';' ; funktion QuoteParam ( s : sträng ) : sträng ; { vid ingången - en sträng; utgången är en sträng inom citattecken och med specialtecken ersatta } var i : heltal ; dest : sträng _ börja Dest := '"' ; för i := 1 till längd ( er ) gör fall s [ i ] av ' '' ' : Dest := Dest + '\ '' ' ; '"' : Dest := Dest + '\"' ; '\' : Dest := Dest + '\\' ; annars Dest := Dest + s [ i ] ; end ; QuoteParam := Dest + '"' ; slut ;För PHP kan filtreringen vara så här:
$query = "SELECT * FROM users WHERE user='" . mysqli_real_escape_string ( $user ) . "';" ;Låt oss ta en annan begäran:
statement := 'SELECT * FROM users WHERE id = ' + id + ';' ;I det här fallet har fältet iden numerisk typ, och det är oftast inte citerat. Därför fungerar det inte att "citera" och ersätta specialtecken med escape-sekvenser. I det här fallet hjälper typkontroll; om variabeln idinte är ett tal ska frågan inte köras alls.
Till exempel i Delphi hjälper följande kod till att motverka sådana injektioner:
om TryStrToInt ( id , id_int ) then statement := Format ( 'SELECT * FROM users WHERE id =%0:d;' , [ id_int ]) ;För PHP skulle den här metoden se ut så här:
$query = 'VÄLJ * FRÅN användare WHERE id = ' . ( int ) $id ;För att göra ändringar i logiken för att köra en SQL-fråga krävs injicering av tillräckligt långa strängar. Så den minsta längden på den inbäddade strängen i exemplen ovan är 8 tecken (" 1 ELLER 1=1 "). Om den maximala längden på ett giltigt parametervärde är liten, kan en av skyddsmetoderna vara maximal trunkering av indataparametervärden.
Till exempel, om det är känt att fältet idi exemplen ovan kan ta värden högst 9999, kan du "klippa av de extra" tecknen och lämna inte mer än fyra:
statement := 'SELECT * FROM users WHERE id = ' + LeftStr ( id , 4 ) + ';' ;Många databasservrar stöder möjligheten att skicka parametriserade frågor (förberedda satser). I det här fallet skickas parametrar av externt ursprung till servern separat från själva förfrågan, eller escapes automatiskt av klientbiblioteket. För detta används de
Till exempel
var sql , param : sträng begin sql := 'välj :text som värde från dual' ; param := 'alfa' ; Fråga 1 . SQL . Text : = sql Fråga 1 . ParamByName ( 'text' ) . AsString := param ; Fråga 1 . öppen ; ShowMessage ( Fråga1 [ 'värde' ]) ; slut ;