web-dev-qa-db-fra.com

Quels caractères sont réellement capables de provoquer une injection SQL dans mysql

Nous savons tous que nous devons utiliser des instructions préparées ou les règles de remplacement/formatage appropriées afin d'empêcher l'injection SQL dans nos applications.

Cependant, en jetant un œil à la liste des littéraux de caractères de MySQL, j'ai remarqué qu'elle comprend les caractères suivants:

  • \0 An ASCII NUL (0x00) personnage.
  • \' Une seule citation (') personnage.
  • \" Une double citation (") personnage.
  • \b Un caractère de retour arrière.
  • \n Un caractère de nouvelle ligne (saut de ligne).
  • \r Un caractère de retour chariot.
  • \t Un caractère de tabulation.
  • \Z ASCII 26 (Ctrl+Z). Voir note suivant le tableau.
  • \\ Une barre oblique inversée (\) personnage.
  • \% UNE % personnage.
  • \_ UNE _ personnage.

Maintenant, tandis que le % et _ les caractères doivent être échappés afin d'empêcher l'injection de caractères génériques indésirables dans les instructions LIKE, et tandis que ' (simple citation), \ (barre oblique inverse) et " (guillemet double) tous doivent être échappés afin d'empêcher l'injection de SQL arbitraire - un de ces autres caractères pourrait-il échapper directement à une vulnérabilité d'injection SQL qui ne serait pas présente autrement? Quelqu'un a-t-il des exemples réels d'un tel exploit?

Supposons que nous construisons notre requête comme:

SELECT * FROM users WHERE username='$user'

Y a-t-il une valeur pour $user où les seuls littéraux de caractères non échappés sont \b (retour arrière), \0 (NUL), \n (nouvelle ligne), \r (saut de ligne), \t (onglet) ou \Z (Ctrl+Z) qui permet l'injection de SQL arbitraire dans cette requête?

22
schizodactyl

Considérant les lignes ci-dessous du manuel mysql_real_escape_string () :

MySQL requiert uniquement que la barre oblique inverse et le caractère de guillemet utilisé pour citer la chaîne dans la requête soient échappés. mysql_real_escape_string () cite les autres caractères pour les rendre plus faciles à lire dans les fichiers journaux.

L'injection SQL dans MySQL ne devrait pas être possible avec ces caractères spéciaux seuls: \b\0\n\r\t\Z.

Cependant, le manuel String Literals indique ce qui suit, mais les raisons spécifiées (ou non) ne se rapportent pas à l'injection SQL:

Si vous souhaitez insérer des données binaires dans une colonne de chaîne (telle qu'une colonne BLOB ), vous devez représenter certains caractères par des séquences d'échappement. La barre oblique inverse ("\") et le caractère de guillemet utilisé pour citer la chaîne doivent être échappés. Dans certains environnements client, il peut également être nécessaire d'échapper à NUL ou Control + Z. Le client mysql tronque les chaînes entre guillemets contenant des caractères NUL si elles ne sont pas échappées, et Control + Z peut être utilisé pour END-OF-FILE sur Windows s'il n'est pas échappé.

De plus, dans un test simple, quelle que soit la météo, les caractères spéciaux listés ci-dessus sont échappés ou non, MySQL a donné les mêmes résultats. En d'autres termes, MySQL ne se souciait même pas:

$query_sql = "SELECT * FROM `user` WHERE user = '$user'";

La requête ci-dessus a fonctionné de manière similaire pour les versions non échappées et échappées des caractères répertoriés ci-dessus, comme indiqué ci-dessous:

$user = chr(8);     // Back Space
$user = chr(0);     // Null char
$user = chr(13);    // Carriage Return
$user = chr(9);     // Horizontal Tab
$user = chr(26);    // Substitute
$user = chr(92) .chr(8);    // Escaped Back Space
$user = chr(92) .chr(0);    // Escaped Null char
$user = chr(92) .chr(13);   // Escaped Carriage Return
$user = chr(92) .chr(9);    // Escaped Horizontal Tab
$user = chr(92) .chr(26);   // Escaped Substitute

Tableau de test et données utilisées dans le test simple:

-- Table Structure

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(10) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

-- Table Data

INSERT INTO `user` ( `user` ) VALUES
( char( '8' ) ),
( char( '0' ) ),
( char( '10' ) ),
( char( '13' ) ),
( char( '9' ) ),
( char( '26' ) );
6
Uours

Il n'y a pas de tels personnages.

Il y a deux fausses déclarations dans votre question qui vous amènent à confondre:

  1. Nous savons tous que nous devons utiliser ... les règles de remplacement appropriées afin d'empêcher l'injection sql dans nos applications.

C'est une fausse déclaration. Pas de remplacement mais formatage . C'est une chose essentielle. Les remplacements ne protègent pas contre les injections, contrairement au formatage. Notez que chaque partie distincte de la requête nécessite une mise en forme différente qui est inutile pour toute autre partie. Disons, il y a un autre personnage, essentiel pour la protection contre les injections - un backtick (`). Mais vous ne l'avez pas répertorié car cela n'a rien à voir avec les littéraux de chaîne.

  1. les '(guillemet simple),\(barre oblique inverse) et "(guillemet double) doivent tous être échappés afin d'empêcher l'injection

C'est une déclaration terriblement erronée. Les échappements n'empêchent pas les injections! Ces caractères doivent être échappés pour formater les chaînes et n'a absolument rien à voir avec les injections. Bien qu'il soit vrai qu'une partie de requête correctement formatée est invulnérable contre l'injection. Mais la vérité est - vous devez formater des parties de requête dynamiques juste pour le plaisir, pour suivre les règles de syntaxe - pas à cause des injections. Et vous aurez votre requête impénétrable juste en conséquence.

Maintenant, vous pouvez voir pourquoi votre dernière déclaration,

pourquoi tous ces autres personnages sont suffisamment vulnérables pour être échappés via mysql_real_escape_string, car cela ne m'est pas immédiatement évident.

est mal écrit:
Ce sont les règles de formatage des chaînes qui nécessitent ces caractères, et non la "vulnérabilité". Certains d'entre eux sont échappés juste pour des raisons de commodité, certains pour plus de lisibilité, certains pour des raisons évidentes d'échapper à un délimiteur. C'est tout.

Pour répondre aux questions récentes des commentaires:

Je veux vraiment une réponse à cela, car mysql_real_escape_string de PHP ne cite pas non plus ces littéraux.

Encore une fois: bien que dans l'esprit de la moyenne PHP user mysql_real_escape_string() est fortement connecté à toute injection d'effarouchement, en réalité, ce n'est pas le cas. Il y a aucun caractère "dangereux" jamais. Pas un seul. Il y a des caractères de service avec une signification spéciale. Ils doivent être échappés dans certaines circonstances, dépend du contexte.

Ainsi, il n'y a aucun lien entre les caractères échappés par cette fonction, et quel que soit le "danger". Dès que vous commencez à penser que le but de mysql_real_escape_string() est d'échapper aux personnages "dangereux", vous êtes en effet en danger. Tant que vous n'utilisez cette fonction que pour échapper aux chaînes (et le faites sans condition) - vous pouvez vous considérer en sécurité (bien sûr, si vous n'oubliez pas de formater tous les autres littéraux aussi, en utilisant leurs règles de formatage respectives)

Je veux savoir si le caractère "%" peut conduire à autre chose que des résultats supplémentaires dans une clause LIKE.

Non.

5
Your Common Sense