Attention, ça devient sérieux et ça rigole pas : on va parler sécurité !

Pour peu que vous vous soyiez un peu interressé au sujet, vous savez qu’il ne faut jamais faire confiance aux utilisateurs et controler tout ce qu’ils font. Si jamais vous faites partie de ces personnes qui ne s’en soucient pas le moins du monde, Asp.net vous protège quand même malgré vous, grâce au ValidateRequest. Bien que ne remplaçant pas une sécurisation correcte du code par le développeur, c’est quand même un formidable atout pour protéger les quelques endroits que vous auriez oublié de sécuriser. Le principe : chaque requête est analysée, et si l’une d’entre elle ressemble de près ou de loin à une tentative de piratage, le site renvoie une exception du style :

A potentially dangerous Request.Form value was detected from the client (login="<script>hahaha</scri...")

Cependant, bien que très pratique, cette protection peut s’avérer irritante pour certains, si par exemple on estime que l’utilisateur a le droit d’envoyer du code html sur le site. Dans ce cas, pas de soucis, on désactive le ValidateRequest dans la directive de la page :

<%@ Page Language="C#" ValidateRequest="false" %>

voire même dans le web.config pour les plus téméraires :

<pages validateRequest="false">	   
</pages>

Mais voilà le soucis, je suis totalement parano : je me suis vu obligé de désactiver le ValidateRequest pour que les administrateurs de mon site puissent faire leur boulot, mais il est hors de question que je le laisse les utilisateurs anonymes faire n’importe quoi !

Mon premier réflexe a donc été de vérifier par code si l’utilisateur était administrateur avant de décider si j’active ou désactive la sécurité… et déception : aucune propriété “ValidateRequest” dans ma page.

Un petit tour sur le msdn donc, et je tombe sur quelque chose d’interressant : HttpRequest.ValidateInput Method “Validates data submitted by a client browser and raises an exception if potentially dangerous data is present.” ça me plait bien, c’est justement ce que je veux. Je désactive donc le ValidateRequest, et j’appelle cette méthode par code… et là re-déception. Tout semble correct, et pourtant quand je balance un script javascript, ça passe comme si de rien n’était.

Pour comprendre, je vais faire un petit tour dans Reflector, et quelle n’est pas ma surprise de voir ça :

public void ValidateInput()
{
   this._flags.Set(1);
   this._flags.Set(2);
   this._flags.Set(4);
   this._flags.Set(0x40);
}

Au lieu de valider ma requête comme je m’y attendais, cette méthode se contente de modifier un flag. Il s’avère qu’en fait la validation ne s’effectue pas lors de l’appel du ValidateInput, mais lorsque l’on essaie d’acceder à notre HttpRequest. Il suffit donc pour sécuriser notre application de lire dans Request après avoir fait le ValidateInput. Ce qui nous donne quelque chose comme ça (En ayant pris soin auparavant de désactiver le ValidateRequest dans la page) :

protected void Page_Load(object sender, EventArgs e)
{
   if (!Context.User.IsInRole("administrateur"))
   {
       try
       {
           // on flague le Request
            Request.ValidateInput();
           // on lit un objet qui n'existe pas, juste pour lancer la validation
            object forceValidation = Request["ForceValidation"];
       }
       catch
       {
           // on tombe ici si la requête est suspecte
            throw;
       }
   }
}

En espérant que ça vous sera aussi utile qu’à moi !