SQL-injektion

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 19 december 2021; kontroller kräver 9 redigeringar .

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.

Typer av attacker som SQL-injektion

Det finns tre huvudklasser av attacker baserade på SQL-injektion:

SQL Injection Attack Princip

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 = 5

Men 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 = 1

Att ä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 ).

Injektion i strängparametrar

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%' )

Använder UNION

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 admin

Eftersom 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.

Använder UNION + group_concat()

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 admin

Fråga svans escapeing

Ofta 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.

Dela upp en SQL-fråga

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.

SQL Injection Attack Techniques

Hitta skript som är sårbara för attack

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:

  • Data passerade genom POST- och GET-metoderna
  • [HTTP Cookie] värden
  • HTTP_REFERER (för skript)
  • AUTH_USER och AUTH_PASSWORD (när autentisering används)

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:

  • olika felmeddelanden visas;
  • när du begär data (till exempel nyheter eller en lista över produkter) visas inte den begärda informationen alls, även om sidan visas

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

Skydd mot attacker som SQL-injektion

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.

Filtrera strängparametrar

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 ) . "';" ;

Filtrera heltalsparametrar

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 ;

Trunkering av ingångsparametrar

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 ) + ';' ;

Använda parametriserade frågor

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

  • i Delphi  - egendom TQuery.Params;

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 ;
  • i Perl  - genom DBI::quoteeller DBI::prepare;
  • i Java  , genom klassen PreparedStatement;
  • i C#  - egenskap SqlCommand.Parameters;
  • i PHP  - MySQLi (när man arbetar med MySQL ), PDO.

Se även

Länkar