Je testais quelques requêtes et j'ai obtenu un résultat bizarre.
J'ai testé la requête suivante
Select 1 from Persons where 1=1='a';//returns nothing select 1 from Persons where 1=2='a';//returns 1
cela renvoie les crédits de l'administrateur (nom d'utilisateur et mot de passe) p>
Donc, si j'ai raison, password = username = 'a' est retourné true ..
mais comment?
alors J'ai testé plus de requêtes et j'ai obtenu le résultat suivant
SELECT * FROM Persons where username = 'admin' and password = username = 'a'
so true = 'a' is false and false = 'a' is true?
Merci ,
4 Réponses :
Probablement ceci:
0 = 0
renvoie false qui pour MySql est évalué comme 0 .
Puis ceci:
0 = 'a'
après MySql essaie implicitement de convertir 'a' en un nombre pour évaluer l'expression et parce que 'a' ne peut pas être converti en nombre, le résultat de la conversion est 0 .
Vous pouvez trouver tout ce que vous devez savoir sur les conversions implicites ici: 12.3 Conversion de type dans l'évaluation des expressions .
Donc:
password = username
renvoie true.
Mysql convertit les variables dans le type de variable de gauche.
Ainsi, l'expression password = username = 'a' peut être exprimée comme ceci:
password = username // 0 (false)
0 = 'a' // 1 (true), car CAST ('a' AS INTEGER) = 0
Même chose pour 1 = 1 = 'a' code>:
1 = 1 // 1 (vrai)
1 = 'a' // 0 (false), car CAST ('a' AS INTEGER) = 0
Et pour 1 = 2 = 'a' :
1 = 2 // 0 (faux)
0 = 'a' // 1 ( true), car CAST ('a' AS INTEGER) = 0
Vous pouvez essayer la requête suivante pour vérifier ceci:
SELECT "string1" = "string2", 0 = "a", CAST('a' AS INTEGER);
tout d'abord, lorsque vous faites x = y = z , ce qui se passe réellement est (x = y) = z ce qui signifie que vous comparez password = username (false, pour chaque utilisation qui sait comment choisir un mot de passe fort ...) à 'a'.
Maintenant, le problème avec les booléens dans mySql est qu'ils sont représentés par tinyint - 1 est vrai , 0 est faux. vous pouvez le voir en exécutant select true - vous obtiendrez 1 comme résultat.
Cela fonctionne également avec des chaînes - '1' par rapport à booléen est vrai, toute autre chaîne est fausse, vous pouvez exécuter ces deux et voir que vous obtiendrez 1 comme résultat:
select true = 1; select true = '1'; select false = 0; select false = '0'; select false = 'any other string';
MySQL traite false comme 0 et true comme 1. Cela permet aux hacks spécifiques à MySQL comme
SELECT 1 = 1 = 1, (1 = 1) = 1
de faire des rapports légers de style pivot.
Cela ressemble à Le traitement par MySQL des clauses WHERE contenant plus d'un comparateur s'exécute de gauche à droite. Donc
SELECT 1 = 1
donne 1, tout comme ces deux expressions équivalentes.
SELECT COUNT(*), SUM(active = 1) active, SUM(active <> 1)inactive FROM tbl
Maintenant, 0 = 'a' renvoie 1 (vrai) à cause d'une autre bizarrerie MySQL qui contraint les chaînes à des entiers en interprétant les premiers chiffres de la chaîne comme un entier. Ainsi, 7 = '7a' vaut 1 (vrai) tout comme 0 = '0a' (et 0 = 'a' ). Mais 6 = '7a' est faux (0).
La morale de l'histoire? Pour un code clair, évitez les clauses WHERE avec plus d'un comparateur.
AVERTISSEMENT : Vous ne devez jamais stocker les mots de passe sous forme de texte brut.