Protection contre les failles csrf : cross site request forgeries

Soyez le premier à donner votre avis sur cette source.

Vue 9 481 fois - Téléchargée 492 fois

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 / Exemple :


<?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

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

winwarrior
Messages postés
654
Date d'inscription
jeudi 3 avril 2003
Statut
Membre
Dernière intervention
10 février 2009
1
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

@+
aKheNathOn
Messages postés
276
Date d'inscription
dimanche 22 juillet 2001
Statut
Modérateur
Dernière intervention
5 décembre 2013

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.
neigedhiver
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
14
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 ;)
victorcoasne
Messages postés
1100
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
17 octobre 2012
3
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,
@++
aKheNathOn
Messages postés
276
Date d'inscription
dimanche 22 juillet 2001
Statut
Modérateur
Dernière intervention
5 décembre 2013

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 , 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.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.