Protection contre les failles csrf : cross site request forgeries

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