Hvad er Sql Injection?

Tags:    php

Hej.

jeg har et, tror jeg nok simpelt spørgsmål: Hvad er Sql Injection?

Har læst noget omkring det, men jeg vil gerne lige have helt styr på hvad det er.



10 svar postet i denne tråd vises herunder
3 indlæg har modtaget i alt 3 karma
Sorter efter stemmer Sorter efter dato
SQL injection er en form for angreb man kan lave på en hjemmeside.

Tag f.eks. følgende eksempel

Fold kodeboks ind/udKode 


Det der er meningen at der skal ske er at hvis man indtaster det rigtige brugernavn og password bliver man logget ind.

MEN! Der er et problem.

"SELECT * FROM users WHERE username = $user AND password = $pass"

Som du kan se bliver $username og $password sat ind i dette query. Det vil sige at alt hvad vi skriver i username og password feltet i vores form vil blive indsat i queryet.

Hvis man så skriver ' or '1'='1' i begge felter vil vores query nu se sådan ud

"SELECT * FROM users WHERE username = or '1'='1' AND password = or '1'='1'"

Da 1 altid er lige med 1 vil queryet blive true og vi vil derfor blive logget ind uden at have hverken brugernavn eller password.

Det skal så lige siges at php efterhånden er så sikkert så dette kan ikke lade sig gøre med mindre slår et par sikkerhedsfunktioner fra i php.



Der er også en anden måde der foregår via GET variabler.

Fx hvis du har et artikel system hvor du bruger en GET variable til at finde ud af hvilken artikel vi skal have fat i, så ser query'en fx sådan her ud:

SELECT * FROM Artikel WHERE ID=12

Her kommer 12 så fx fra en GET variable. Dvs at der i adresselinien står fx artikel.php?artikel=12

Men hvis brugeren så skriver
artikel.php?artikel=12;DROP TABLE Artikel

Så ser query sådan her ud:
SELECT * FROM Artikel WHERE ID=12;DROP TABLE Artikel

Ovenstående query vil kunne SLETTE artikel 12 fra databasen, såfremt rettighederne giver mulighed for dette, og hermed give hvem som helst mulighed for manuelt at tømme databasen for artikler, hvis de skulle få lyst.



PHP har en indstilling, som er sat til som standard, der hedder Magic Quotes. Denne indstilling laver om på inputs, som kommer *direkte* fra brugeren, så de kan indsættes som en del af en SQL query.

Læg mærke til ordet "direkte". Variabler du selv laver er ikke beskyttet, og variabler som kommer andre steder fra er heller ikke beskyttet. Sammensætter du derefter variabler, som kommer fra brugeren, med andre variabler, resulterer det i en tekststreng, hvor noget af den er beskyttet. Samtidigt betyder det at variablerne fra brugeren kun er beregnet til SQL, og quotesne skal derfor fjernes, hvis de skal bruges andre steder. Min anbefaling: lav en htaccess-fil og slå Magic Quotes fra. Det er noget værre rod.

I kodeeksemplerne går jeg ud fra at Magic Quotes er slået fra. $db refererer til er en databaseforbindelse via PDO ( http://php.net/pdo ), $user og $pass er informationer indtastet af brugeren.

Først en query, som er åben for angreb:

<?php
$stmt = $db->query("SELECT * FROM users WHERE user = '$user' AND pass = '$pass'");
?>

Denne kan hurtigt sikres:

<?php
$sql_clean_user = $db->quote($user);
$sql_clean_pass = $db->quote($pass);
$stmt = $db->query("SELECT * FROM users WHERE user = $sql_clean_user AND pass = $sql_clean_pass");
?>

Den kan dog sikres på en langt bedre måde:

<?php
$stmt = $db->prepare("SELECT * FROM users WHERE user = :user AND pass = :pass");
$stmt->execute(
array(
':user' => $user,
':pass' => $pass
)
);
?>

Hvorfor er den sidste metode bedre? Fordi den helt undgår problemstillingen omkring SQL injections. Her skrives hele SQL-queryen som en enkelt string, der ikke sammensættes af flere variabler, og man undgår herved at variablerne sammensættes på en usikker måde.

Variablerne som bruges i arrayen skal ikke være sikrede, da databasen selv sørger for dette.

PS. Eksemplerne forudsætter brug af PDO, og kræver derfor en nyere udgave af PHP



Som Jonas siger, er SQL injection en form for angreb, hvor du ved at give specielt input til et script, kan for uventede ting til at ske.

Dog vil jeg påpege at der er en lille fejl i det Jonas har skrevet. Det vigtige ved SQL injection, er at man laver valide queries. Den query some Jonas har produceret, er ikke helt valid. Lad os tage Jonas' eksempel:

Fold kodeboks ind/udKode 


Hvis vi brugte SQL injectionen her:

Fold kodeboks ind/udKode 


Så ville vi ikke få et gyldigt resultat, da querien ville blive til:

Fold kodeboks ind/udKode 


Som du kan se, er dette ikke gyldigt SQL, da der mangler nogle citationstegn, for at det bliver gyldigt. Hvis vi istedet bruger denne SQL injection:

Fold kodeboks ind/udKode 


Så ville vi få følgende SQL sætning:

Fold kodeboks ind/udKode 


Som du kan se, så tester vi nu om og username password er lig med '' eller at '1' er lig '1'. Da 1 altid er 1, så vil denne SQL injection validere, og vi ville derfor blive logget ind.

Det er altså meget forskellet om hvordan et request skal udformes, hvis man vil ind. Men den bedste måde at teste om systemet er sårbart, er simpelthen at fylde et citationstegn ind i et felt, og derefter skrive alt muligt junk(Eller ingenting) ind i alle andre felter. Så vil SQL sætningen fejle, hvis systemet er sårbart.



Jeg kan godt se hvorfor mit er forkert, men ikke desto mindre har jeg fået netop det til at virke på en hjemmeside...



Det kommer an på hvilken SQL server der ligger bag ved, det var mest for at gøre opmærksom på at det ikke altid er ligegyldigt, hvordan sætningen ser ud.



Aah, okay.
Jeg vidste godt det var noget omkring sikkerhed, men det var dejligt lige at få det på plads. :)

Jonas, hvilke sikkerheds funktioner er det du tænker på?

Og, hvis jeg nu laver mit eget loginsystem som bare tjekker brugernavn og password med en mysql database, er der så nogle specielle ting jeg skal huske eller tage højde for?



Kan faktisk ikke huske hvor mange man skal slå fra. Men magic_quotes_gpc er vist den vigtigste.



Hmm, okay.
Det må jeg kigge på når jeg kommer igang.

Tak. :)



Indlæg senest redigeret d. 04.02.2007 21:35 af Bruger #10850
t