C’est un message populaire. Èsska (S-K) 136 Posté(e) le 28 juin 2018 C’est un message populaire. Partager Posté(e) le 28 juin 2018 (modifié) Salut à tous. 1. Introduction Étant développeur web, on peut rencontrer plusieurs types de failles dans un CMS, qu'il sois vieux ou récent. Une faille en particulier a attiré mon attention dans le monde du développement web. En sachant que PHP regroupe les moins bons comme de très bons développeurs, il faut savoir que souvent, les amateurs oublient de gérer une faille qui reste extrêmement dangereuse dans certains cas. C'est pas pour autant que je vais aborder sur ce topic, plusieurs failles récurrentes dans un projet web amateur. N'oubliez pas le petit +1 si ça vous a plu. :3 2. Quelque failles A) Restrictions + Redirections Problématique: Malgré une restriction du rang sur certaines pages, comment être sûr que la redirection fonctionne et que la personne n'a pas accès à la page en question? Réponse: Vous pensez peut-être qu'en essayant de vous dérank et si vous essayez d'accéder à la page, que vous subissez une redirection, vous êtes protégés? [HIDE] Réponse réelle (Ce n'est pas la résolution du problème): Imaginons une fonction publique provenant d'une classe type: <?php public function restrict() { if(!$user->Logged()) { // Savoir si le joueur n'est pas connecté header('Location: index.php'); } } ?> Si vous n'utilisez pas de classes, c'est facilement adaptable. Le principe est que lorsqu'on veut restreindre une page par exemple à un utilisateur non connecté, on a tendance à utiliser un header();. Maintenant si on se déconnecte ce la page en question et que l'on veut accéder à la page, on est logiquement redirigé. Mais que se passe-t-il si on bypass le header(); ? Il existe par exemple sur Chrome une extension, permettant de bypass les headers: Le nom est "ModHeader". Voici un screen: Si jamais je coche le bouton à gauche de "Location" que j'ai au préalable ajouté dans "Response Headers", je vais pouvoir éviter les redirections des sites webs. Attention, ça ne bloque que les header('Location:'); Du coup j'imagine que vous avez une idée de la suite, on va activer cette application qui va nous permettre de vérifier si jamais on est pas redirigé, qu'est-ce qu'il se passe. Si jamais on essaie, on va tomber sur la page, sans redirection, et c'est plutôt problématique si jamais ça arrive dans des pages qui sont plutôt dite à risque comme dans l'administration par exemple. Ce qu'on va faire donc, c'est modifier notre fonction qui retourne qu'un header('Location'); par une fonction un peu plus poussée. <?php public function safeRedirect($url, $exit = true) { if (!headers_sent()){ header('HTTP/1.1 301 Moved Permanently'); header('Location: ' . $link); header("Connection: close"); } print "<html>"; print "<head><title>Redirection...</title>"; print "<meta http-equiv='Refresh' content='0;url='{$link}' />"; print "</head>"; print "<body onload='location.replace('{$link}')'>"; print "Vous rencontrez peut-être un problème.<br />"; print "<a href='{$link}'>Se faire rediriger</a><br />"; print "Si ceci est une erreur, merci de cliquer sur le lien.<br />"; print "</body>"; print "</html>"; if ($exit) exit; } ?> Le plus important dans ce code, c'est le "exit;" qui permet de bloquer les informations du site, et ne donne aucune suite. Ça reviendrait à faire un header('Location'); avec un exit; à la fin, mais cette fonction donne des infos supplémentaires à la personne qui est bloquée par la redirection. [/HIDE] B) Faille CSRF Problématique: Imaginons que nous sommes connecté à notre site. Et qu'une personne hasardeuse nous demande d'aller checker son site par exemple. Ça nous redirige vers un site plus que douteux, on clique quand même sur ce lien, et 15 minutes après, lorsqu'on souhaite accéder à notre site, il se trouve qu'une personne inconnue est gradée dans notre site, et y a fait n'importe-quoi. Réponse: Nous souhaitons voir comment est-ce que cela a pu se produire. Pour cela, en général, dans un site web on a un système de logs qui définit les faits qu'un staff a fait par exemple. Ce qui est utile pour voir si un problème a eu lieu, ou pour modérer les faits d'un staff. Si jamais ces logs n'existent pas, on ne peut pas vérifier à 100% que c'est dû à ça. Mais la plupart des sites webs amateurs n'ont pas de protection contre la faille CSRF. Donc, je poursuis, en voyant les logs, on peut voir que c'est "vous" qui avez gradé l'utilisateur en question. Si on en revient aux faits, vous avez cliqué sur un lien, qui a gradé un utilisateur. Et ce lien peut poser problème dans un autre contexte. On va voir un autre cas pratique: Dans un forum, imaginons un utilisateur qui fait un post. Ce post a comme contenu une image qui n'est pas visible, vous vous dites sûrement que cette image est morte, mais vous regardez quand même le post. Plus tard, vous vous apercevez que certains de vos topics ont été supprimés. Le problème étant l'image, qui pointe vers une page .php, et cette page a le même principe que l'autre contexte, en revanche touche celui qui a vu l'image, sachant que lorsqu'une image est appelée, elle fait appel à la page PHP, et donc elle est interprétée. Vous allez me dire, supprimer la possibilité de mettre une page .php dans les images est une possibilité, mais ça ne change pas le problème de lorsqu'on clique sur un lien douteux ou que l'on reçoit une image douteuse. Enfin bref, nous allons voir par la suite comment régler ce problème. [HIDE] Je ne vais pas évoquer la façon dont on fait pour exploiter ces failles, mais plutôt comment régler ces failles. Le but de la faille étant de créer un formulaire distant. Ce formulaire distant étant lié au formulaire du site. Pour régler ce problème, on va étudier déjà la façon dont sont fait les systèmes de connexions à un espace membre basique en temps normal. Pour ma part, ça sera sous forme de classe et de fonction, mais ça reste presque le même principe, suffit d'imaginer les restrictions qui ne sont pas stockés dans une classe mais de façon procédurale. #region [Login] /** * @param string $username * @param string $password * @return array|bool */ public function Login($username, $password) { if(!$this->existValue('auth')) { if(!empty($username) && !empty($password)) { $username = htmlspecialchars($username); $searchUser = $this->db->query('SELECT * FROM alive_users WHERE username = ? OR mail = ?', [$username, $username]); // La fonction query est réecrite dans ma classe, elle correspond à un prepare() et execute() en PDO. if($searchUser->rowCount() > 0) { $user = $searchUser->fetch(); if(password_verify(htmlspecialchars($password), $user->password)) { // On utilise du BCrypt dans ce cas $this->setValue('auth', $user); // Équivalent: $_SESSION['auth'] = $user; $e = ['error' => false, 'message' => '5f6f1764f7c2c961654cfbdb8aed67fe735a96bc']; return $e; } else { $e = ['error' => true, 'message' => 'Mot de passe incorrect.']; return $e; } } else { $e = ['error' => true, 'message' => 'Compte introuvable.']; return $e; } } else { $e = ['error' => true, 'message' => 'Les champs ne sont pas remplit.']; return $e; } } else { $e = ['error' => true, 'message' => 'Erreur interne...']; return $e; } } #endregion Pour régler ce problème il va y avoir plusieurs étapes. On va d'abord rajouter une ligne lorsque la connexion est faite, là où on y rajoute le $_SESSION['auth'] = $user; La ligne en question est: $this->setValue('token', sha1(uniqid(rand(), TRUE))); // Équivalent: $_SESSION['token'] = sha1(uniqid(rand(), TRUE))); Ce code va permettre l'intégration d'un token CSRF. Ce token va servir aux vérifications lors des formulaires lorsqu'on est connecté. Chaque fois qu'on se connecte, on possède donc un token unique. Le but étant de pouvoir vérifier si l'utilisateur qui utilise le formulaire est bien la bonne personne. Une personne quelconque n'aura pas accès à votre token, et donc si le formulaire distant est crée, il ne pourra pas y mettre votre token. Vous allez comprendre par la suite. Maintenant, imaginons vous avez un formulaire une fois connecté pour disons... Ajouter votre adresse mail. <form method="POST" action="#"> <label for="form_mail">Entrez votre adresse mail</label> <input id="form_mail" type="text" name="mail"> <!-- On rajoute donc un champs en plus de type "hidden" qui va contenir notre token: --> <input type="hidden" name="token" value="<?= $user->getToken(); /* Ça correspond au $_SESSION['token'] qu'on a crée au préalable à la connexion. */ ?>"> </form> Dernière étape donc, c'est lorsqu'on va donc vérifier ce formulaire, on va devoir prendre en compte le token: <?php // Une fois de plus je reste sous forme de classe: Mais ça reste simple de vérifier votre code, il y a juste 1 vérification en plus à faire: public function addMail($postMail,$postToken) { $session = new Session(); // Appel de la classe Session que j'ai crée mais vous en aurez sûrement pas besoin if(filter_var($postMail, FILTER_VALIDATE_EMAIL)) { if($postToken === $session->getValue('token')) { // Si le $_POST['token'] correspond strictement à $_SESSION['token'] // Code } else { $e = ['error' => true, 'message' => 'Erreur interne...']; return $e; // Le token CSRF est incorrect } } else { $e = ['error' => true, 'message => 'L\'adresse mail est incorrect.']; return $e; } } ?> [/HIDE] C) Faille XSS Problématique: Imaginons que du jour au lendemain, suite à des gens ayant quelque bases qui se sont inscrit sur votre site, vous ayez des alert(); en javascript qui sont présent sur certaines pages de votre site mais pas que! Il est possible aussi que quelques minutes après avoir visité quelques pages, vous pouvez voir que la configuration est plus accessible, voir même que depuis l'administration, une fois de plus, c'est vous qui avez fait tout ça. Détrompez-vous, ce n'est pas quelqu'un qui a accès à votre mot de passe. Résolution: [HIDE] Dans certains cas, si on ne restreint pas les caractères autorisés, les membres ont la possibilité d'entrer des caractères pouvant entrer en conflit avec le langage HTML / Javascript. ( Le PHP n'est pas prit en compte. ) Cela peut même toucher le SQL si la requêtes n'est pas bien faite. Comme toujours j'avance pas de propos concernant la façon dont on exploite les failles mais comment les régler. Il existe donc plusieurs moyens pour régler ces genres de problèmes. 1er moyen: Utilisation d'un moteur de template: Les moteurs de templates sont réputés pour être utilisé en M.V.C ( Model View Controller ). J'utilise souvent Twig pour ma part mais il en existe d'autres. Ces moteurs de templates proposent leur propre langages qui seront retransmit en PHP si par exemple le CMS est en PHP ou en Python si le CMS est en Python, etc. Ça permet dans un premier temps une meilleur lisibilité du code, un rendement plus efficace et permet de découper son code afin de le rendre plus explicite si quelqu'un passe derrière nous afin d'améliorer notre travail. 2ème moyen: Fonction Parse en PHP C'est une fonction assez efficace qui va servir lorsqu'on va afficher du texte qu'on peut définir de "pas sûr". Lorsqu'un utilisateur s'inscrit, il va avoir la possibilité de choisir un pseudo. Certes, on peut rajouter un preg_match afin de lui demander d'utiliser que des lettres / chiffres ( [a-zA-Z0-9-._]+ ) en revanche ça peut facilement poser problème dans d'autres cas. Pour ma part une fois de plus j'ai une class "Security" possédant plusieurs fonctions liés à la sécurité, mais là on parle uniquement de la faille XSS. Ma fonction ressemble à ça, je vais la recoder en tant que fonction simple afin de vous simplifier la tâche, mais le mieux reste vraiment de structurer son travail et donc d'utiliser des classes. Ma fonction: /** * @param $val string * @return string */ public function Show($val){ return htmlspecialchars(utf8_encode($val), ENT_QUOTES, 'UTF-8'); } La fonction simplifiée: function Show($val){ return htmlspecialchars(utf8_encode($val), ENT_QUOTES, 'UTF-8'); } Si jamais vous utilisez des classes, il vous suffira d'utiliser un echo $security->Show($username); par exemple ( sans oublier d'instancier les classes ). Pour les autres, un simple Show($username);. Par contre il faut bien pousser sur le fait que chaque valeur provenant de la base de donnée et affichée, devrait vraiment utiliser cette fonction, sauf si vous êtes sûr de vous. Par la même occasion je vous invite aussi pour le nom d'utilisateur de rajouter un preg_match, cette fonction est générale et fonctionne dans tous les cas. Dernière chose, afin d'éviter les "?" avec les accents, etc. Vérifiez bien que votre base de donnée est en UTF8 -> utf8_general_ci. [/HIDE] Merci de prendre en considération que ce post m'a prit pas mal de temps à concevoir. Si le post est suivit par plusieurs personnes, je rajouterais d'autres types de failles. Modifié le 7 juillet 2018 par Èsska (S-K) Mise à jour 55 4 1 5 Lien à poster Partager sur d’autres sites Plus d'options de partage...
Maxyme 0 Posté(e) le 28 juin 2018 Partager Posté(e) le 28 juin 2018 Top Lien à poster Partager sur d’autres sites Plus d'options de partage...
Tig3r 36 Posté(e) le 28 juin 2018 Partager Posté(e) le 28 juin 2018 Merci à toi ! Développeur PHP, Python, Java, NodeJS Lien à poster Partager sur d’autres sites Plus d'options de partage...
Pancani 168 Posté(e) le 28 juin 2018 Partager Posté(e) le 28 juin 2018 Salut, merci à toi d'avoir pris de ton temps pour ce tutoriel détaillé Ça en aidera plus d'un! Lien à poster Partager sur d’autres sites Plus d'options de partage...
Kioas 6 Posté(e) le 28 juin 2018 Partager Posté(e) le 28 juin 2018 Merci! Lien à poster Partager sur d’autres sites Plus d'options de partage...
Jill 24 Posté(e) le 29 juin 2018 Partager Posté(e) le 29 juin 2018 Merci bien Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 29 juin 2018 Auteur Partager Posté(e) le 29 juin 2018 Il y a 3 heures, Maxyme a dit : Top Il y a 3 heures, Tig3r06 a dit : Merci à toi ! Il y a 2 heures, Pancani a dit : Salut, merci à toi d'avoir pris de ton temps pour ce tutoriel détaillé Ça en aidera plus d'un! Il y a 2 heures, Kioas a dit : Merci! à l’instant, TheJill a dit : Merci bien Oubliez pas le petit +1 si ça vous a été utile. :3 ( Ça compensera le temps que j'ai prit à faire tout ça, sûrement que je continuerais à rajouter des failles. ) 1 Lien à poster Partager sur d’autres sites Plus d'options de partage...
Freefox 1 Posté(e) le 29 juin 2018 Partager Posté(e) le 29 juin 2018 Merci bien ! Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 29 juin 2018 Auteur Partager Posté(e) le 29 juin 2018 il y a 23 minutes, Freefox a dit : Merci bien ! Pas de soucis. Lien à poster Partager sur d’autres sites Plus d'options de partage...
ArKing 2 Posté(e) le 6 juillet 2018 Partager Posté(e) le 6 juillet 2018 Merci mec Lien à poster Partager sur d’autres sites Plus d'options de partage...
Nexus 1 Posté(e) le 6 juillet 2018 Partager Posté(e) le 6 juillet 2018 (modifié) Je comprend pas l’intérêt de cacher le code a ceux qui n'ont pas répondu au sujet mais bon c'est le tiens. Edit: Il faut arrêter de filtrer vos variable en écriture ça ne sert a rien vous ne faites que de perdre de potentiel données. Un htmlspecialchars en écriture suffit largement et d'ailleurs c'est son utilité. Modifié le 6 juillet 2018 par Nexus Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 6 juillet 2018 Auteur Partager Posté(e) le 6 juillet 2018 il y a 30 minutes, Nexus a dit : Je comprend pas l’intérêt de cacher le code a ceux qui n'ont pas répondu au sujet mais bon c'est le tiens. Edit: Il faut arrêter de filtrer vos variable en écriture ça ne sert a rien vous ne faites que de perdre de potentiel données. Un htmlspecialchars en écriture suffit largement et d'ailleurs c'est son utilité. C'est pas ce que j'ai utilisé un "htmlspecialchars"... ? Ton argument n'a aucun intérêt. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Nexus 1 Posté(e) le 6 juillet 2018 Partager Posté(e) le 6 juillet 2018 il y a 26 minutes, Èsska (S-K) a dit : C'est pas ce que j'ai utilisé un "htmlspecialchars"... ? Ton argument n'a aucun intérêt. Non c'est appart la remarque sur les htmlspecialchars juste que ça sert a rien de filtrer une variable en ecriture! Il faut htmlspecialchars en lecture unqiuement.. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Nagasaki 117 Posté(e) le 6 juillet 2018 Partager Posté(e) le 6 juillet 2018 Salut, Merci pour ce formidable tutoriel Une petite révision ne fait aucun mal Ancien Responsable des modérateurs Mon discord : Nagasaki#5318 16 août 2017 -> 16 février 2020 Je m'en vais .. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 6 juillet 2018 Auteur Partager Posté(e) le 6 juillet 2018 à l’instant, Nexus a dit : Non c'est appart la remarque sur les htmlspecialchars juste que ça sert a rien de filtrer une variable en ecriture! Il faut htmlspecialchars en lecture unqiuement.. Mouais, tant que c'est préparé. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Nexus 1 Posté(e) le 6 juillet 2018 Partager Posté(e) le 6 juillet 2018 il y a une heure, Èsska (S-K) a dit : Mouais, tant que c'est préparé. Effectivement tant que c'est préparé Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 7 juillet 2018 Auteur Partager Posté(e) le 7 juillet 2018 Mise à jour: Ajout de la faille XSS Lien à poster Partager sur d’autres sites Plus d'options de partage...
R4x0r3 48 Posté(e) le 7 juillet 2018 Partager Posté(e) le 7 juillet 2018 Super tuto amigo ! Il manque juste certaines failles plutôt récurrentes sur les CMS habbo (Include , SQL , session hijacking , CRLF) et même si t'es vraiment chaud de faire un tuto sur le Buffer Overflow chapeaux aha ! J'aurais même rajouté un alinéa pour parler des stealers et toutes ces conneries limite aha ! Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 8 juillet 2018 Auteur Partager Posté(e) le 8 juillet 2018 Il y a 19 heures, R4x0r3 a dit : Super tuto amigo ! Il manque juste certaines failles plutôt récurrentes sur les CMS habbo (Include , SQL , session hijacking , CRLF) et même si t'es vraiment chaud de faire un tuto sur le Buffer Overflow chapeaux aha ! J'aurais même rajouté un alinéa pour parler des stealers et toutes ces conneries limite aha ! Je me doute bien mais déjà j'ai presque mit 2h sur ce tuto pour mettre des situations, et bien structurer le tout, je fais des ajouts de temps en temps. Lien à poster Partager sur d’autres sites Plus d'options de partage...
UnioOff 5 Posté(e) le 8 juillet 2018 Partager Posté(e) le 8 juillet 2018 merci Lien à poster Partager sur d’autres sites Plus d'options de partage...
LourdLeSon 0 Posté(e) le 8 juillet 2018 Partager Posté(e) le 8 juillet 2018 Merci ! Lien à poster Partager sur d’autres sites Plus d'options de partage...
Èsska (S-K) 136 Posté(e) le 9 juillet 2018 Auteur Partager Posté(e) le 9 juillet 2018 Il y a 3 heures, ShutdownIsBack a dit : Ce qui ce reconnaissent, #!#!#!#! il monte pas le SONS !!! Ça date ça. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Uhmm 1 Posté(e) le 9 juillet 2018 Partager Posté(e) le 9 juillet 2018 Merci ! Tout autant existant qu'inexistant. Lien à poster Partager sur d’autres sites Plus d'options de partage...
Claushpw 1 Posté(e) le 10 juillet 2018 Partager Posté(e) le 10 juillet 2018 Top Lien à poster Partager sur d’autres sites Plus d'options de partage...
KasutageIP 2 Posté(e) le 21 juillet 2018 Partager Posté(e) le 21 juillet 2018 bg Cordialement, Kasutage Lien à poster Partager sur d’autres sites Plus d'options de partage...
Messages recommandés
Créer un compte ou se connecter pour commenter
Vous devez être membre afin de pouvoir déposer un commentaire
Créer un compte
Créez un compte sur notre communauté. C’est facile !
Créer un nouveau compteSe connecter
Vous avez déjà un compte ? Connectez-vous ici.
Connectez-vous maintenant