Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Reichen mysql_real_escape_string() und mysql_escape_string() für die App-Sicherheit aus?

@Charles ist absolut richtig!

Sie setzen sich einem Risiko für mehrere Arten von bekannten aus SQL-Angriffe, einschließlich, wie Sie erwähnt haben,

  • SQL-Injection:Ja! Mysql_Escape_String hält Sie wahrscheinlich NOCH anfällig für SQL-Injektionen, je nachdem, wo Sie PHP-Variablen in Ihren Abfragen verwenden.

Bedenken Sie Folgendes:

$sql = "SELECT number FROM PhoneNumbers " .
       "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);  

Kann man dem so sicher und genau entgehen? NEIN! Wieso den? denn ein Hacker könnte das immer noch tun:

Wiederholen Sie nach mir:

mysql_real_escape_string() soll nur variable Daten maskieren, NICHT Tabellennamen, Spaltennamen und insbesondere keine LIMIT-Felder.

  • LIKE-Exploits:LIKE "$data%", wobei $data "%" sein könnte, was ALLE Datensätze zurückgeben würde ... was sehr gut sein kann ein Sicherheits-Exploit ... stellen Sie sich einfach eine Suche nach den letzten vier Ziffern einer Kreditkarte vor ... OOPs! Jetzt können die Hacker potenziell jede Kreditkartennummer in Ihrem System erhalten! (Übrigens:Das Aufbewahren vollständiger Kreditkarten wird kaum empfohlen!)

  • Charset Exploits:Egal was die Hasser sagen, Internet Explorer ist immer noch , im Jahr 2011, anfällig für Zeichensatz-Exploits, und das ist wenn Sie haben Ihre HTML-Seite korrekt gestaltet, mit dem Äquivalent von <meta name="charset" value="UTF-8"/> ! Diese Angriffe sind SEHR böse, da sie dem Hacker genauso viel Kontrolle geben wie direkte SQL-Injektionen:z. voll.

Hier ist ein Beispielcode, um all dies zu demonstrieren:

// Contains class DBConfig; database information.
require_once('../.dbcreds');                       

$dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass);
mysql_select_db(DBConfig::$db);
//print_r($argv);

$sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE '%s%%' LIMIT %s",
               mysql_real_escape_string($argv[1]),
               mysql_real_escape_string($argv[2]),
               mysql_real_escape_string($argv[3]));
echo "SQL: $sql\n";
$qq = mysql_query($sql);
while (($data = mysql_fetch_array($qq)))
{
        print_r($data);
}

Hier sind die Ergebnisse dieses Codes, wenn verschiedene Eingaben übergeben werden:

$ php sql_exploits.php url http://www.reddit.com id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://www.reddit.com%'
               ORDER BY id;
Returns: Just URLs beginning w/ "http://www.reddit.com"

$ php sql_exploits.php url % id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE '%%' 
               ORDER BY id;
Results: Returns every result Not what you programmed, ergo an exploit --

$ php sql_exploits.php 1=1'http://www.reddit.com ' id Ergebnisse:Gibt jede Spalte und jedes Ergebnis zurück.

Dann gibt es noch die WIRKLICH fiesen LIMIT-Exploits:

$ php sql_exploits.php url 
> 'http://www.reddit.com'
> "UNION SELECT name FROM CachedDomains"
Generated SQL: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://reddit.com%' 
               LIMIT 1 
               UNION
               SELECT name FROM CachedDomains;
Returns:  An entirely unexpected, potentially (probably) unauthorized query
          from another, completely different table. 

Ob Sie das SQL in den Angriffen verstehen oder nicht, ist unerheblich. Dies hat gezeigt, dass mysql_real_escape_string() einfach ist selbst von den unreifsten Hackern umgangen werden. Das liegt daran, dass es sich um einen REAKTIVEN Abwehrmechanismus handelt. Es behebt nur sehr begrenzte und BEKANNTE Exploits in der Datenbank.

Jegliches Escaping wird NIEMALS ausreichen, um Datenbanken zu sichern. Tatsächlich können Sie auf jeden BEKANNTEN Exploit explizit REAGIEREN, und in Zukunft wird Ihr Code höchstwahrscheinlich anfällig für Angriffe, die in der Zukunft entdeckt werden.

Die richtige und einzige (wirklich) Verteidigung ist eine PROAKTIVE:Verwenden Sie vorbereitete Anweisungen. Vorbereitete Anweisungen werden mit besonderer Sorgfalt entworfen, damit NUR gültiges und PROGRAMMIERTES SQL ausgeführt wird. Das bedeutet, dass bei richtiger Ausführung die Wahrscheinlichkeit, dass unerwartetes SQL ausgeführt werden kann, drastisch reduziert wird.

Theoretisch wären vorbereitete Anweisungen, die perfekt implementiert sind, für ALLE bekannten und unbekannten Angriffe unempfindlich, da es sich um eine SERVERSEITIGE Technik handelt, die von den DATENBANKSERVERN SELBST und den Bibliotheken, die mit der Programmiersprache verbunden sind, gehandhabt wird. Daher sind Sie IMMER garantiert gegen JEDES BEKANNTE HACK geschützt, zumindest zumindest.

Und es ist weniger Code:

$pdo = new PDO($dsn);

$column = 'url';
$value = 'http://www.stackoverflow.com/';
$limit = 1;

$validColumns = array('url', 'last_fetched');

// Make sure to validate whether $column is a valid search parameter.
// Default to 'id' if it's an invalid column.
if (!in_array($column, $validColumns) { $column = 'id'; }


$statement = $pdo->prepare('SELECT url FROM GrabbedURLs ' .
                           'WHERE ' . $column . '=? ' .
                           'LIMIT ' . intval($limit));
$statement->execute(array($value));
while (($data = $statement->fetch())) { }

Das war jetzt nicht so schwer, oder? Und es sind siebenundvierzig Prozent weniger Code (195 Zeichen (PDO) gegenüber 375 Zeichen (mysql_). Das nenne ich "voller Gewinn".

BEARBEITEN:Um all die Kontroversen anzusprechen, die diese Antwort ausgelöst hat, erlauben Sie mir, zu wiederholen, was ich bereits gesagt habe:

Durch die Verwendung vorbereiteter Anweisungen können Sie sich die Schutzmaßnahmen des SQL-Servers selbst zunutze machen, und daher sind Sie vor Dingen geschützt, über die die SQL-Server-Leute Bescheid wissen. Aufgrund dieser zusätzlichen Schutzebene sind Sie weitaus sicherer, als wenn Sie einfach die Escape-Funktion verwenden, egal wie gründlich.