Mysql
 sql >> Base de données >  >> RDS >> Mysql

mysql_real_escape_string() et mysql_escape_string() sont-ils suffisants pour la sécurité de l'application ?

@Charles a parfaitement raison !

Vous vous exposez à plusieurs types de connus Les attaques SQL, y compris, comme vous l'avez mentionné

  • Injection SQL :oui ! Mysql_Escape_String vous garde probablement ENCORE sensible aux injections SQL, selon l'endroit où vous utilisez les variables PHP dans vos requêtes.

Considérez ceci :

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

Cela peut-il être échappé de manière sûre et précise de cette façon ? NON! Pourquoi? car un hacker pourrait très bien encore faire ça :

Répétez après moi :

mysql_real_escape_string() est uniquement destiné à échapper aux données variables, PAS les noms de table, les noms de colonne, et surtout pas les champs LIMIT.

  • LIKE exploite :LIKE "$data%" où $data pourrait être "%" qui renverrait TOUS les enregistrements ... ce qui peut très bien être un exploit de sécurité... imaginez une recherche par les quatre derniers chiffres d'une carte de crédit... OOPs ! Désormais, les pirates peuvent potentiellement recevoir tous les numéros de carte de crédit de votre système ! (BTW :stocker des cartes de crédit complètes n'est presque jamais recommandé !)

  • Charset Exploits :Peu importe ce que disent les ennemis, Internet Explorer est toujours , en 2011, vulnérable aux exploits de jeux de caractères, et c'est si vous avez correctement conçu votre page HTML, avec l'équivalent de <meta name="charset" value="UTF-8"/> ! Ces attaques sont TRÈS désagréables car elles donnent au pirate autant de contrôle que les injections SQL directes :par ex. plein.

Voici un exemple de code pour illustrer tout cela :

// 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);
}

Voici les résultats de ce code lorsque plusieurs entrées sont transmises :

$ 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 Results :Renvoie chaque colonne et chaque résultat.

Ensuite, il y a les VRAIMENT méchants exploits LIMIT :

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

Que vous compreniez ou non le SQL dans les attaques n'est pas pertinent. Ce que cela a démontré, c'est que mysql_real_escape_string() est facilement contourné même par les pirates les plus immatures. C'est parce qu'il s'agit d'un mécanisme de défense RÉACTIF. Il ne corrige que des exploits très limités et CONNUS dans la base de données.

Toutes les fuites ne seront JAMAIS suffisantes pour sécuriser les bases de données. En fait, vous pouvez RÉAGIR explicitement à chaque exploit CONNU et à l'avenir, votre code deviendra très probablement vulnérable aux attaques découvertes à l'avenir.

La bonne, et la seule (vraiment) défense est une défense PROACTIVE :utilisez des déclarations préparées. Les instructions préparées sont conçues avec un soin particulier afin que SEUL le SQL valide et PROGRAMMÉ soit exécuté. Cela signifie que, lorsque cela est fait correctement, les chances que du SQL inattendu puisse être exécuté sont considérablement réduites.

Théoriquement, les instructions préparées parfaitement implémentées seraient insensibles à TOUTES les attaques, connues et inconnues, car il s'agit d'une technique CÔTÉ SERVEUR, gérée par les SERVEURS DE BASE DE DONNÉES EUX-MÊMES et les bibliothèques qui s'interfacent avec le langage de programmation. Par conséquent, vous êtes TOUJOURS assuré d'être protégé contre TOUS LES HACKS CONNUS, au strict minimum.

Et c'est moins de 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())) { }

Ce n'était pas si difficile, n'est-ce pas ? Et c'est 47 % de code en moins (195 caractères (PDO) contre 375 caractères (mysql_). C'est ce que j'appelle "full of win".

EDIT :Pour répondre à toute la controverse suscitée par cette réponse, permettez-moi de réitérer ce que j'ai déjà dit :

L'utilisation d'instructions préparées permet d'exploiter les mesures de protection du serveur SQL lui-même et, par conséquent, vous êtes protégé contre les éléments dont les utilisateurs du serveur SQL sont au courant. En raison de ce niveau de protection supplémentaire, vous êtes beaucoup plus en sécurité qu'en utilisant simplement une évasion, aussi minutieuse soit-elle.