Archive pour la catégorie ‘ASP.NET’

Sécurité : Cross-Site Request Forgery (CSRF/XSRF)

10 juin 2007

Le magazine 01informatique vient de sortir un dossier complet sur la sécurité dans les sites AJAX (http://www.01net.com/01informatique/). Ayant entendu le teaser à la radio (les développeurs ont négligé la sécurité !! oh mon dieu), je m’attendais à un article pour pinpins basé sur des vérités générales. Je dois avouer que j’ai été surpris de la qualité avec laquelle le dossier a été traité. Il ont même réussi à me faire peur et j’ai repassé dans ma tête tous les sites web que j’ai pu développer en me posant cette question : sont-ils sécurisés, y’a t-il des failles ?

Je me suis toutefois rassuré rapidement, ASP.NET est loin d’être un gruyère et j’ai toujours appliqué les grands principes de sécurité du Web :

  • vérifier toutes les saisies utilisateurs (Cross-Site Scripting, SQL Injection, Overflow)
  • faire attention à tout Cookie, les crypter si nécessaire
  • limiter la surface d’exposition des API publiques (WS, Ajax, GET, etc.)
  • utiliser des ID temporaires (token ou ticket), casser les séquences (IDENTITY)

Cependant, j’ai été interpellé dans l’article par une technique de piratage appelée : Cross-Site Request Forgery (CSRF ou XSRF pour les intimes). Ne connaissant pas cette technique, j’ai donc fait quelques recherches pour me documenter et je me suis monté un petit lab pour voir comment l’utiliser (et la contourner).

Je ne vais pas décrire dans le détail l’histoire et la description de cette faille donc je laisse la main a des spécialistes pour cette partie : http://www.cgisecurity.com/articles/csrf-faq.shtml

Le principe, c’est qu’une page, un site tiers, un mail, un document, etc. exécute une requête vers le site à pirater en utilisant l’identité « reconnue » de l’utilisateur. Cela paraît simple sur le papier mais bien évidemment il faut réunir de nombreuses circonstances pour réussir son coup. La principale étant que le site à pirater doit baser son authentification sur un cookie persistant.

Démonstration : Sur mon site, j’expose une fonctionnalité. On va prendre la plus simple à détourner, le GET : http://lab.djeepy1.net/CSRF/default.aspx?action=achat&article=123456. Supposons que dans le code behind, je vérifie uniquemement la présence d’un cookie pour sécuriser l’action.

if (Request.Cookies["UserId"] != null)
{
    //on considère que l'utilisateur est OK
    BusinessLayer.ShoppingMgr.Buy(Helper.Decrypt(Request.Cookies["UserId"].Value), Request["ArticleId"]);
}

Le site tiers a juste à faire une requête, mais comment peut-il récupèrer la bonne valeur de cookie ? Avec un Cross-Site Scripting (XSS) classique mais pour cela il doit pouvoir exécuter du Javascript sur votre site (cf. règle n° 1 plus haut). L’autre moyen est à la base du Cross-Site Request Forgery : on s’arrange pour que cette requête soit exécutée depuis le navigateur de l’utilisateur, ainsi, les cookies sont automatiquement envoyés au site à pirater avec la fausse requête. Par exemple, on vous envoie un message sur votre webmail avec une image pointant sur la fonctionnalité GET. Vous ne voyez qu’une image « cassée » et pourtant, l’action a eu lieu sur l’autre site.

<img src="http://site/?action=XX"/>

Pourquoi donc Ajax est-il pointé du doigt ? Cette faille est vieille comme le web (1998) mais très difficilement exploitable dans un monde fondé sur les Postback. Avec Ajax, de nombreuses API s’exposent sans pudeur sur le Web, bien souvent accessibles avec un simple GET.

Comment sécuriser son site ? Vérifiez toute l’API exposée et vérifiez que vous n’utilisez pas de cookie persistant pour authentifier une requête ou tout du moins que TOUTE votre sécurité ne soit pas basée sur cet unique moyen. Les Sessions ASP.NET sont protégées de cette faille car elles se basent sur un cookie dit « de session » (temporaire et lié à la navigation).

Cette faille fait la une car on assiste depuis quelques temps à un nouveau type de site Web : le site composite (ou mashup). Un site composite est un assemblage de modules provenant de différents autres sites. Exemple : mes dernières enchères depuis ebay, mes news depuis MSN, ma météo depuis meteoconsult et mon site de chat depuis googletalk. Tout étant exécuté avec le même contexte, un module peut potentiellement exploiter les fonctionnalités d’un autre (via son API Javascript). 

En conclusion, ne cédez pas à la panique et suivez les conseils suivants (qui s’appliquent même au dela de l’informatique) :

  • quels sont les risques (mobile du crime, conséquences) ?
  • quelles sont les failles (ouvertures, exposition) ?
  • comment je souhaite me protéger de ces risques ?

Pour cela, prévoyez toujours une phase d’audit de votre site web avant la mise en production.

Afficher un titre sous la forme d’une image en CSS

30 mai 2007

Tout développeur de site web a été confronté à cette problématique et la réponse technique que l’on rencontre dans 99% des cas est de mettre un tag <img />. Cela répond certes à la problématique mais ce n’est en aucun cas bulletproof[1] et ne respecte pas les rudiments du web design.

En effet, les moteurs de recherche ne considèreront pas comme pertinente l’information, les outils d’accessibilité risquent d’être perdus et votre code HTML peut devenir vite inmaintenable avec cette forme de conception. Comment faire pour palier à ces problématiques ? Un webdesigner vous répondra : CSS biensur ! Et je ferai la même réponse.

Repartons du début :

  1. Toujours commencer par trouver la sémantique correcte. Pour un titre, on met un tag <h1/> (ou h2, etc.)
  2. on met le titre de façon TEXTUELLE pour être compris par les outils donc <h1 id="maintitle">ici mon super titre</h1>
  3. l’image est décorative donc on la met dans le style. Dans votre CSS, vous aurez
    #maintitle { background:url(title.gif) ; }
  4. à ce stade, tout semble correct sauf que le texte apparait au dessus de l’image, il faut donc le faire disparaître. Il existe 2 solutions.
  5. 1ère solution (la plus élégante) : mettre un tag dit technique pour faire disparaître le texte. Le HTML devient <h1 id="maintitle"><span>ici mon super titre<span></h1>.
    Ensuite, il suffit de faire disparaître le <span> en CSS : #maintitle span {visibility:hidden[2] ;}
    Attention : vous aurez certainement des problèmes de padding à régler.
  6. 2ème solution (à proscrire mais bon) : on a pas besoin du span et on décale le texte pour le faire sortir de la fenêtre #maintitle { text-indent:99999px; } 

[1]: j’adore ce terme et vous le trouverez souvent dans mes propos (au même titre que le très fameux : « ça poutre »)
[2]: on peut utiliser un display:none mais la taille du rendu du h1 devient minuscule (voire invisible); visibility:hidden permet de garde la taille que le texte aurait pris