Alternative à mysql_real_escape_string sans se connecter à DB

91

J'aimerais avoir une fonction se comportant comme mysql_real_escape_string sans me connecter à la base de données car parfois je dois faire des tests à sec sans connexion à la base de données. mysql_escape_string est obsolète et n'est donc pas souhaitable. Certaines de mes découvertes:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064

Viet
la source
1
+1 J'écris moi-même la classe MySQL et j'utilise mysql_real_escape_string () à des fins de liaison de paramètres. J'évite d'utiliser mysqli car tous les hébergeurs ne le prennent pas en charge. J'évite également les bibliothèques multi-fichiers et multi-classes. Ce dont j'ai besoin, c'est juste une classe unique soignée et propre. Je vous remercie!
Viet
+1 pour moi aussi. Mon cas d'utilisation est un APi SugarCRM où je dois pousser des fragments de SQL vers l'instance SugarCRM distante via l'API. Aussi méchant que cela soit, c'est ce avec quoi je dois travailler (allez frapper quelques têtes de développeurs SugarCRM ensemble). J'ai besoin d'échapper aux chaînes en SQL dans l'application qui utilise l'API et qui est totalement distincte de la base de données derrière l'instance SugarCRM.
Jason

Réponses:

75

Il est impossible d'échapper en toute sécurité à une chaîne sans connexion DB. mysql_real_escape_string()et les instructions préparées nécessitent une connexion à la base de données afin de pouvoir échapper à la chaîne en utilisant le jeu de caractères approprié - sinon, les attaques par injection SQL sont toujours possibles en utilisant des caractères multi-octets.

Si vous ne faites que tester , vous pouvez aussi bien l'utiliser mysql_escape_string(), ce n'est pas garanti à 100% contre les attaques par injection SQL, mais il est impossible de créer quelque chose de plus sûr sans une connexion DB.

trop de php
la source
1
+1 Merci pour la note. Je ne sais pas trop comment tester contre les attaques par injection SQL utilisant des caractères multi-octets.
Viet
2
On m'a donné un vieux code à mettre à jour. Il utilise mysql_escape_stringsans connexion (essayant toujours de comprendre pourquoi). Puisque cette fonction est obsolète, je me demande simplement comment je peux la remplacer. Il semble certainement raisonnable que l'on puisse spécifier le "jeu de caractères approprié" dans n'importe quelle fonction qui le remplace sans ouvrir de connexion.
JohnK
3
Impossible? Qu'est-ce que mysql_real_escape_string obtient de la connexion à la base de données qui ne sont pas des données de configuration qui pourraient être transmises manuellement à une fonction équivalente? Edit: il suffit de lire ci-dessous, cela appelle une fonction de bibliothèque dans MySQL, il y a donc un traitement qui se produit en dehors de PHP. Il peut encore être portable, mais le maintenir à jour serait un projet en soi.
Jason
2
Que faire si le jeu de caractères DB est connu à l'avance?
jchook
7
Ouais si vous connaissez le jeu de caractères, qu'est-ce qui empêche de s'échapper sans connexion?
Johan
66

Eh bien, selon la page de référence de la fonction mysql_real_escape_string : "mysql_real_escape_string () appelle la fonction de bibliothèque de MySQL mysql_real_escape_string, qui échappe les caractères suivants: \ x00, \ n, \ r, \, '," et \ x1a. "

Dans cet esprit, la fonction donnée dans le deuxième lien que vous avez publié devrait faire exactement ce dont vous avez besoin:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}
zombat
la source
6
Merci. Je suggérerais autre chose: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet
1
pourquoi \ x1a est remplacé par \\\ x1a plutôt que \\ x1a? Est-ce une faute de frappe?
Michael Z
16
-1 C'est extrêmement dangereux. Si la connexion à la base de données utilise un jeu de caractères multi-octets, de simples remplacements octets comme celui-ci pourraient entraîner une corruption des données (y compris des caractères d'échappement / guillemets) - cela pourrait être délibérément exploité par un attaquant malveillant pour injecter du SQL arbitraire.
eggyal
Si vous vous trompez dans les jeux de caractères, cela peut être dangereux. Pour les jeux de caractères multi-octets, si mysql l'utilise, quelqu'un peut simplement mettre un octet pour annuler le \\. Les jeux de caractères multi-octets peuvent souvent prendre n'importe quoi comme deuxième octet, y compris \\ car mysql ne le verra pas comme un caractère autonome \\ mais faisant partie du caractère multi-octets. Je n'ai aucune idée de ce qui se passe avec UTF8. J'espère qu'avec [0xB0, '\\'] qu'en frappant un octet invalide \\ qui s'arrête et recommence avec cet octet plutôt que de l'avaler.
jgmjgm
1
Si je sais que le jeu de caractères est utf8, est-il sûr d'utiliser mb_strpos()(et mb_substr()de créer un comportement similaire à substr_replace()) pour faire cela?
SOFe
28

En opposition directe à mon autre réponse, cette fonction suivante est probablement sûre, même avec des caractères multi-octets.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

J'espère que quelqu'un de plus compétent que moi pourra me dire pourquoi le code ci-dessus ne fonctionnera pas ...

trop de php
la source
+1 Merci pour l'effort supplémentaire. Je vais en savoir plus sur les injections SQL liées à plusieurs octets.
Viet
Je suppose que ça devrait être $ return. = '\ X'. dechex ($ ord); à la place
Viet
1
En règle générale, je préfère utiliser '\\' même dans les chaînes entre guillemets, simplement parce qu'un seul '\' peut affecter le caractère suivant si vous ne faites pas attention. Je suis probablement de nouveau un trouble obsessionnel-compulsif.
trop de php
1
Cette fonction ne suit pas les règles d'échappement de mysql et entraînera une perte d'intégrité des données. "MySQL reconnaît les séquences d'échappement indiquées dans le Tableau 9.1," Séquences d'échappement de caractères spéciaux ". Pour toutes les autres séquences d'échappement, la barre oblique inverse est ignorée. Autrement dit, le caractère échappé est interprété comme s'il n'était pas échappé. Par exemple," \ x " est juste "x". " - dev.mysql.com/doc/refman/5.6/en/…
velcrow
2
Est-ce que \ xAA veut dire autre chose que le texte "xAA" dans une chaîne littérale MySQL? La documentation semble dire que \ x n'a pas de signification particulière, donc le \ sera ignoré. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason
6

De plus amples recherches, j'ai trouvé:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Correction de sécurité:

Une faille de sécurité d'injection SQL a été trouvée dans le traitement de codage multi-octets. Le bogue était dans le serveur, analysant incorrectement la chaîne échappée avec la fonction API C mysql_real_escape_string ().

Cette vulnérabilité a été découverte et signalée par Josh Berkus et Tom Lane dans le cadre de la collaboration de sécurité inter-projets du consortium OSDB. Pour plus d'informations sur l'injection SQL, veuillez consulter le texte suivant.

Discussion. Une faille de sécurité d'injection SQL a été trouvée dans le traitement de codage multi-octets. Une faille de sécurité d'injection SQL peut inclure une situation dans laquelle, lorsqu'un utilisateur a fourni des données à insérer dans une base de données, l'utilisateur peut injecter des instructions SQL dans les données que le serveur exécutera. En ce qui concerne cette vulnérabilité, lorsque l'échappement sans prise en compte du jeu de caractères est utilisé (par exemple, ajoute des barres obliques () en PHP), il est possible de contourner l'échappement dans certains jeux de caractères multi-octets (par exemple, SJIS, BIG5 et GBK). Par conséquent, une fonction telle que addlashes () ne peut pas empêcher les attaques par injection SQL. Il est impossible de résoudre ce problème côté serveur. La meilleure solution est pour les applications d'utiliser l'échappement sensible au jeu de caractères offert par une fonction telle que mysql_real_escape_string ().

Cependant, un bogue a été détecté dans la façon dont le serveur MySQL analyse la sortie de mysql_real_escape_string (). En conséquence, même lorsque la fonction de jeu de caractères mysql_real_escape_string () était utilisée, l'injection SQL était possible. Ce bug a été corrigé.

Solutions de contournement. Si vous ne parvenez pas à mettre à niveau MySQL vers une version qui inclut le correctif du bogue dans l'analyse mysql_real_escape_string (), mais que vous exécutez MySQL 5.0.1 ou supérieur, vous pouvez utiliser le mode SQL NO_BACKSLASH_ESCAPES comme solution de contournement. (Ce mode a été introduit dans MySQL 5.0.1.) NO_BACKSLASH_ESCAPES active un mode de compatibilité standard SQL, où la barre oblique inverse n'est pas considérée comme un caractère spécial. Le résultat sera que les requêtes échoueront.

Pour définir ce mode pour la connexion actuelle, entrez l'instruction SQL suivante:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Vous pouvez également définir le mode globalement pour tous les clients:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Ce mode SQL peut également être activé automatiquement lorsque le serveur démarre en utilisant l'option de ligne de commande --sql-mode = NO_BACKSLASH_ESCAPES ou en définissant sql-mode = NO_BACKSLASH_ESCAPES dans le fichier d'options du serveur (par exemple, my.cnf ou my.ini , selon votre système). (Bogue n ° 8378, CVE-2006-2753)

Voir aussi le bogue # 8303.

Viet
la source
1
Cela a été corrigé il y a longtemps.
Votre bon sens
2
Méfiez-vous également qui NO_BACKSLASH_ESCAPES introduit d'autres vulnérabilités .
eggyal
2
Corrigé dans 5.1.11 - Le lien était rompu, voici l'archive: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion