Gillar du den här guiden? Vill du att vi ska fortsätta göra fler guider? - läs mer här » 

skriv ut »

SQL injections och PHP säkerhet

När du använder PHP finns alltid en risk att dina script blir manipulerade. Målsättningen med den här guiden är att göra dig medveten om problemen och ge tips om var du kan hitta mer information. Vi visar även hur du kan skydda dig mot vanliga SQL injections i MySQL.

Vad är SQL injections?

SQL injections innebär att din MySQL-databas manipuleras genom att indata i MySQL-frågan ändras. Detta kan ske med flera olika metoder beroende på hur din kod är skriven. Ett vanligt fel är att inte använda någon form av indatakontroll av vad som skickas eller hämtas från MySQL-tabellerna. Genom att lägga till kod i frågesträngarna kan databasen manipuleras att visa skyddad information eller lägga till data i tabellerna. En en allvarligare typ av SQL injections är att kolumner eller hela tabellen raderas.

 

Exempel på SQL injection

Exemplet nedan visar hur en vanlig inloggning kan utnyttjas till en SQL injection. Formuläret nedan visar hur inloggningen sker med användarnamnet "lisa" och lösenordet "lisa1234" vilket är de riktiga användaruppgifter som finns i MySQL-tabellen:

Kodavsnittet som bearbetar informationen från formulärets POST-data lagrar dem i variablerna $anvandarID och $password:

<?php

$anvandarID = $_POST["anvandarID"];
$password = $_POST["losenord"];

$query = "SELECT username FROM usertable WHERE username = '$anvandarID' AND password = '$password'";

?>

...och informationen som skickas till MySQL-databasen ser ut så här:

SELECT username FROM usertable WHERE username = 'lisa' AND password = 'lisa1234'

MySQL-frågan i exemplet är öppen för att lägga till mer kod i frågesträngen. En vanlig SQL injection är att lägga till villkoret OR där två värden jämförs med varandra. Här är några exempel:

' OR '1'='1
' OR ''='
' OR 'hackat'='hackat

Pricipen är alltså att värdet i raden är tomt eller att siffran "1" är lika med "1" vilket ju alltid stämmer. Villkoret för WHERE i frågesträngen är alltså uppfyllt.

Vi behöver inte veta namnet på MySQL-tabellen eller någon av kolumnerna för att utföra den här typen av SQL injection. Vi använder formuläret för att lägga till villkoret OR både som användarnamn och lösenord i inloggningen:

...och informationen som skickas till MySQL-databasen ser ut så här:

SELECT username FROM usertable WHERE username = '' OR '1'='1' AND password = '' OR '1'='1'

Vi loggar in utan problem och har tillgång till de skyddade sidorna! Om användaruppgifter som ger behörighet på administratörs-nivå finns i tabellen kan vi nu gå vidare och utföra andra mer eller mindre skadliga åtgärder. SQL injectionen som används ovan fungerar bara mot MySQL-databaser men samma injection kan göras mot en SQL-databas med liknande frågesträngar.

OBS! Kodavsnittet till inloggningen i exemplet ovan är hämtad från guiden Login för flera användare » och är "anpassad" för att kunna manipuleras. Den kod som ingår i guiden använder hashing med SHA1 och kan inte manipuleras som i exemplet.

 

Förhindra MySQL injections

Det finns flera åtgärder för att skriva säkrare kod och förhindra de vanligaste typerna av SQL injections.

En metod är att använda funktionen preg_match (regular expressions, reguljära uttryck) för att kontrollera indata i frågesträngarna.
Läs mer om preg_match i guiden Formmail - skicka formulär till epost » .

En annan metod är att använda hashing i frågesträngarna och den metoden är vanlig vid inloggning där den skickade informationen inte behöver kunna reverseras.
Läs mer om hashing i guiden Login för flera användare »

En av de åtgärder som är mest effektiv är att använda funktionen addslashes som lägger till escape-tecknet backslash \ för att att inaktivera enkelfnuttar ( ' ) och dubbelfnuttar ( " ) innan frågan skickas till MySQL-databasen.
Läs mer om "addslashes" hos PHP.net »

Om du använder senare versioner än PHP 4.3.0 ska du (istället för addslashes) använda funktionen mysql_real_escape_string för att escapa specialtecknen i strängarna innan de skickas till MySQL-databasen. En förutsättning för att använda mysql_real_escape_string är att du är redan är ansluten till databasen med mysql_connect (läs mer i guiden PHP och MySQl » ).

OBS! Det här är den metod som rekommenderas. Använd alltid mysql_real_escape_string i frågesträngar till MySQL så har du ett bra skydd mot SQL injections!

Här är samma kodavsnitt men nu används mysql_real_escape_string i variablerna:

<?php

$anvandarID = mysql_real_escape_string($_POST["anvandarID"]);
$password = mysql_real_escape_string($_POST["losenord"]);

$query = "SELECT username FROM usertable WHERE username = '$anvandarID' AND password = '$password'";

?>

...och informationen som skickas till MySQL-databasen ser ut så här:

SELECT username FROM usertable WHERE username =
'\' OR \'1\'=\'1' AND password = '\' OR \'1\'=\'1'

Alla citationstecken, fnuttar och enkelfnuttar är escapade och inloggningen misslyckas.

Slutsats: Kör alltid indata genom funktionen mysql_real_escape_string innan de används i MySQL-frågan!

 

mer information om PHP säkerhet och SQL injections

Exemplet i den här guiden visar hur du kan skydda dig mot SQL-injections vid en inloggning där PHP och MySQL används. Det finns andra typer av intrång och säkerhetsrisker beroende på vilken databas och scriptspråk du använder.

Här är länkar till resurser där du kan läsa mer om säkerhet men även till tips om hur du kan utföra olika typer av "hack". Genom att du får kunskap om hur intrång kan genomföras så lär du dig också vilka risker som finns och hur du kan skydda din webplats och databaser.