21-04-2014, 11:29 PM
Les entrées utilisateurs
A coup de "if"
Utilise les cast.
Et vérifie la validité des valeurs de façon exhaustive
La POO
La POO est souvent plus légère dans ce cas-là, puisqu'elle te permettra d'écrire des trucs du genre:
Exceptions
Préfère l'utilisation des Exceptions.
Ou POO (le message de l'exception est caché dans la classe de l'exception):
Injection
Coté sécurité, ceci est mal venu:
Si mon login est le suivant:
Alors la query devient:
Et je récupère les graines de celui ou celle qui a le plus de crystal. Evidemment, on aurait pu faire bien pire, en utilisant le login:
Et là, adieu ta BDD...
Solution:
Soit utiliser des requêtes préparées, soit valider proprement chaque donnée avant de l'insérer dans la requête SQL, via un escape string comme tu l'as fait ailleurs.
Simplifier ses requêtes
Pense à simplifier les requêtes SQL, ou à défaut, à les regrouper.
Regroupé:
Faire N requêtes "INSERT" est assez long: préfère la syntaxe de INSERT permettant d'insérer plusieurs données d'un coup.
Encore mieux:
Location:
Double toujours tes "location:" par un lien, au cas où le navigateur ne suive pas.
Injection cliente
L'injection ne se fait pas que dans la BDD: elle se fait aussi chez le visiteur.
Considère que tout ce que ton serveur émet doit être valide.
Ici, supposons que j'envoie le lien suivant:
Alors ce code:
Va émettre ceci au visiteur:
Si jamais j'envoyais ce lien à une victime, et qu'au lieu d'un "alert()" j'utilisais autre chose pour m'envoyer la valeur de "document.cookie", alors je pourrai connaitre le cookie de ma victime, et accéder à son compte.
Mysql_* est déprécié
Utilise, à la place, mysqli ou PDO.
Note finale: il est tard, je suis creuvé, y'a peut-être une ou deux conneries dans ce post, que les autres corrigent si besoin
$nombre = isset( $_POST['nombre'] ) ? mysql_real_escape_string($_POST['nombre']) : 0;
$variete = isset( $_POST['variete'] ) ? mysql_real_escape_string($_POST['variete']) : null;
A coup de "if"
Utilise les cast.
Et vérifie la validité des valeurs de façon exhaustive
define('_INDEX_POST_NOMBRE', 'nombre');
define('_INDEX_POST_VARIETE', 'variete');
if (
isset($_POST[_INDEX_POST_NOMBRE])
and isset($_POST[_INDEX_POST_VARIETE])
and ($nombre = (int)($_POST[_INDEX_POST_NOMBRE])) >= _NOMBRE_VALEUR_MIN
and $nombre <= _NOMBRE_VALEUR_MAX
and ($variete = (string)($_POST[_INDEX_POST_VARIETE])) >= _VARIETE_VALEUR_MIN
and $variete >= _VARIETE_VALEUR_MAX)
{
//...
}
La POO
La POO est souvent plus légère dans ce cas-là, puisqu'elle te permettra d'écrire des trucs du genre:
$data = new DataContainer();
$data->add( new DataNombre( new LoadFromPOST('nombre') ) );
$data->add( new DataVariete( new LoadFromPOST('variete') ) );
if ($data->isEverythingOkay())
{
//...
}
Et tous les contrôles de valeurs fileront dans les objets: les contrôles pour s'assurer que tel ou tel truc (données $_POST par exemple) sont définies et valides seront masqués.Exceptions
if($variete==null){
$message = 'Vous devez choisir une variété';
Préfère l'utilisation des Exceptions.
try
{
if($variete==null)
throw new Exception('Vous devez choisir une variété');
//...
}
catch (Exception $e)
{
var_dump($e);
}
Ou POO (le message de l'exception est caché dans la classe de l'exception):
try
{
if($variete==null)
throw new Exception\VarieteNonChoisie();
//...
}
catch (Exception $e)
{
var_dump($e);
}
Injection
Coté sécurité, ceci est mal venu:
$sql = 'SELECT graines_crystal, graines_skunk, graines_shiva, graines_haze FROM tbl_infos_membres WHERE login="'.$_SESSION['login'].'"';
Si mon login est le suivant:
Code :
" OR 1=1 ORDER BY `graines_crystal` DESC; --
Alors la query devient:
SELECT graines_crystal, graines_skunk, graines_shiva, graines_haze FROM tbl_infos_membres WHERE login="" OR 1=1 ORDER BY `graines_crystal` DESC; --"
Et je récupère les graines de celui ou celle qui a le plus de crystal. Evidemment, on aurait pu faire bien pire, en utilisant le login:
"; DROP DATABASE `nom_de_BDD`; --
Et là, adieu ta BDD...
Solution:
Soit utiliser des requêtes préparées, soit valider proprement chaque donnée avant de l'insérer dans la requête SQL, via un escape string comme tu l'as fait ailleurs.
$rq = mysql_query($sql) or die('Erreur SQL !'.$sql.''.mysql_error());
A "or die", je préfère l'utilisation d'un "if (mysql_error()) throw new Exception(...)". Le "or die" est assez pesant, et te donne très peu de contrôle sur comment rattraper une erreur.Simplifier ses requêtes
Pense à simplifier les requêtes SQL, ou à défaut, à les regrouper.
while ($nb <= $nb_desired)
{
$sql1 = 'INSERT INTO niveau1 VALUES ("", "'.mysql_escape_string($_SESSION['login']).'", "'.mysql_escape_string($variete).'", "0", "5")';
mysql_query ($sql1) or die ('Erreur SQL !'.$sql1.''.mysql_error());
$message = 'Vous avez enregistré la variété. ';
$nb++;
}
Regroupé:
$message = 'Vous avez enregistré la variété. ';
$inserts = array();
while ($nb <= $nb_desired)
{
$inserts[] = '("", "'.mysql_escape_string($_SESSION['login']).'", "'.mysql_escape_string($variete).'", "0", "5")';
$nb++;
}
$sql1 = 'INSERT INTO niveau1 VALUES '.implode(',', $inserts);
mysql_query ($sql1) or die ('Erreur SQL !'.$sql1.''.mysql_error());
Faire N requêtes "INSERT" est assez long: préfère la syntaxe de INSERT permettant d'insérer plusieurs données d'un coup.
Encore mieux:
$message = 'Vous avez enregistré la variété. ';
$inserts = array_fill(0, $nb_desired, '(DEFAULT, "'.mysql_escape_string($_SESSION['login']).'", "'.mysql_escape_string($variete).'", 0, 5)';
$sql1 = 'INSERT INTO niveau1 VALUES '.implode(',', $inserts);
mysql_query($sql1)
if (mysql_error())
throw new Exception('Erreur SQL !'.$sql1.''.mysql_error());
Location:
Double toujours tes "location:" par un lien, au cas où le navigateur ne suive pas.
header ('Location: index.php?nav=niveau1');
echo('<a href="index.php?nav=niveau1">Niveau 1</a>');
Aussi, attention aux "index.php?nav=..." car ils sont parfois sensibles à l'injection. Ils sont aussi assez moche dans la barre d'URL, mais c'est secondaire.Injection cliente
L'injection ne se fait pas que dans la BDD: elle se fait aussi chez le visiteur.
Considère que tout ce que ton serveur émet doit être valide.
Ici, supposons que j'envoie le lien suivant:
Code :
index.php?message=<script>alert(document.cookie);</script>
Alors ce code:
$message = isset($_GET['message']) ? $_GET['message'] : null;
echo $message;
Va émettre ceci au visiteur:
<script>alert(document.cookie);</script>
Si jamais j'envoyais ce lien à une victime, et qu'au lieu d'un "alert()" j'utilisais autre chose pour m'envoyer la valeur de "document.cookie", alors je pourrai connaitre le cookie de ma victime, et accéder à son compte.
Mysql_* est déprécié
Utilise, à la place, mysqli ou PDO.
Note finale: il est tard, je suis creuvé, y'a peut-être une ou deux conneries dans ce post, que les autres corrigent si besoin