Failles des applications web liées à l'encodage

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
L'encodage incorrect peut provoquer des failles de sécurité très graves. Elles peuvent provoquer une vulnérabilité XSS malgré l'utilisation des filtres et le blacklisting de certains mots (d'où il faut privilégier le whitelisting). De même, une faille causée par l'encodage peut être à l'origine d'un problème avec SQL injection.

La première partie de l'article présentera les spécificités de différents encodages utilisés dans le monde informatique. Ensuite un bref rappel historique prouvera que l'encodage ne peut pas être négligé dans le développement d'une application web sécurisée. Dans la dernière partie on verra les moyens d'exploiter une faille de sécurité liée au mauvais encodage de l'application.

De l'ASCII à l'UTF-8
Il y a 50 ans, en 1961, Bob Bemer a inventé l'ASCII qui est vite devenue la norme de codage de caractères la plus connue (aussi grâce à la domination américaine dans le monde informatique). Un caractère (lettre, chiffre, signes de ponctuation) y est codé en binaire sur un octet.

Avec la démocratisation de l'informatique, le monde a voulu utiliser les caractères nationaux (lettres accentuées, signes de ponctuation supplémentaires). Une multitude d'encodage a alors vu le jour. Chaque coin de la planète avait alors ses propres standards. En Russie on utilisait KOI8-R, les pays de l'Est préféraient ISO-8859-2, l'Europe occidentale travaillait avec ISO-8859-1... Afin de mettre tout le monde d'accord (et donc faciliter le travail de développeurs = baisser les coûts), en 1991 le Consortium Unicode a été fondé.

Cinq ans plus tard UTF-8 a été amendé et défini dans la norme ISO/CEI 10646 (un sorte de répertoire contenant tous les caractères acceptables par les applications informatiques). La spécificité de ce standard d'encodage repose sur une meilleure interopérabilité des logiciels. Cependant, pour certains caractères bien spécifiques (par exemple idéogrammes utilisés dans le chinois, coréen ou japonais), UTF-8 occupe plus d'octets que d'autres encodages. Pour l'exemple des pays asiatiques, un signe encodé en UTF-8 prend 3 octets. Le même caractère, codé en UTF-16, occupe 1 octet en moins.

10 ans d'exploits
Une nouvelle fois Microstoft a la lourde tâche de subir les premiers exploits. Comme c'était déjà le cas avec SQL injection, cette fois-ci le géant américain n'a pas été épargné. En 2000 un utilisateur anonyme a détecté une faille sur les serveurs IIS 4 et 5. Elle consistait sur l'utilisation des caractères Unicode à la place de \ et / traditionnels pour se déplacer dans les répertoires de la machine et, finalement, exécuter les commandes interdites pour un utilisateur non authentifié.

Google a rencontré le même sort que son frère américain. En 2005 on pouvait exploiter une faille liée aux caractères envoyés en encodage UTF-7. Le filtre XSS de Google a correctement échappé les chaînes de caractères dangereuses contenant les < et > . Cependant, si ces caractères étaient envoyés en UTF-7, le filtre les acceptait comme tels. Un exploit XSS a donc été possible. Google a corrigé cette faille en renforçant son mécanisme d'encodage.

Exemples d'attaques liées au double encodage
Le problème vient souvent du fait que l'on applique mal la règle d'or du filtrage "filter input, escape output". Supposons que notre application accepte les données textuelles passées dans le paramètre GET. Elle prend ce texte et l'insère dans la base de données pour l'afficher ensuite aux autres internautes. Voici le code:


// we call an url /filter.php?text=%3Cb%3ETesT%3C%2Fb%3E
$textGet = strip_tags($_GET['text']);
// after stripping we receive %3Cb%3ETesT%3C%2Fb%3E
echo urldecode($textGet);
// we see TesT (HTML was applied correctly)

Ici, on a mal implémenté la règle d'or de filtrage. Certes, on a filtré les données entrantes, mais on ne les a pas échappées correctement. En plus, l'encodage des caractères n'a pas été uniformisé avant l'affichage. Le code correct se présente ainsi :

// we call an url /filter.php?text=%3Cb%3ETesT%3C%2Fb%3E
$textGet = strip_tags(urldecode($_GET['text']));
// after stripping we receive %3Cb%3ETesT%3C%2Fb%3E
echo $textGet;
// we see TesT (HTML not applied)


Un autre point vulnérable concerne les attributs "href" des liens. En fait, on peut y préciser les liens vers les pages précédés par le protocole HTTP, mais on peut également y mettre du texte encodé en base64. Cela peut permettre de surpasser les filtres qui, par exemple, ignorent tout le contenu qui concerne JavaScript ou qui contient les < et > . Voici le code de l'exploit :

<a href="data:text/html;base64,alert("JavaScript called");');?>">click on me</a>

Si l'on voudrait échapper ces caractères, on pourrait utiliser ceci :

// base64 exploit
$code = "data:text/html;base64, ".base64_encode('<script type="text/javascript">alert("JavaScript called");')."";
$accepted = array("http://", "ftp://");
if(preg_match("/^(http:\/\/|ftp:\/\/)(.*)$/i", $code, $match))
{
echo "Href parameter is correct";
}


Souvent les applications web sont confrontées à des attaques basées sur double encodage. Elle repose également sur le fait d'exploiter la faille du mauvais filtrage. La chaîne de caractères est alors encodée deux fois. Souvent le premier encodage la traduit en un autre format (par exemple ASCII en hexadécimale). La deuxième transformation change encore une fois les caractères traduits (par exemple % devient %25). Pour illustrer ces modifications, on peut regarder cet exemple :


This is a test

<b>This is a test</b>

%3C%62%3E%54%68%69%73%20%69%73%20%61%20%74%65%73%74%3C%2F%62%3E


Comment un attaquant pourrait utiliser cette technique pour mettre une application web en danger ? Comme dans la première situation, il peut contourner le mauvais ordre du système de filtrage. Dans un premier temps, l'application traduit les caractères en entités correspondantes. Ensuite elle échappe les balises HTML. A la fin elle affiche le résultat des transformations sur l'écran en décodant tous les caractères incompréhensibles par un humain. Voici le code de ce mauvais système de protection :
 
// We use the string This is a test for our examples
// String encoded one time
$encodedOnce = "<b>This is a test</b>";
// String encoded twice (= $encodedOnce encoded)
$encodedTwice = "%3C%62%3E%54%68%69%73%20%69%73%20%61%20%74%65%73%74%3C%2F%62%3E";
// It'll work; we'll see only This is a test, without bolder style.
echo urldecode(strip_tags(html_entity_decode($encodedOnce)));
// It won't work. We'll see This is a test, with bolder style.
$text = strip_tags(html_entity_decode($encodedTwice));
// Save into database...
// Get from the database and show
echo urldecode($text);


L'attaquant peut aller encore plus loin et rendre la protection plus complexe à élaborer. Il peut double encoder uniquement les caractères sensibles (<, / et >). Cela donnera "%253Cb%253EThis is a test%253C%252Fb%253E". Il faut alors modifier le système de filtrage, décoder d'abord les informations envoyées et à la fin appeler la méthode d'échappement.

// We use the same examples
$text = urldecode(html_entity_decode($encodedTwice));
echo strip_tags($text);


Les langages de programmation, leurs librairies et frameworks fournissent de bons outils de protection contre XSS. Cependant, il faut toujours rester vigilant et prévoir les scénarios des attaques potentielles. Juste pour (mais uniquement dans ce cas précis!) ne pas faire comme Microsoft ou Google.

L'article écrit en rythme de:

Slaï - Mizik
Bartosz KONIECZNY 25-12-2011 12:53 sécurité des applications web
Un conseil Symfony2

Comment récupérer le SecurityContext dans la vue ?

Dans Symfony2 on peut récupérer le SecurityContext directement dans les templates de vue.

Pour ce faire, utilisez la ligne suivante (s'applique seulement pour les templates PHP) :

$viewUser = $view->container->get('security.context')->getToken();