begin process at 2010 03 21 11:48:49
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Sécurité & Cryptage

 > PROTECTION CONTRE LES FAILLES CSRF : CROSS SITE REQUEST FORGERIES

PROTECTION CONTRE LES FAILLES CSRF : CROSS SITE REQUEST FORGERIES


 Information sur la source

Note :
9,5 / 10 - par 2 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Sécurité & Cryptage Classé sous :CSRF, CROSS SITE, XSS, FORM, TOKEN Niveau :Initié Date de création :10/02/2009 Date de mise à jour :10/02/2009 13:27:31 Vu / téléchargé :4 342 / 136

Auteur : aKheNathOn

Ecrire un message privé
Site perso
Commentaire sur cette source (13)
Ajouter un commentaire et/ou une note

 Description

La faille de type CSRF consiste à dévier une requette pour faire effectuer à l'utilisateur une manipulation non voulue en exploitant ses droits d'identification.

Plus concrètement, un administrateur ouvre une session d'administration, puis navigue, soit sur le site actuel, soit sur un autre site. Dans les deux cas, un hackeur pourrait injecter par exemple dans la page navigué par l'administrateur une image pointant vers un lien de supression. Avec une injection de JS on pourrait éventuellement exploiter du POST.

Le tout se sert du principe que l'utilisateur posséde une session ouverte, donc par conséquent effectue les actions sans le savoir.

La protection consiste à créer des jetons validant l'accès à une page. Ceci permet de vérifier que l'utilisateur à réellement visité la page d'administration, puis cliqué sur le lien de suppression qui n'est plus générique puisqu'il contient l'info du jeton.

Une fois le jeton utilisé il est aussi tôt invalidé, donc pas possible d'actualiser une demande déjà traitée.

Le jeton est généré à chaque chargement, invalidant l'ancien token, vous ne pouvez lancer plusieurs pages d'actions en même temps (cas d'un iframe caché).

Le token est pris en fonction de l'IP de celui qui navigue, donc au cas où la session serait volée, le token serait de toutes les façons invalide.

Source

  • <?php
  • include('csrf.class.php');
  • // CHECK FOR GET
  • if (isset($_GET['action'])) {
  • if (!CrossSite::check()) {
  • die('UNAUTH');
  • }
  • echo '<h1>Doing '.$_GET['action'].'</h1>';
  • }
  • // CHECK FOR POST
  • if (isset($_POST['send'])) {
  • if (!CrossSite::check()) {
  • die('UNAUTH : token');
  • }
  • if (!CrossSite::checkSameScript()) {
  • die('UNAUTH : another script');
  • }
  • if (!CrossSite::checkVars()) {
  • echo '-- Possible tentative d\'injection : ';
  • }
  • echo '<h1>Posting '.$_POST['value'].'</h1>';
  • }
  • ?>
  • Try this (on localhost) :
  • <a href="http://localhost<?php echo $_SERVER['SCRIPT_NAME']; ?>?action=delete&<?php echo CrossSite::getLinkToken(); ?>">
  • Do an delete action
  • </a>
  • <hr />
  • Same link from 127.0.0.1 :
  • <a href="http://127.0.0.1<?php echo $_SERVER['SCRIPT_NAME']; ?>?action=delete&<?php echo CrossSite::getLinkToken(); ?>">
  • Do an delete action
  • </a>
  • <hr />
  • <form method="post">
  • Send a form data :
  • <input type="text" name="value" value="<script>alert('toto');</script>" />
  • <input type="submit" name="send" />
  • <?php echo CrossSite::getInputToken(); ?>
  • </form>
<?php
	include('csrf.class.php');
	
	// CHECK FOR GET
	if (isset($_GET['action'])) {
		if (!CrossSite::check()) {
			die('UNAUTH');
		}
		echo '<h1>Doing '.$_GET['action'].'</h1>';
	}
	
	// CHECK FOR POST
	if (isset($_POST['send'])) {	
		if (!CrossSite::check()) {
			die('UNAUTH : token');
		}		
		if (!CrossSite::checkSameScript()) {
			die('UNAUTH : another script');
		}
		if (!CrossSite::checkVars()) {
			echo '-- Possible tentative d\'injection : ';
		}
		echo '<h1>Posting '.$_POST['value'].'</h1>';
	}
	
?>
Try this (on localhost) :
<a href="http://localhost<?php echo $_SERVER['SCRIPT_NAME']; ?>?action=delete&<?php echo CrossSite::getLinkToken(); ?>">
	Do an delete action
</a>
<hr />
Same link from 127.0.0.1 :
<a href="http://127.0.0.1<?php echo $_SERVER['SCRIPT_NAME']; ?>?action=delete&<?php echo CrossSite::getLinkToken(); ?>">
	Do an delete action
</a>
<hr />
<form method="post">
	Send a form data : 
	<input type="text" name="value" value="<script>alert('toto');</script>" />
	<input type="submit" name="send" />
	<?php echo CrossSite::getInputToken(); ?>
</form>

 Conclusion

Bonne prog à tous,
Akh

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

10 février 2009 13:27:31 :
- Vérification d'un postback - Vérification des variables pour éviter une faille XSS

 Sources du même auteur

Source avec Zip OBSERVER PATTERN ORIENTÉ DÉVELOPPEMENT ÉVÉNEMENTIEL DÉCLARAT...
Source avec Zip SERVICE DESIGN PATTERN / CHARGEMENT DYNAMIQUE DE SERVICES D'...
Source avec Zip Source avec une capture WHOIS DOMAIN CLASS : LOOKUP & AVAIBILITY
Source avec Zip Source avec une capture XML MAPPING TO CLASS OBJECTS / CHARGEMENT / PARSING / MODIFI...
Source avec Zip SQLDIFF : MIGRATION, VERSIONNING ET SYNCHRONISATION DE LA ST...

 Sources de la même categorie

FONCTION DE NETTOYAGE DE VARIABLES AVEC UNE INSTALLATION DE ... par jroger
ALGORITHME DE CÉSAR SUR LA TABLE ASCII par Nementon
Source avec une capture CODEC D'OBFUSCATION DE LIEN HTML (PHP5) par masternico
GÉRER UN .HTPASSWD par coockiesch
Source avec Zip SERSESSIONS > CLASS PHP5 POUR GERER LES SESSIONS SIMPLEMENT par Astalavista

 Sources en rapport avec celle ci

Source avec une capture GÉNÉRATION/GESTION DE FORMULAIRE VIA FICHIER XML par Garno
Source avec Zip MAJAX UN TOOLS (AJAX EN PHP) par michelsto
Source avec Zip Source avec une capture GÉNÉRATEUR DE FORMULAIRE [AJAX][PHP5] par Morphinof
Source avec Zip [PHP5] - CLASSE DE VÉRIFICATION DE FORMULAIRE par codefalse
PROTECTION CONTRE LE XSS ET L'SQL INJECTION par psykocrash

Commentaires et avis

Commentaire de winwarrior le 10/02/2009 20:13:11

Salut,

J'ai lu la source en diagonale, mais n'y a t'il pas de problemes avec le referer en cas d'url rewriting?
Quelqu'un qui aurait un  firewall qui bloque le header referer ne pourrait pas surfer sur le site?
Pour les méthodes escapeValue/checkValue, je doute qu'on puisse envisager toutes les possibilités.. là exemple idiot si je passe comme variable "<SCRIPT" (donc en majuscule), ou "jav\nascript" ça passe les filtres actuels, il y a tellement de manieres d'écrire ce genre de scripts..
Par contre l'idée des tokens est sympa :p

@+

Commentaire de aKheNathOn le 10/02/2009 20:31:40

Salut Warrior !

Le referer est utilisé pour vérifier la provenance de la requette, genre vérifier que l'appel ne se fait pas d'un webmail ou d'un autre host. Ca va un peu plus loin car ça vérifier si c'est pas une autre page que celle contenant le script qui serait appelée. Faudrait que je vérifie le cas d'une url rewritée mais le principe doit être le même.

Sinon la classe est configurable en écrivant ceci :
CrossSite::$checkHost = true / false;
CrossSite::$checkToken = true / false;

Concernant la vérification d'injection JS effectivement ça ne doit pas être case sensitive, parcontre la découpe de java\nscript est bien spécifique :) c'est un cas spécial.

Je refais un release, mais je suis certain que le filtrage des variables avant utilisation est indispensable vu le nombre de failles sur la majorité des sites.

Commentaire de neigedhiver le 14/02/2009 00:00:49

Salut,

C'est marrant, ça  me fait penser à un billet de Korben sur son blog récemment (il y a une petite dizaine de jours je crois) dans lequel il expliquait comment faire écrire ce qu'on veut sur le twitter de n'importe qui...
Il disait notamment qu'il n'était pas possible de se protéger contre cette "faille" : en fait, les protections à mettre en place doivent l'être sur le site, et pas par les visiteurs.
La meilleure protection consiste encore à ne pas garder ses sessions d'admins ouvertes et à personnaliser (autant que possible) les chemins des fichiers d'admin.
L'idée de token est bonne, moi, ça me plait.
J'ai pas regardé le code, mais... je te fais confiance ;)

Commentaire de victorcoasne le 02/03/2009 13:36:19

Salut,
Je penses que tu t'es inspiré de Kerberos car tu parles de tickets.
Tu sais qu'en intégrant à ta page les vérifications normales d'un espace membre on obtient le même effet.
En protégeant biensûr les requêtes avec addslashes() et les champs avec htmlentities() pour éviter que le navigateur interprête un script.
Bonne continuation et bonne prog,
@++

Commentaire de aKheNathOn le 02/03/2009 13:49:32

Salut Victor,

En intégrant les vérifications normales tu laisses des failles.

On prends par exemple un espace d'admin sur ton site, sur lequel en exécutant le script delete_all.php, ton site est vidé. Moi étant méchant et sachant que tu utilises le fameux cms PhpDuke, je décide de te tendre un piège. En te connectant à ton panneau d'admin, tu décides après que je t'envoie une URL sur mon blog de consulter la page. Elle à un lien <img src="...tonsite/delete_all.php" />, or tu est loggué, donc tu as le droit de l'exécuter, sauf que tu ne l'as pas demandé.

Pareil, l'histoire de tickets, c'est pour te protéger de ce même type de faille, mais à l'intérieur de ton propre site, car tu peux avoir un forum et que je puisse y cacher une image vers cette url également.

C'est des failles encore mal comprises et peu exploitée, mais une grande majorité de sites sont vulnérables.

L'histoire du token est loin d'être inutile. L'idée est que tu crées une autorisation avant d'exécuter une action. Sans cette action au préalable, impossible de l'exécuter. Ca peut être piraté mais qu'avec des tonnes d'injection JS plus difficiles à coder, et qui souvent ne passent pas par injection en raison de la longeur de stockage des messages, ça sécurise donc à 99% des cas.

Commentaire de victorcoasne le 02/03/2009 22:32:50

Je vois un peu mieux l'intérêt sauf que je n'utilise jamais de CMS et que je n'ai aucune page qui supprime tout (ça serait débile).
En plus tout mes deletes de BDD se font par POST et dans une page où seule moi est accès et seul moi sait comment elle fonctionne.
Je peux aussi dans ce cas teste le référer et n'autoriser que si c'est de mon site.

Commentaire de aKheNathOn le 03/03/2009 10:52:24

Ok victor, t'as tout à fait raison quand tu parles de ton système propriétaire. Je reviens juste sur tes choix pour montrer leurs limitation et expliquer quelques fonctionnalités.

Le post n'est pas suffisant, en javascript tu peux faire du post avec de l'ajax ou même avec un formulaire dont le target est vers un iframe caché.

Le referer dont tu parles est un très bon choix :) ça limite les attaques à ton site seulement - mais elles peuvent subsister si sur ton site l'utilisateur peut y stocker des informations affichées. C'est le principe même des réseaux d'utilisateurs, ou forums. Si a ce moment l'utilisateur trouve une faille d'injection javascript il pourra te forcer à ton insu à executer des appels (post ou get).

C'est pour ça l'histoire de token : c'est que quand tu demandes la page de listing des utilisateurs que le token est créé et t'ouvre le droit d'en supprimer un.

Sans appeller cette page et trouver ce token, on ne pourra pas te forcer à executer la page.

Du moment ou tu as customisé ton site avec tes propres scripts tu court moins de problèmes côté administration mais le méchant hacker pourra s'amuser à créer des virus javascript si t'as des failles d'injections exploitables avec des failles CSRF, et là ton site n'est pas à l'abri de ce type d'attaque.

Commentaire de victorcoasne le 03/03/2009 22:21:43 10/10

Ok merci des infos.
ça fait plaisir de voir que sur ce site y'a quand même des gens qui maîtrise bien leur sujet et qui donnent un avis objectif.
Sinon c'est une bonne source pour les gens qui n'aurait pas connaissance des principales failles existance, et avec tes explications ça en éclairera plus d'un.
Bonne prog,
@++

Commentaire de kankrelune le 29/06/2009 17:05:57 9/10

A l'époque ou je travaillais sur le code de Xoops on avait intégrés les tokens dans les formulaire admin... l'idée ne date pas d'hier et c'est la meilleur solution, même la seule, pour lutter contre ce genre d'attaque... cependant l'utilisation de l'ip dans le token peut être problématique avec des utilisateur dont le FAI gère les ip en dynamique (on avait de gros pb avec AOL à l'époque) le mieux étant d'utiliser l'host de l'ip et non l'ip elle même... couplé par exemple avec le user_agent... beaucoup plus fiable... .. . ;o)

Au passage ta méthode pour récupérer l'ip est trop simpliste et peu fiable et à partir du moment ou tu check les tokens à chaque action tu n'a pas besoin de checker la présence de code executable dans les variables (ce qui pourrais poser pb dans un site comme code sources)

@ tchaOo°

@ tchaOo°

Commentaire de kankrelune le 29/06/2009 17:08:28

ah au passage... stock ton token la première fois que tu le génère... inutile de faire 36 fois md5(... .. . ;o)

@ tchaOo°

Commentaire de aKheNathOn le 29/06/2009 18:01:34

Bjr Kankrelune,

Merci pour ton com, juste quelques remarques suite au tiennes :

- Le token est généré (md5) qu'une seule fois au chargement de la page, c'est un singleton.

- La récup de l'IP ne prend pas en compte les proxy, parcontre je ne vois pas d'autres moyens pour récupérer l'adresse IP de celui qui demande la page - si tu pouvais m'en dire plus ...

- Pour le check du token, je suis d'accord avec toi, pas besoin de vérifier s'il y a injection. C'est pour ça que la fonction check qui valide le token n'execute pas checkVars qui est une fonction indépendante. Je l'ai implémentée en tant que fonction utilitaire car sur certains formulaires les actions ne sont pas faites que par des personnes de confiance.

Concernant la remarque sur les FAI tu n'as pas tord, mais malgré tout le user_agent ne me plait pas car le client peut y mettre ce qu'il veut.
Pour le remote host, la variable n'est pas toujours renseignée, faut qu'apache soit configuré (mon code doit être générique et tourner sur un max de config). Concernant l'histoire d'ip et hostname si tu connais une lib d'autres fonctions, je suis vraiment preneur.

Bonne prog,
akh

Commentaire de kankrelune le 30/06/2009 00:39:08

Slt...

- je n'avais pas vu pour le singleton (j'ai pas épluché la source en détail) du coup c'est pas du token dont je parle mais de la clef tokenKey() qui plus est ça fait peut être beaucoup une string de 32 char comme index (ça prend de la place pour rien dans une requête GET) et je ne suis pas sûr que le gain soit énorme niveau sécu

- tu sais comme moi que récupérer l'ip via php (et même tout court) est pas super fiable, d'autant plus quand l'internaute est derrière un proxy ou un réseau cependant tu as des variables transmise par les proxy notament les x_forwarded et http_via qui peuvent être utile si renseignées... tu pourra trouver un exemple dans le code source de phpmyadmin... après il reste toujours une marge d'erreur mais c'est mieux que de se baser uniquement sur remote_addr

- j'avais pas fait gaffe... j'ai rien dis...

- oui tu peut facilement modifier le user_agent mais encore faut il connaitre le user_agent de la personne que tu vise ce qui est faisable mais c'est une variable de plus... de toute façon si un gars réussis à récupérer le user_agent exacte (versioning & co) de sa cible il y a fort a parier qu'il aura récupéré l'ip aussi donc bon... c'est pas pour ce que ça change

concernant l'ip elle même maintenant... tu récupère le host via un classique gethostbyaddr() tu extrait l'ip qui est généralement renvoyée par le serveur BAS sur lequel est relié l'internaute du coup tu te retrouve avec le non du FAI et généralement avec le code du NRA (des fois même le n° de carte DSLAM et/ou les vp/vc DSLAM/BAS mais c'est plus rare faut pas trop compter dessus) que tu peux coupler avec les deux premiers blocks de l'ip qui sont propres au FAI le tout mixé via md5 avec, éventuellement, le user agent et là ton token reste fiable tout en évitant le plus possible les pb dû aux ip dynamique... c'est un poil moins fiable que l'ip au complet car certains FAI on une résolution ip => host un peu pauvre en infos (pas de nom de NRA par ex) mais ça reste, à mon sens, suffisamment fiable pour la plupart des utilisations... tu peux aussi te servir de uniqid() pour corser le tout...

uniqid(md5($uvars),true)

mais là ça devient de la parano je pense... .. . ;o)

@ tchaOo°

Commentaire de kankrelune le 30/06/2009 00:46:25

tiens...

function uv_getVar($var_name) {
    if (isset($_SERVER[$var_name])) {
        return $_SERVER[$var_name];
    }
    if (isset($_ENV[$var_name])) {
        return $_ENV[$var_name];
    }
    if(($env = @getenv($var_name)) !== false) {
        return $env;
    }
    if (function_exists('apache_getenv')) {
        if(($env = @apache_getenv($var_name, true)) !== false) {
            return $env;
        }
    }
    return '';
}

function uv_getIP()
{
    $proxy_ip = '';
    $i = -1;
    $where = array(
                    'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED',
                    'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED',
                    'HTTP_VIA', 'HTTP_X_COMING_FROM', 'HTTP_COMING_FROM'
                );
    
    while(!empty($proxy_ip) && isset($where[++$i])) {
        $proxy_ip = uv_getVar($where[$i]);
    }
    
    if (empty($proxy_ip))
        return uv_getVar('REMOTE_ADDR');
    else
    {
        $is_ip = preg_match('|^([0-9]{1,3}\.){3,3}[0-9]{1,3}|', $proxy_ip, $regs);
        if (!empty($is_ip) && (count($regs) > 0))
            return $regs[0];
                else
                    return $proxy_ip;
    }
}

@ tchaOo°

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Mise en form du texte [ par David ] J'utilise feuille html avec des contentsTout le texte qui contient des apostrophesdoit etre précéderde "\"exemplel'eau donne l\'eaucomment faire la mi form->php->html [ par BigZoo ] voilà mon pb:j'ai un fichier html en destination avec une structure bien définie et je veux, à partir d'un formulaire dans lequel je mets du texte, de Pb Recup variables FORM POST [ par fil ] Bonjour, Je suis en train de me prendre la tete sur un moyen de recuperer des variables d'un formluaire qui est créé dynamiquement par la lecture des Tutorial form de discussion [ par must ] Salut,cherche tutorial pour faire un forum de discussion,avec arborescence,et possibilité quand quelqu'un repond à une question,de prevenir celui qui un Form dans un Form [ par stailer ] Salut tout le monde !Donc voila mon problème :J'ai un formulaire qui contient notamment un champ et une liste déroulante.Lorsque je valide 1 de ces ch fction mail() en local [ par MisterJAD ] voilà, j'essaie de faire un formulaire qui permette d'envoyer un mail avec les données des champs du form... voici le code du form&lt;form name="form1 Probleme variable FORM [ par Clonk ] bonjour,voilà mon 'petit' probleme:j'ai un formulaire de modification, je recupere les infos d'un fichier texte et puor certaines infos, il se peut qu Aide svp ;( Inclure upload form dans un form existant [ par poluxdeparis ] Bonjour a ceux qui seront interessés par mon appel à l'aideJe souhaite integrer, à un module que j'ai mis en place pour phpnuke, un champ de form pour alleger un script a l'aide de swicth et autres structures... [ par bricethenetman ] Slt à tous hier j'avé un prob ke g résolu grace à Tortue Géniale, aujourd'hui g un autre prob cependant bocou mo1 grave. J'aimerais alléger mon script Liste de form et BDD [ par Cestmoi ] Bonjour,Comment faire pour inserer dans une base tout les enregistrements present dans une liste, meme si ils ne sont pas selectionné ?Merci !


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mars 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728
293031    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,640 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales