-
Security (2)
-
Linux-Security (10)
-
Firewalls (3)
-
Cryptography (2)
-
Firewalls (3)
- Windows-Security (2)
-
Cryptology (1)
-
Programmierung (1)
-
PHP (2)
-
PHP (2)
-
Linux-Security (10)
-
Be-paranoid.net (-2)
- Viren & Würmer (2)
- Hints (1)
- Buchtipps (1)
- Offtopic (7)
- Programmieren (5)
- Honeypots (1)
- Linux Security (2)
- Cryptology (1)
- Datenschutz (3)
- Viren & Würmer (2)
Hexblog
SEppl's Blog
Rabenhorst
The Daily WTF
Otrn Blog
Userfriendly
Schneier on Security
Planet SELinux & News
Heise
SecurityFocus
Open4Free Blog
xkcd
|_|_|0|
|0|0|0|
Be-Paranoid.net
SQL-Injection
Orginal Version | Artikel editieren | Versionen anzeigen | Bottom
Letzte Änderung: 31.03.2008, 20:07
Inhaltsverzeichnis
- Einführung
- Angriffsmöglichkeiten von SQL-Injections
- Szenarien
- Gegenmaßnahmen
- Abfrageklasse
- mod_security
- Weblinks
Einführung Top
In letzter Zeit häufen sich die Meldungen über SQL-Injection Lücken in bekannte OpenSource Projekten. Viele Entwickler sind sich überhaupt nicht bewusst, dass die Strings, die sie dem SQL Query übergeben nicht unbedingt sicher sein müssen. Dieses Tutorial behandelt SQL-Injection in MySQL Datenbanken.
In MySQL-Queries werden oft irgendwelche Variablen (meistens Integer) übergeben, die entweder per URL, oder POST-Formular, oder GET-Formular übergeben werden. Diese Variablen können, wenn sie nicht ordentlich überprüft werden den query manipulieren.
Natürlich braucht man Kenntnisse über die Datenbank, damit man einen erfolgreichen SQL-Injection Angriff überhaupt durchführen kann, aber "security by obscurity" ist nicht die Technik die ich bevorzuge.
Angriffsmöglichkeiten von SQL-Injections Top
Hier sind einige Beispiele, was ein Angreifer durch SQL-Injection erreichen könnte:
- Zugriff auf Daten, für die keine Berechtigung vorhanden ist
Beispiel: Der Angreifer setzt die Spalte für die Rechte auf den entsprechenden Wert, und kommentiert den Rest aus.
- Veränderung von Daten in der Datenbank
Beispiel: Der Angreifer verändert eine INSERT/UPDATE Abfrage so, das sie andere Daten manipuliert.
- Root Status
Beispiel: Der Angreifer verändert das Passwort vom Benutzer root.
- Einrichten einer Shell auf dem Datenbankserver
Der Angreifer führt eine Datei aus, die dem Angreifer remote Zugriff auf das System gewährt.
Das sind natürlich nur ein paar Beispiele, der Kreativität ist praktisch keine Grenze gesetzt...
Szenarien Top
Hier sind einige Beispiele, die die unzureichende Überprüfung der Input-Variablen erläutern, und dem Angreifer Vorteile bringen:
- Beschreibung: Der MySQL-Query gibt den Text eines Artikels aus, wenn der Benutzer die entsprechenden Rechte hat.
Bugs: Das Script überprüft die Variablen überhaupt nicht, und macht keine Anführungszeichen in den Abfragen.
Code:
$test = $_GET['test'];
//Der Benutzer ist in diesem Fall 2
$UserID = 2;
$Query = "SELECT
artikel_text
FROM
artikel
LEFT OUTER JOIN
user ON(user_id = '$UserID')
WHERE
artikel_id = $test AND
user_group = 3";
echo('Mysql Query:
').$Query.'
';
$test = mysql_fetch_array($Query);
echo($test['artikel_text']);
Normalerweise wird die Seite mit http://url.xyz/index.php?test=1 aufgerufen, und ein Benutzer, der nicht in der Benutzergruppe '3' ist bekommt keinen Text geliefert.
Bei http://url.xyz/index.php?test=1 AND user_group = 1/* schaut die Sache schon anders aus, hier wird folgendes ausgegeben:
query:
SELECT artikel_text FROM artikel LEFT OUTER JOIN user ON(user_id = '$UserID') WHERE artikel_id = 1 AND user_group = 1/* AND user_group = 3"
Das bewirkt, das alles nach dem /* Kommentar weg ist, und die user_group auf 1 gesetzt wird, der Artikel wird ausgegeben. Der Angriff war erfolgreich.
- Beschreibung: MySQL gibt einen Text, und den Titel aus.
Bugs: Das Script überprüft die Variablen überhaupt nicht, und macht keine Anführungszeichen in den Abfragen.
Code:
$test = $_GET['test'];
//Der Benutzer ist in diesem Fall 2
$UserID = 2;
$Query = "SELECT
artikel_text, artikle_title
FROM
artikel
WHERE
artikel_id = $test;
echo('Mysql Query:
').$Query.'
';
$test = mysql_fetch_array($Query);
echo('Text: '.$test['artikel_text'].' Title:'.$test['artikel_title']);
Wenn jetzt http://url.xyz/index.php?test=1 aufgerufen wird, wird der Artikel ganz normal ausgegeben, http://url.xyz/index.php?test=1 UNION SELECT user_password, user_username FROM user WHERE user_id = 1/* gibt uns aber das Passwort, und den usernamen aus.
Gegenmaßnahmen Top
Die wichtigste Verteidigung gegen Mysql-Injections ist das überprüfen der Eingangsvariablen. Des weiteren können Strings, die nicht escaped sind, wie im letzten Kapitel gezeigt, Probleme bereiten. Hier sind einige Maßnahmen gegen Mysql Injection aufgelistet:
- Anführungsstriche verwenden
Anführungsstriche werden dazu verwendet um Variablen in SQL-Queries zu benutzen.
Beispiel:Code:
SELECT z FROM xyz WHERE id = '$Test'
Ein Angreifer, der $Test verändert kann nicht aus den Anführungsstrichen ausbrechen, mit der Voraussetzung das $Test so geparst wurde, dass alle ' mit \' maskiert sind. Man sollte sich allerdings nicht zu stark darauf verlassen, diese Methode ist nur ein Teil von den Massnahmen die getroffen werden sollten.
- Keine Strings in numerischen Variablen zulassen
Die Funktion settype wandelt Variablen in einen Integer um:
Code:
settype($Variable, 'Integer');
Mit der Funktion is_numeric kann man überprüfen ob eine Variable Zeichen enthält:
Code:
if(is_numeric($Variable)) die('Fehler, falsche Eingangvariable');
Wobei is_numeric nicht immer 100% sicher ist.
- Stellen Sie nur Datenbankverbindungen mit eingeschränkten Rechten her
- Eingangvariablen maskieren
Die folgende Funktion maskiert die Eingangsvariable, wenn sie kein Integer ist:
Code:
function quotesqlvar($value)
{
// Stripslashes if quoted
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
// Quote if not Integer
if (!is_numeric($value)) {
$value = "'" .mysql_real_escape_string($value) . "'";
}
return $value;
}
Abfrageklasse Top
Da das sicherste Mitel gegen SQL-Injections Typkontrolle ist, basteln wir uns eine Klasse (Idee stammt von Hanse), die eine strenge Typenkontrolle macht:
Datei sec.inc:
Code:
<?php
class Sec
{
function MakeMysqlSecure($Variable, $Type, $Min = 0, $Max = 10000)
{
switch($Type)
{
case 'int':
settype($Variable, 'Integer');
if($Variable < $Min || $Variable > $Max)
$Variable = 0;
break;
case 'string':
$Variable = mysql_real_escape_string($Variable);
break;
case 'float':
settype($Variable, 'float');
if($Variable < $Min || $Variable > $Max)
$Variable = 0;
break;
case 'bool':
settype($Variable, 'boolean');
break;
default:
return 0;
}
return $Variable;
}
function MakeMysqlArraySecure($Variable, $Type, $Min = 0, $Max = 10000)
{
foreach ($Variable as $key => $value)
$Variable[$key] = Sec::MakeMysqlSecure($value ,$Type, $Min, $Max);
return $Variable;
}
function Get($Variable, $GetType = 'Get', $Type = 'int', $Min = 0, $Max = 100000)
{
switch($GetType)
{
case 'Post':
$Variable = $_POST[$Variable];
break;
case 'Get':
$Variable = $_GET[$Variable];
break;
default:
return 0;
}
$Variable = Sec::MakeMysqlSecure($Variable, $Type, $Min, $Max);
return $Variable;
}
}
?>
Eine einfache, zentrale Struktur führt oft zu einer besseren Sicherheit, hier sehen wir wie einfach die Klasse angewendet werden kann:
Code:
$ArticleID = Sec::Get('articleid');
$Page = Sec::Get('page');
$Blubbfish = Sec::Get('name','Post','string');
$Test = 'sdfdsf1234';
Sec::MakeMysqlSecure($Test, 'int', 16, 100);
weiteres Beispiel:
Code:
$secure = new Sec();
$text1 = $secure->Get('text1','Post','string');
$text2 = $secure->Get('text2','Post','string');
Die Klasse ist natürlich noch nicht perfekt, und kann beliebig ausgebaut werden.
mod_security Top
Als zusätzliche Massnahme gegen SQL-Injection kann ModSecurity als Erweiterung für den Apache verwendet werden. Unter anderem werden MySQL Anweisungen aus dem Link gefiltert.
Weblinks Top
Ich meine es ist keine sogute Idee des hier so ungeschützt zu lassen da kann ja jeder Hanz Kunz i-was hinschreiben !!!
Orginal Version | Artikel editieren | Versionen anzeigen | Top
Letzte Änderung: 31.03.2008, 20:07