99 votes

Dois-je me protéger contre l'injection SQL si j'utilise une liste déroulante ?

Je sais qu'il ne faut JAMAIS faire confiance aux données saisies par l'utilisateur dans un formulaire, principalement en raison du risque d'injection SQL.

Toutefois, cela s'applique-t-il également à un formulaire où la seule entrée est effectuée à partir d'une ou de plusieurs listes déroulantes (voir ci-dessous) ?

Je garde le $_POST['size'] à une session qui est ensuite utilisée dans l'ensemble du site pour interroger les différentes bases de données (avec un code d'accès à la base de données). mysqli Select query) et toute injection SQL leur porterait définitivement préjudice (voire les ferait tomber).

Il n'y a pas de zone de saisie pour interroger les bases de données, seulement des listes déroulantes.

<form action="welcome.php" method="post">
<select name="size">
  <option value="All">Select Size</option> 
  <option value="Large">Large</option>
  <option value="Medium">Medium</option>
  <option value="Small">Small</option>
</select>
<input type="submit">
</form>

113 votes

Oui. Rien n'empêche un attaquant de soumettre toutes les valeurs qu'il souhaite dans votre fichier <select> entrée. En effet, même un utilisateur un peu technique pourrait ajouter des options supplémentaires à l'aide de la console du navigateur. Si vous conservez une liste blanche des valeurs disponibles et que vous comparez les données saisies à cette liste, vous pouvez atténuer ce problème (et vous devriez le faire, car cela permet d'éviter les valeurs indésirables).

0 votes

Bummer.... si je devais lier dynamiquement des paramètres dans une déclaration préparée avec MySQLi, cela protégerait-il mes fichiers ?

13 votes

Vous devez comprendre les principes de base des requêtes et des réponses, et savoir que la façon dont le frontal est construit sur la requête n'a pas d'importance, c'est-à-dire que dans le cas présent, la liste déroulante doit être utilisée.

196voto

doppelgreener Points 2857

Oui, vous devez vous protéger contre cela.

Laissez-moi vous montrer pourquoi, en utilisant la console du développeur de Firefox :

i've edited one of the values in the dropdown to be a drop table statement

Si vous ne nettoyez pas ces données, votre base de données sera détruite. (Il se peut que ce ne soit pas une déclaration SQL totalement valide, mais j'espère avoir fait passer mon message).

Ce n'est pas parce que vous avez limité les options disponibles dans votre liste déroulante ne signifie pas vous avez limité les données que je peux envoyer à votre serveur.

Si vous avez essayé de restreindre davantage ce comportement sur votre page, je peux désactiver ce comportement ou simplement écrire une requête HTTP personnalisée sur votre serveur qui imite la soumission du formulaire. Il existe un outil appelé bouclette utilisé exactement pour ça, et je pensez à la commande pour soumettre cette injection SQL de toute façon ressemblerait à quelque chose comme ça :

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(Il se peut que ce ne soit pas une commande curl totalement valide, mais encore une fois, j'espère avoir fait passer mon message).

Donc, je vais réitérer :

Ne faites JAMAIS confiance à la saisie de l'utilisateur. Protégez-vous TOUJOURS.

Ne supposez pas qu'une entrée utilisateur est toujours sûre. Elle est potentiellement dangereuse même si elle arrive par un moyen autre qu'un formulaire. Aucune de ces données n'est suffisamment fiable pour ne pas se protéger contre l'injection SQL.

24 votes

Sans parler de la création d'une charge utile personnalisée avec curl . TOUJOURS désinfecter l'entrée côté serveur !

14 votes

Une image en dit plus que mille mots.

4 votes

Cela devrait être la réponse par défaut. Il faudrait aussi inclure quelque chose sur curl . Les gens ne comprennent pas que l'on peut envoyer une requête HTTP de n'importe où à n'importe quel endroit en utilisant n'importe quel format et en passant n'importe quelles valeurs, c'est au serveur de s'assurer que la requête est valide avant de la traiter.

69voto

OliverBS Points 1334

Vous pouvez faire quelque chose d'aussi simple que l'exemple suivant pour vous assurer que la taille affichée correspond à vos attentes.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

Utilisez ensuite mysqli_* si vous utilisez une version de php >= 5.3.0, ce qui devrait être le cas, pour enregistrer votre résultat. Si vous l'utilisez correctement, cela vous aidera à lutter contre l'injection sql.

0 votes

Est-ce une version abrégée d'une "liste blanche" OliverBS ?

0 votes

Pas vraiment, juste une version très basique de celui-ci, vous pourriez ajouter les valeurs dans une base de données à vérifier pour le rendre plus facile et réutilisable. ou peut-être faire une classe de liste blanche avec une méthode spécifique pour chaque liste blanche à vérifier. si vous ne voulez pas utiliser une base de données, les propriétés de la liste blanche pourraient être à l'intérieur d'une propriété de tableau dans votre classe de liste blanche.

9 votes

Néanmoins, vous devez utiliser Prepared Statements (recommandé) ou mysqli_real_escape_string . De plus, les valeurs sont correctement échappées lors de leur sortie (par exemple, utilisez la commande htmlspecialchars() dans un document HTML).

45voto

Cette question a été étiquetée avec injection sql voici une réponse concernant ce type particulier d'attaque :

Comme on vous l'a dit dans les commentaires, vous devez utiliser des déclarations préparées pour chaque requête unique impliquant des données variables, avec aucune exception .

Indépendamment de tout ce qui concerne le HTML !
Il est essentiel de comprendre que les requêtes SQL doivent être formatées correctement. indépendamment de de tout facteur externe, qu'il s'agisse d'une entrée HTML ou autre.

Bien que vous puissiez utiliser la liste blanche suggérée dans d'autres réponses pour la validation des entrées, cela ne devrait pas affecter les actions liées à SQL - ils doivent rester les mêmes, peu importe si vous avez validé l'entrée HTML ou non. Cela signifie que vous devez toujours utiliser des instructions préparées lorsque vous ajoutez des variables dans la requête.

Vous trouverez ici une explication détaillée des raisons pour lesquelles les déclarations préparées sont indispensables et comment les utiliser correctement, ainsi que des cas où elles ne sont pas applicables et ce qu'il faut faire dans ce cas : Le guide du routard de la protection contre les injections SQL

Cette question a également été étiquetée avec mysqli . La plupart du temps par accident, je présume, mais de toute façon, je dois vous avertir que mysqli brut n'est pas une substitution adéquate pour les anciennes fonctions mysq_*. . Tout simplement parce que si elle est utilisée dans l'ancien style, elle n'ajoutera aucune sécurité. Le support des déclarations préparées est douloureux et gênant, au point que l'utilisateur moyen de PHP est incapable de les utiliser. Ainsi, si aucun ORM ou une sorte de bibliothèque d'abstraction n'est en option, alors AOP est votre seul choix.

5 votes

I = random(0, 15) ; //quelque requête utilisant i. Ai-je encore besoin d'une déclaration préparée ici ?

1 votes

Avez-vous une défense pour ça ?

2 votes

Quelle est l'implémentation de random ?

12voto

rm-vanda Points 1754

Oui.

N'importe qui peut usurper n'importe quoi pour les valeurs qui sont réellement envoyées --

Ainsi, pour valider les menus déroulants, vous pouvez simplement vérifier que la valeur avec laquelle vous travaillez se trouve dans le menu déroulant - quelque chose comme ça serait la meilleure façon (la plus sainement paranoïaque) :

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}

5 votes

Cette réponse est incomplète, en outre, vous devriez utiliser des déclarations préparées, de sorte que l'injection n'est pas possible indépendamment de ce que la valeur est fixée à

7 votes

@Slicedpan Vraiment ? On dirait que tu sautes dans le train en marche sans savoir pourquoi... Si j'ai une poignée d'entrées possibles dans une requête, de telle sorte que je puisse vérifier qu'elles sont toutes correctes (ce que je sais, car je les ai faites), alors vous ne gagnez rien de plus. sécurité avantages de l'utilisation d'une déclaration préparée

3 votes

Sauf que le fait d'imposer l'utilisation d'instructions préparées comme convention vous protège de l'introduction de vulnérabilités d'injection SQL à l'avenir.

8voto

Styphon Points 2494

Une façon de se protéger contre les utilisateurs qui modifient vos listes déroulantes à l'aide de la console est de n'utiliser que des valeurs entières dans celles-ci. Vous pouvez alors valider que la valeur POST contient un nombre entier, et utiliser un tableau pour le convertir en texte si nécessaire. Par exemple

<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '<select name="size">';
foreach($sizes as $i => $s) {
    echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';

Vous pouvez alors utiliser $size dans votre requête en sachant qu'elle ne contiendra jamais que FALSE ou un nombre entier.

2 votes

@OliverBS Qu'est-ce que filter_input si ce n'est pas une vérification du côté du serveur ? Personne ne peut afficher autre chose qu'un nombre entier.

0 votes

Merci Styphon, cela remplace donc le formulaire dans l'OP ? Est-ce que cela peut s'appliquer à des formulaires plus grands avec plusieurs listes déroulantes ? Si j'y ajoutais une autre liste déroulante, par exemple pour la "couleur" ?

0 votes

@SamuelTattersfield Oui et oui. Vous pouvez l'utiliser pour autant de dropdowns que vous le souhaitez, avec autant d'options que vous le souhaitez. Il suffit de créer un nouveau tableau pour chaque liste déroulante et de placer toutes les options de la liste déroulante dans le tableau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X