La vulnérabilité open redirect dans les applications web

mieux protéger une application internet

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com
Chaque attaque est provoquée par l'inconscience du développeur et de l'internaute. La faille communément appelée "open redirect" en est l'exemple parfait.

Dans la première partie de l'article on verra comment un attaquant peut exploiter cette inconscience commune. Ensuite, on présentera des méthodes de détection de ce type d'attaque dans le code de l'application. On finira par les moyens de protection qu'on peut mettre en place.

Une base pour phishing
Une faille de la redirection ouverte est possible dès que l'application ne valide pas les données modifiables par l'internaute. On peut, par exemple, utiliser une page avec la redirection pour amener la victime sur un autre site qui imite, par exemple, le formulaire de connexion d'une banque. La vulnérabilité ouvre alors la porte au phishing car l'attaquant peut facilement collecter toutes les informations utiles.

L'attaquant peut procéder selon la manière suivante. D'abord il peut copier la page de connexion du site A, dont il n'est pas propriétaire, sur son site B. Évidemment, l'adresse ne sera pas la même, mais la majorité d'internautes ne le remarquera pas (combien de fois, après une mauvaise connexion vous avez regardé l'URL de la page sur laquelle vous vous trouvez ?).

La façon d'atteindre la victime peut être plus ou moins directe. L'attaquant peut envoyer un mail directement à la personne concernée. Mais il peut également agresser une cible plus large via, par exemple, l'achat de l'espace publicitaire. En adoptant la règle "le client est le roi", les supports publicitaires peuvent, malgré eux, laisser apparaître un lien dangereux pour les internautes moins avertis.

Détecter open redirect
La détection de la vulnérabilité open redirect peut commencer par un bon, vieux grep. Dans la chaîne de caractères recherchés on peut mettre des noms des paramètres qui sont souvent associées à la redirection (redirect, redirect_url, url, forward, forward_url...).

Si cette recherche est infructueuse, cela veut dire qu'il faut analyser plus profondément. Selon le langage de programmation utilisé, vous pouvez chercher les fragments avec les noms des méthodes de redirections et de forwardings (Header("Location"), sendRedirect(), setHeader( "Location"), document.location.href...). Si vous utilisez un framework, vous pouvez également rechercher dans votre application web l'apparition des méthodes gérant les redirections (forward(), redirect(), new RedirectResponse() pour Symfony2, _forward() et _redirect() pour Zend Framework)

On peut aussi utiliser des bots qui se baladent dans l'application et testent de différentes variantes. Cependant, cela devrait être, au mieux, un élément supplémentaire de l'analyse.

Se protéger contre open redirect
La protection de base repose sur le principe accept known good. Selon lui, l'application accepte uniquement les éléments pré-définis, qui lui sont donc familiers. Ce whitelisting peut se résumer, par exemple, aux noms de domaines sur lesquels on peut effectuer les redirections. Il peut également signifier les patterns RegEx des URLs acceptés.

Pour bien se protéger contre l'attaque open redirect, le développeur devra prendre en compte tous les endroits qui peuvent provoquer une redirection. Si la gestion des redirections repose sur les en-têtes des requêtes, on devra les protéger au même titre que comme s'il s'agissait des variables $_POST ou $_GET passées depuis les formulaires. La même préoccupation concerne les cookies, les données propres au client (comme l'adresse IP par exemple). Une simple méthode de redirection, avec une protection incluse, peut se présenter ainsi :

/**
* Checks if the $url is legitimate to make a redirect.
* @param string $url Url to check.
* @return bool True if $url is correct, false otherwise.
*/
function safeRedirect($url)
{
$acceptedHosts = array('http:\/\/(www.|)mysite.com\/', 'http:\/\/(www.|)mysite.net\/');
$patterns = array('news\/([A-Za-z0-9])+', 'account\/([a-z])+');
foreach($acceptedHosts as $host)
{
// checks main domain
echo 'Using pattern : /^'.$host.'$/i on URL '.$url.'

';
if(preg_match('/^'.$host.'$/i', $url))
{
return true;
}
// checks URL patterns
foreach($patterns as $pattern)
{
echo 'Using pattern : /^'.$host.$pattern.'$/i on URL '.$url.'

';
if(preg_match('/^'.$host.$pattern.'$/i', $url))
{
return true;
}
}
}
return false;
}
/* Uncomment to see the output of safeRedirect() calls
echo (int)safeRedirect('http://phishingsite.com/');
echo '
';
echo (int)safeRedirect('http://mysite.com/');
echo '
';
echo (int)safeRedirect('http://www.mysite.com/news/çàs');
echo '
';
echo (int)safeRedirect('http://www.mysite.com/account/feeds');
echo '
';
echo (int)safeRedirect('http://www.mysite.com/news/about');
*/


La vulnérabilité open redirect est une nouvelle fois la preuve qu'il faut à tout prix contrôler les données introduites par l'internaute dans notre application web. Sans cette maîtrise, on expose notre utilisateur à des attaques du type phishing. L'application, quant à elle, est exposée à la mauvaise presse, difficile à rattraper par la suite.

L'article écrit en rythme de:
Slaï - Reviens
Bartosz KONIECZNY 27-12-2011 13:34 sécurité des applications web
Un conseil PHP

Problème lors d'implode du saut de ligne ?

Si tu tentes d'introduire un saut de ligne (\r\n) dans un fichier, fais attention. L'appel implode(' \r\n ', $array) ne l'ajoutera pas car '\r\n' est traité comme une chaîne de caractères.

Pour réussir la manipulation, il faut appeler implode(" \r\n ", $array).