JeuWeb - Crée ton jeu par navigateur
La sécurité & les bonnes pratiques - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : La sécurité & les bonnes pratiques (/showthread.php?tid=7389)

Pages : 1 2 3


RE: La sécurité & les bonnes pratiques - Sôbi - 25-03-2016

J'ai un peu de mal à saisir le "filter_input".

Si je prends le cas de Akira777, c'est à dire cette url : index.php?page=equipement&action=supprimer&id=5

Il faudrait donc faire :
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_SPECIAL_CHARS);
$action = filter_input(INPUT_GET, 'action', FILTER_SANITIZE_SPECIAL_CHARS);
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);

Cela permettra de récupérer déjà des réponses correctes et cohérentes, c'est bien ca ?
Cela veut donc dire que si on met du "javascript" ou du code "html" dans un champs genre <strong>
Le "filter_input" fait le trie dans tout cela ?

et pour ce qui est de : htmlspecialchars ?


RE: La sécurité & les bonnes pratiques - L'Omniscient - 25-03-2016

Mais pour onmouseover="alert('et Boum');" il faut ouvrir une balise, si strip_tag efface la balise, ça ne fonctionnera pas non ?

(Xenos, je n'ai pas de $_GET, que des $_POST, presque tous en traitement Ajax).

Et les injections SQL, ça fonctionne uniquement via des balises PHP ?

Et quant tu dis que la machine ne sait pas que $id est un 'paramètre', tu entends quoi par là ?
J'ai des commandes comme ça moi :
prepare('UPDATE table SET tot = "'.$soustrait.'" WHERE ID = "'.$ID.'" AND obj = "'.$ressource.'"')
Sachant que $ID correspond à $SESSION_ID et que $soustrait et $ressource sont en strip_tag juste avant l'insertion en SQL.

Ca me stresse ces histoires de sécurité >,...,<

EDIT : Autre question, peut-on modifier des tableaux JSON via le code source ?
J'ai essayé, j'arrive bien à modifier la donner dans mon code source, mais la modification ne fonctionne pas... (Si on peut vraiment pas modifier, j'en suis heureux Big Grin)
En fait j'ai même l'impression de pas pouvoir modifier le Javascript Oo Par exemple je peux appeler mon ID en alert, mais je peux pas modifier la valeur de l'ID


RE: La sécurité & les bonnes pratiques - Akira777 - 25-03-2016

Hey!


Si ton tableau JSON est écrit via du PHP pour être utilisé par du javascript c'est très simple pour que la modification soit prise en compte.

Exemple :
Code :
<script>
// L'intérieur du tableau est généré en PHP
var data = {
    id: 1,
    isAdmin: false
};

$('form').on('submit', function(e) {
    e.preventDefault();

    $.ajax({
       url: 'http://...',
       type: 'POST',
       data: {
           id: data.id,
           isAdmin: data.isAdmin
           name: $('form input.name').val()
       }
    });

    return false;
});
</script>

Dans ce cas, le tableau, qu'il soit généré par du PHP ou rendu par un GET en AJAX peut être modifié via la console de ton navigateur.
Non pas en modifiant la source, mais en utilisant la console.

Ici, je modifie "data.isAdmin" en tapant dans ma console "data.isAdmin = true". Cela sera pris en compte à la soumission du formulaire d'exemple (exemple moisi je concède).


RE: La sécurité & les bonnes pratiques - L'Omniscient - 25-03-2016

Salut Akira, oui en prenant Google Chrome j'ai réussi à facilement modifier ! ^^
Je m'en doutais de toute façon, ces prochains jours je m'attèle à la sécurité anti-triche ! ^_^


RE: La sécurité & les bonnes pratiques - Xenos - 25-03-2016

Attention à ne pas confondre deux choses:
• Valider la donnée d'entrée (GET, POST etc) pour que son "typage" soit correct; ie: je veux un nombre qui sera un id donc je sanitize ou filtre l'entrée pour être sûr d'avoir un entier)
• Encoder la donnée pour l'insérer à un endroit donné (JSON, HTML, XML); ie: je veux afficher le pseudo du joueur dans un strong, donc je fais un echo "<strong>" . htmlentities($user->name, 'utf-8') . "</strong>"

Dans l'exemple de Sôbi, FILTER_SANITIZE_NUMBER_INT: pas de soucis, on veut effectivement un entier car l'id est un entier par nature. Mais FILTER_SANITIZE_SPECIAL_CHARS, non car on veut en fait un texte (osef de ce qu'il y a dedans), donc cette entrée n'aura pas de FILTER_* particulier.

Dans un second temps, ces données sont surement utilisées ailleurs dans le code (dans un HTML, dans un JSON, dans une requête SQL, etc). A chacun de ces endroit-là correspondra un "encodage" de la donnée:
• "<strong>" . htmlentities($myData, 'utf-8') . "</strong>"
• json_encode($myData)
• prepare_query... execute_query($preparedQuery, array('myParam' => $myData))
• $domNode->appendChild(new DOMText($myData))

Il y a donc bien deux opérations à distinguer pour ne pas s'emmêler: le filtrage des entrées, qui sert à s'assurer de l'existence et de la nature de ce que le serveur reçoit, et "l'encodage des sorties", qui sert à s'assurer qu'une donnée est insérée/utilisée correctement dans une chaine de caractères (HTML) ou autre.

C'est pour cette raison qu'il existe finalement très peu de FILTER_*: il n'y a pas de FILTER_JSON par exemple, car en pratique, la donnée d'entrée doit être une texte (FILTER_UNSAFE_RAW me semble-t-il) et l'échappement json se fait dans la sortie du serveur (echo json_encode(...)).


Si je reprends:
Code :
prepare('UPDATE table SET tot = "'.$soustrait.'" WHERE ID = "'.$ID.'" AND obj = "'.$ressource.'"')

Alors tu rates la partie "encodage", car ton $soustrait, ton $ID, ton $ressources sont balancés directement par concaténation dans ta requête. L'encodage se ferait par un
Code :
$prepared = prepate('UPDATE table SET tot = ? WHERE ID = ? AND obj = ?)
execute($prepared, array($soustrait, $ID, $ressource)
ou
Code :
query('UPDATE table SET tot = "'.sql_escape($soustrait).'" WHERE ID = "'.sql_escape($ID).'" AND obj = "'.sql_escape($ressource).'"')
Mais il n'existe pas tellement de "sql_escape()" donc je te le déconseille.


Alors, oui, si tu te dis "mais $ID est un entier: je l'ai filtré en le récupérant du $_POST[] donc c'est pas grave?", alors tu as raison, car "sql_escape({INT}) == {INT}" (ie: un entier ne change pas quand il est échappé). Mais cela vient juste de ça! Supposons que, pour une raison quelconque, le SQL n'accepte les entiers qu'en hexadécimal, alors "sql_escape({INT}) != {INT}" (ie: 100 deviendra 0x64). Donc, même s $ID est un entier "et qu'on peut donc le mettre là dans la requête sans problème", je te le déconseille: traite-le comme une donnée quelconque à échapper, osef que le résultat de cet échappement" soit le même.

Cela te simplifiera éééénormément le raisonnement car tu ne chercheras pas à savoir ce qu'une variable contient pour savoir s'il faut ou non l'échapper: tu échappes tout, et dans tes variables, tu stockes toujours des données réelles (non-échappées, mais éventuellement filtrées).



Tout ce qui est sorti du serveur peut avoir été modifié: JSON, HTML, COOKIES, etc.

Et n'oublie pas que rien n'oblige l'utilisateur à être passé par ton interface: tu peux très bien créer ta propre interface faisant n'importe quelle requête.


RE: La sécurité & les bonnes pratiques - L'Omniscient - 25-03-2016

Merci Xenos pour ces explications.
Je vais les relire attentivement car moi et les termes ça fait 1000 Big Grin

En tous cas je vais tout exécuter comme tu me l'a montré dans ton deuxième exemple ^_^

Par contre, il n'y a aucun moyen d'empêcher un utilisateur de modifier un tableau JSON utilisé par du Javascript ?


RE: La sécurité & les bonnes pratiques - Akira777 - 25-03-2016

Re,

Non, comme le dit Xenos, tout ce que tu envois à l'utilisateur peut être modifié.
D'où le principe simple : NEVER TRUST USER INPUT.

Ne te fie pas non plus aux cookies, aux requêtes AJAX, aux formulaires et même à ton javascript.


RE: La sécurité & les bonnes pratiques - Ter Rowan - 29-03-2016

qui plus est vérifier qu'un id est un entier n'apporte rien côté sécurité. Faut penser à vérifier que l'id est le bon id (si c'est l'id d'un objet, vérifier que le personnage possède l'objet, si c'est l'id du joueur vérifier que ce n'est pas un autre joueur qui utilise l'id d'un autre, etc...)

y a des tests fonctionnels importants à vérifier. L'aspect "tester l'injection sql" est limite le plus basique (obligatoire, je ne dis pas, mais "ridicule" dans l'aspect contrôle anti triche)


RE: La sécurité & les bonnes pratiques - niahoo - 29-03-2016

Bah justement, pour pouvoir vérifier qu'un utilisateur possède bien un objet ayant tel id, il faut aller faire une requête en base. Et donc vérifier que ce que tu envoies à la base est correct. Donc vérifier que ton id est bien un integer – ou laisser l'ORM s'en charger – puis vérifier la propriété de l'objet. Ce sont deux étapes différentes.


RE: La sécurité & les bonnes pratiques - Ter Rowan - 29-03-2016

(29-03-2016, 12:11 PM)niahoo a écrit : Bah justement, pour pouvoir vérifier qu'un utilisateur possède bien un objet ayant tel id, il faut aller faire une requête en base. Et donc vérifier que ce que tu envoies à la base est correct. Donc vérifier que ton id est bien un integer – ou laisser l'ORM s'en charger – puis vérifier la propriété de l'objet. Ce sont deux étapes différentes.

je ne dis pas le contraire, mais la discussion tourne uniquement autour du typage, à la limite qu'est ce qui est le plus important que "BABA" ne soit pas un entier, ou que "BABA" ne soit pas la clef qui permet de s'assurer que la demande est autorisée. C'est pas parce qu'on a vérifié le type qu'on n'a fini le boulot, on le commence juste.

d'ailleurs en allant même plus loin, si je compare une chaine à un entier (non nul) attendu y a toutes les chances que le système me dise que la chaine n'est pas ce que j'attends et que donc la requête / action doit être refusée