Sécurisation des failles CSRF

Formation

En Semi-présenciel Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En semi-présentiel

  • Lieu

    Paris

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Les matières

  • Sécurité
  • Cross-Site Request Forgeries

Le programme

Introduction du cours

Bienvenue à tous !

Aujourd'hui, je vais vous introduire une nouvelle faille de sécurité, et vous expliquer comment vous en protéger au mieux.

Si vous êtes développeur et que la notion de "token" ne vous dit rien, lisez vite ce tuto, on est peut-être déjà en train de vous pirater !

Ce tutoriel concerne les sites PHP, vous devez donc maîtriser ce langage (c.f. : le tuto de M@teo21). Il est surtout utile pour les sites en activité, et assez complets, puisque ceux-ci doivent reposer sur un système de privilèges.

C'est partiiiii ! ;)

CSRF, késako?

Je suis sûr que vous vous demandez :

Mais c'est quoi ce CSRF dont il nous parle depuis tout à l'heure ?

Ah oui, j'avais oublié de vous expliquer ! :diable:

CSRF signifie "Cross-Site Request Forgeries". Je vous donne un exemple :
Paul est newser d'un site, il peut donc ajouter, modifier, et supprimer une news, ce qu'un utilisateur du site lambda ne peut PAS faire.
Jean est un de ces utilisateurs lambda, et il aimerait pirater le site de Paul ! :pirate: Il va donc récupérer l'adresse permettant de supprimer une news, et envoyer un message privé à Paul contenant une image dont l'adresse sera celle de la page de suppression de news.

Et là, le navigateur entre en jeu. En essayant d'afficher l'image, il va aller sur la page web permettant de supprimer la news et donc l'exécuter. Or, Paul était identifié en tant que newser, la news sera donc supprimée car IL a affiché la page.

Sur le même principe, si Paul peut recevoir une requête ajax qui en s'exécutant va poster ou modifier une news !
C'est-à-dire que Paul recevra un code javascript qui "forcera" le navigateur à appeler la page que le pirate veut que Paul exécute.

On va donc apprendre à se protéger de ces failles très dangereuses, sachant qu'il n'existe pas de protection parfaite.

Avant d'entrer dans le vif du sujet, je précise à toutes fins utiles que cette faille ne s'applique pas uniquement au cas que je présente dans ce tuto (c'est à dire le "piratage" d'un espace d'administration), mais peut-être utilisée dans de nombreux domaines où le but est de faire générer une requête par le navigateur de la victime (pour truquer des votes par exemple).

Le jeton de sécurité ou token

Alors, pour commencer, voyons la protection la plus courante. :)
Elle consiste à stocker un jeton unique (clairement une suite de nombres et de lettres) associé à la date d'affichage pour chaque visiteur qui affiche un formulaire dans une session, et ce même jeton dans un champ caché. Ceci permet que la personne qui tente d'exécuter la page est bien passée par le formulaire avant, où on lui a délivré le jeton.

Bon, jusque-là, c'est bon je pense... Les commentaires sont explicites. :soleil:

Je rappelle que session_start() se place avant tout affichage, c'est souvent une cause d'erreurs inexpliquées. Vous pouvez outrepasser cette limitation grâce aux fonctions ob_, mais c'est moins propre.

Ensuite, on passe à la page du traitement, et vous vous rendrez compte qu'il est très simple de se protéger efficacement.

On va déjà vérifier la présence du token, de sa date dans la session, et du token envoyé par POST. Donc, si la personne qui exécute la page n'est pas passée par le formulaire, ça bloque...

Le token doit aussi être valide, c'est-à-dire identique à celui envoyé par POST, et non-expiré, c'est-à-dire que sa génération ne remonte pas à trop longtemps.

Ce qui donne finalement :

Je vous conseille si vous utilisez cette méthode sur plusieurs scripts de nommer vos sessions pour ne pas confondre les jetons.

Voilà pour la protection de base. Suivez le guide, on va rentrer dans d'autres petites sécurités à mettre en place pour bien gêner le pirate. :diable:

Évidemment, on peut utiliser un token pour des actions qui ne passent pas par un formulaire.
Par exemple : sur une page ou l'administrateur peut supprimer des news, il y a plusieurs liens vers : supprimer_news.php?id=34

Au lieu de transmettre le jeton par POST, on le transmet par GET, comme les autres données (en l'occurence l'ID de la news à supprimer). Le principe reste sinon le même, mais le POST est plus sûr.

Le referer

On va donc poursuivre notre long chemin vers la vérité. ;)

Imaginons que le pirate fasse une injection CSRF et que, au moyen de requêtes AJAX, il fasse afficher à l'admin la page du formulaire puis la page du traitement...

Une requête AJAX, c'est un code Javascript qui s'exécute et qui appelle en arrière plan (c'est à dire que c'est invisible pour l'utilisateur) une page distante. Le javascript étant un langage client, c'est à dire exécuté par l'utilisateur et non par le serveur, le site qui reçoit la requête AJAX est appelé comme si l'utilisateur victime l'avait appelé consciemment. C'est donc un moyen de réaliser une attaquer CSRF. Je vous renvoie vers ce tuto.

Eh bien l'injection serait réussie :waw: , car le token aurait bien été généré par la page 1, et la vérification sera passée avec succès sur la page 2, sauf si vous vérifiez que la page qui a conduit le visiteur à la page de traitement est bien le formulaire, c'est à dire que le visiteur a cliqué sur un lien ou un bouton de la page 1 qui l'a directement conduit à la page 2.

On peut vraiment faire ça ? :honte:

Oui, bien sûr, grâce à $_SERVER['HTTP_REFERER']. C'est une variable disponible n'importe où dans votre script sans rien à faire de particulier (comme toutes ses cousines $_SERVER['...']), et elle contient l'adresse, si elle existe, de la page qui a amené votre visiteur sur le script en cours.

ATTENTION : cette variable renvoie une adresse absolue, par exemple http://lesite.com/dossier1/url_a_rallonge.html, et non pas ../url_a_rallonge.html

Donc, on va rajouter un if qui vérifiera si cette variable est égale à la page formulaire.php, je vous laisse trouver ça tout seul (je sais, je suis cruel :diable: ).

Ramassage des copies, et correction :

= $timestamp_ancien) { //Si le referer est bon if($_SERVER['HTTP_REFERER'] == 'http://monserveur.com/leformulaire.php') { //ON FAIT TOUS LES TRAITEMENTS ICI //... //... } } } } //SINON, ON RAJOUTE DES ELSE ET DES MESSAGES D'ERREUR ?>

Remplacez évidemment l'adresse du formulaire par la bonne. :)

Le referer est envoyé par le navigateur du client, en d'autres termes il est très facile de le modifier ! Ne vous fiez donc pas à lui à 100%, ce n'est qu'une protection complémentaire.

Voilà, vous êtes déjà bien protégés, mais il y a encore quelques petites choses à voir... On continue!

Autres conseils

Je vous rappelle qu'aucune protection n'est parfaite, mais que les pirates sont des feignants et donc s'ils doivent passer 50h avant de vous pirater, il vont chercher une autre victime !

Donc, premièrement, passez le plus de données possibles en POST, ça oblige à monter une attaque avec des requêtes AJAX, puisque la technique de l'image (voir partie I) ne permet pas de passer des données en POST à la page appelée, mais seulement en GET (dans l'URL).
De plus, la taille des URL est limitée à 255 caractères, donc ça fait pas lourd.
Privilégiez le POST, mais avec discernement, pour passer un id dans l'URL, par exemple, profil.php?id_membre=1, pas la peine d'utiliser POST, GET suffira bien.

Ensuite, on a obligé le pirate à nous envoyer du code AJAX qui sera exécuté par l'administrateur. Hé, il me vient une idée, si on l'empêchait de le faire ? Allez, lançons-nous ! :magicien:

On va échapper les caractères HTML nécessaires par exemple le < et les ' " qui sont indispensables pour ce type d'attaque (ne soupirez pas, c'est plus que simplissime). La plupart de vous doit s'en douter, on va utiliser htmlspecialchars().

Vous utilisez peut-être déjà htmlentities(), sachez que c'est htmlspecialchars() + d'autres choses, donc ça convient très bien !

Il suffit donc de passer tout ce qui risque de contenir du code qui sera affiché à travers cette fonction, par exemple (vous pouvez changer le nom des variables :D ):

À la poursuite de la protection parfaite :ange: , vous pouvez aussi sur la page traitement demander une confirmation avant de valider l'action. Donc, à moins que le webmaster clique sur poursuivre, rien ne sera exécuté. Mais réservez cette technique aux points clés du site, parce que c'est très lourd !
Dans le même ton, il est possible d'exiger une double connexion pour obtenir l'accès à la partie d'administration, comme dans certains forums PhPBB. Ainsi, on peut conserver une option de connexion automatique (bien pratique) sans risque, puisque si l'administrateur veut se connecter à l'administration, il devra se reconnecter.

Vous pouvez aussi sur le même principe demander avant une action critique de retaper le mot de passe.

Enfin, je vous conseille de lire ce tuto, qui vous donnera des pistes pour contrer le vol de session, qui ici peut constituer une faille dans le système.

Il existe donc de nombreux moyens de vous protéger, je ne les ai pas tous cités, et je vous invite donc à vous documenter, puisque le Web ne manque pas d'informations à ce sujet, et de jeter un coup d'oeil à la partie bonus ! L'idéal est de choisir une ou un ensemble de protections qui combinent praticité et efficacité, c'est à dire le compromis entre sécurité et ergonomie. Là, vous êtes les seuls juges.

Les bonusRésumé de nos fonctions

Vous êtes encore là ? Très bien, pour vous féliciter de votre persévérance, je vous ai récapitulé tout le code, évidemment, à vous de l'adapter à vos besoins.

Voici donc 2 petites fonctions qui récapitulent les principales protections, pour les explications référez-vous aux commentaires :

= (time() - $temps)) if($_SERVER['HTTP_REFERER'] == $referer) return true; return false; } ?>

Bon, je vous donne quand même un exemple d'utilisation mes chers Zéros. Voici la page du formulaire :

Et voici la page de traitement :

Mais pourquoi met-on if(verifier_token(...)) ? Ça n'a aucun sens ?

Eh bien si : la fonction renvoie true si le token est valide, et false s'il est invalide, ce qui donne :
Si le token est validé : if(true), ce qui équivaut à "si vrai", donc la condition est vérifiée
Sinon, c'est if(false), si faux, condition non valide, on exécute le else.

Pour approfondir

Si vous voulez en apprendre plus, je vous conseille les sites suivants :

    • Wikipédia

    • XMCOPartners(audit informatique)

    • MTI

Il est aussi intéressant de voir comment les grands scripts open-source (PhPBB, Joomla, etc.) se protègent de ce genre d'attaques. Les parades qu'ils déploient sont réfléchies par toute une communauté, ça les rend donc efficaces.Enfin, j'attire votre attention sur le fait que certains frameworks facilitent la gestion de la sécurité, nativement ou avec des modules, comme Ruby on Rails, Django, etc.

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Sécurisation des failles CSRF

Prix sur demande