Bienvenue sur PEBKAC.fr, le site qui recense les anecdotes où l’on se moque des utilisateurs ne maîtrisant pas l’outil informatique. PEBKAC est un acronyme signifiant « Problem Exists Between Keyboard And Chair ».
Le problème se situe entre la chaise et le clavier : soumettez vos histoires, donnez votre avis !
Ce site n'est pas le site original pebkac.fr. Je publie ici la liste des PEBKAC que j'ai pu sauvegarder avant que le site original ne soit mis hors ligne.
Je visite le site d'une entreprise qui vendait jadis de l'outillage automobile, et je tente une recherche pour voir s'ils ont toujours du stock. Il semblerait qu'ils en ont encore. En voyant le design très simple et fort peu soigné du site, je tente d'ajouter une apostrophe dans la barre de recherche… Et ça n'a pas raté :

SELECT COUNT(*) FROM <table> WHERE 1=1 AND ToolName LIKE '%test'%' db query failed.

En plus de ne pas échapper correctement les apostrophes, le « développeur » a jugé nécessaire de rajouter WHERE 1=1 dans la requête. Double PEBKAC.
PEBKAC #9212 proposé par ILoveSQL le 07/01/2014 | 21 commentaires | 👍🏽 👎🏽 +151
Pour sa défense, le WHERE 1=1 peut être acceptable. Je prends le code suivant :

1: $sql = 'SELECT * FROM matable';
 2: $sql .= 'WHERE 1=1 ';
 3: $sql .= 'AND champ1 = val1 ';
 4: $sql .= 'AND champ2 = val2 ';
 5: $sql .= 'AND champ3 = val3'; 
 6: $sql .= 'AND champ4 = val4'; 


Je me rend compte que la condition champ1 = val1 est inutile. Je mets donc la ligne 3 en commentaire, et tout marche bien. Si cette ligne avait commencé par un WHERE, la requête aurait été mal formée, et là, c'est le drame.

Il peut aussi s'agir d'une requête crée par une boucle :

1: $sql = 'SELECT * FROM matable';
 2: $sql .= 'WHERE 1=1 ';
 3: for($i=0;$i<$foo;$i++){
 4:   $sql .= 'AND '.$_GET['champ_'.$i].' = '.$_GET['value_'.$i].' ';
 5: }; 


Et dans ce cas là mettre une première condition WHERE évite de devoir faire un truc du genre

1: $sql = 'SELECT * FROM matable';
 2: for($i=0;$i<$foo;$i++){
 3:   if($i == 0)
 4:     $sql .= 'WHERE '.$_GET['champ_'.$i].' = '.$_GET['value_'.$i].' ';
 5:   else
 6:     $sql .= 'AND '.$_GET['champ_'.$i].' = '.$_GET['value_'.$i].' ';
 7: }; 


Dans ce cas là, la lisibilité est légèrement réduite.

Conclusion : même si c'est à priori bizarre, le WHERE 1=1 ne me dérange pas plus que ça.

edit : j'ai gagné la médaille du commentaire le plus long ?
Commentaire #124477 écrit par Link le 07/01/2014 à 08h39 | 👍🏽 👎🏽
Tout à fait d'accord avec Link, c'est très habituel de trouver cette condition dans les requêtes de type moteur de recherche interne, pour être certain d'avoir au moins une condition, ça évite de se demander s'il faut ajouter ou pas le where, et s'il faut un and ou pas.

Par contre, je plussoie le pebkac sur la protection contre les injections SQL.
Commentaire #124479 écrit par CrazyCat le 07/01/2014 à 08h51 | 👍🏽 👎🏽
Hmmmm... Captain Obvious? Une petite explication SVP?
Commentaire #124481 écrit par Moot le 07/01/2014 à 09h10 | 👍🏽 👎🏽
Perso, je suis plus adepte de faire une liste de critères, et de mettre un truc du genre "WHERE ". implode(' AND ', $criteres) dans le cas ou cette liste n'est pas vide ;)
[Note : la syntaxe n'est peut être pas exacte, je ne fais pas souvent de PHP, mais c'est l'idée]
Commentaire #124484 écrit par Anonyme le 07/01/2014 à 09h15 | 👍🏽 👎🏽
Injection SQL, qui permet donc à "n'importe qui" d'exécuter n'importe quelle requête, sans vérification.
Commentaire #124485 écrit par Captain le 07/01/2014 à 09h16 | 👍🏽 👎🏽
C'est ce que l'on appelle l'injection SQL.

Une requête SQL basique dans une base de données est de la forme : SELECT nom_du_champ FROM nom_de_la_table WHERE nom_de_l_attribute = 'xxxxx'. xxxxx étant ce que l'utilisateur entre dans la barre de recherche. Le WHERE indique les conditions à vérifier pour que la requête aboutisse.

Donc si personne ne vérifie ce que l'utilisateur entre, il peut fort bien écrire dans le champ : quelque chose' OR 'x'='x, donc la requête deviendra : SELECT nom_du_champ FROM nom_de_la_table WHERE nom_de_l_attribute = 'quelque chose' OR 'x'='x'.
Ce qui rendra la requête toujours vraie, et renverra donc tout le contenu de la table (du moins tous les nom_du_champ).

Et si vous ne voyez pas le problème, imaginez que la requête porte sur un compte utilisateur, vérifiant un mot de passe (hashé et salé). Une injection SQL vous permet de récupérer toutes les infos de n'importe quel utilisateur, puisque vous modifiez la requête en l'empêchant de vérifier le mot de passe. Et c'est encore gentil, on peut exécuter n'importe quoi (tant qu'on a les droits).

La moralité de l'histoire est un précepte bien connu des dévelopeurs : never trust user input.
Commentaire #124489 écrit par mini le 07/01/2014 à 09h21 | 👍🏽 👎🏽
'toto'; DROP DATABASE;
Commentaire #124490 écrit par Shadam le 07/01/2014 à 09h40 | 👍🏽 👎🏽
Ha oui on en avait déjà parlé sur PEBKAC il y a longtemps!
Merci bien usurpateur de Captain Obvious (décidément toujours à la bourre celui là) et mini.
Commentaire #124492 écrit par Moot le 07/01/2014 à 09h46 | 👍🏽 👎🏽
S'il fallait faire un pebkac à chaque fois qu'on rencontre une injection SQL ... Quant au WHERE 1=1, CTLP (voir l'explication de Link commentaire 1)
Commentaire #124504 écrit par n0p le 07/01/2014 à 10h30 | 👍🏽 👎🏽
http://xkcd.com/327/
Commentaire #124506 écrit par Acné le 07/01/2014 à 10h35 | 👍🏽 👎🏽
@Acné : l'une de mes préférées ^^
Commentaire #124509 écrit par mini le 07/01/2014 à 10h51 | 👍🏽 👎🏽
Ne vous laissez pas berner ! Le vrai moi porte une cape !
Commentaire #124514 écrit par Captain Obvious le 07/01/2014 à 11h57 | 👍🏽 👎🏽
Désolé, je ne retrouvais plus ma cape ! Je l'avais prêtée à un ami qui faisait réveillon déguisé.
Commentaire #124515 écrit par Captain Obvious le 07/01/2014 à 11h58 | 👍🏽 👎🏽
Tout à fait d'accord, cependant je préfère le WHERE 1 qui est largement suffisant.
Commentaire #124535 écrit par aDev le 07/01/2014 à 13h02 | 👍🏽 👎🏽
Le fait que la requête soit affichée en cas d'erreur ajoute encore au PEBKAC.

Que l'on fasse cela en développement, pourquoi pas, mais là c'est vraiment donner le bâton pour se faire battre.
Commentaire #124537 écrit par aDev le 07/01/2014 à 13h09 | 👍🏽 👎🏽
N'oublions pas qu'il inplode et d'autre fonction pour faire ce genre de choses.
Sinon on peut aussi l'écrire
1: $sql = 'SELECT * FROM matable where ';
 2: for($i=0;$i<$foo;$i++){
 3:     $sql .= $_GET['champ_'.$i].' = '.$_GET['value_'.$i].($i<$foo -1 ? ' AND ':';');
 4: }; 


Ou un truc du genre.
1: $sql = 'SELECT * FROM matable where ';
 2: for($i=0;$i<$foo;$i++){
 3:     $sql .= $_GET['champ_'.$i].' = '.$_GET['value_'.$i]
 4:     if ($i<$foo -1) 
 5:             $sql.= ' AND ';
 6: }; 
Commentaire #124567 écrit par but2ene le 07/01/2014 à 14h59 | 👍🏽 👎🏽
Mais comment tu veux déboguer l'injection SQL, si la requête exécutée n'est pas affichée ? :D
Commentaire #124571 écrit par Anonyme le 07/01/2014 à 15h55 | 👍🏽 👎🏽
Je préfère ma solution de gestion du WHERE/AND ;)

De plus si $foo = 0 ta requête devient invalide.
Commentaire #124575 écrit par Link le 07/01/2014 à 16h21 | 👍🏽 👎🏽
Pas de soucis ;) Mais les répétitions c'est mal m'voyez.
1: $sql = 'SELECT * FROM matable where ';
 2: for($i=0;$i<$foo;$i++)
 3:     $sql .= ($i==0 ? ' WHERE ':' AND ').$_GET['champ_'.$i].' = '.$_GET['value_'.$i]; 


1: $sql = 'SELECT * FROM matable';
 2: for($i=0;$i<$foo;$i++){
 3:     if ($foo==0) 
 5:             $sql.= ' WHERE ';
 6:     else 
 7:             $sql.= ' AND ';
 8:     $sql .= $_GET['champ_'.$i].' = '.$_GET['value_'.$i]
 9: };


En passant dans le peckcak, il n'y a pas l'air d'avoir beaucoup de champs.
Commentaire #124583 écrit par but2ene le 07/01/2014 à 17h44 | 👍🏽 👎🏽
Le plus navrant étant les 5/6 exemples de ce qui ne faut surtout pas faire qui suivent ensuite, et qui ratent totalement le problème d'injection. Ca n'est pas comme si PHP supportait le binding de paramètre...
Commentaire #124628 écrit par Foobared le 08/01/2014 à 07h33 | 👍🏽 👎🏽
Ah oui j'avais oublié, les logs c'est pour les chiens ;-)
Commentaire #124688 écrit par aDev le 08/01/2014 à 12h57 | 👍🏽 👎🏽