2009-10-07 4 views
2

J'essaie d'écrire une fonction regex pour supprimer les attributs onclick (aussi onload, onmouseover etc.) des éléments HTML. Je veux faire cela du côté du serveur avant que le HTML soit envoyé au client.Regex pour supprimer les attributs onclick = "" des éléments HTML dans ASP.NET C# (côté serveur)

J'ai du contenu provenant d'un éditeur de texte enrichi et affiché à l'écran dans un div, et je veux protéger contre XSS (Cross Site Scripting). Évidemment je ne peux pas l'encoder en HTML en utilisant Server.HtmlEncode() parce que le texte riche stocke le texte en tant que balisage HTML, donc j'utilise une approche blacklisting, en recherchant certains éléments tels que <script> et <style>. Je suis maintenant essayer de chercher onclick, attributs onmouseover etc., jusqu'à présent, je donne les résultats suivants:

returnVal = Regex.Replace(returnVal, @"\<(.*?)(\ on[a-z]+\=\""?.*?\""?)*(.*?)\>", 
       "<$1 $3>", RegexOptions.Singleline | RegexOptions.IgnoreCase); 

... qui ne fonctionne pas, et je l'ai essayé quelques variations. Fondamentalement, je veux pour que ...

<p style="font-style: italic" onclick="alert('hacked!!');">Hello World</p> 

... voit transformée en

<p style="font-style: italic">Hello World</p> 

Toutes les idées? À votre santé!

+0

avez-vous vu ici: http://refactormycode.com/codes/333-sanitize-html? – AndreasKnudsen

Répondre

2

Essayez cette regex:


returnValue = 
    Regex.Replace(
     returnValue, 
     @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", 
     delegate(Match match) 
     { 
      return String.Concat(match.Groups[1].Value, match.Groups[3].Value); 
     }, RegexOptions.Compiled | RegexOptions.IgnoreCase); 

HTH

+0

WOW! Presque parfait sauf si l'attribut onclick apparaît deux fois dans un seul élément, cela n'enlèvera que l'un d'entre eux. J'ai bloqué ce code dans une boucle while en utilisant Regex.IsMatch (avec votre expression et cela semble fonctionner.) Je posterai le code dans un article séparé dans cette question, car les exemples de code ne sortent pas très bien dans ces commentaires –

+0

Oubliez-vous de dire, merci beaucoup !! –

0

Ceci est une réponse à la réponse Rubens Farias avec l'exemple de code, je suis venu avec. J'ai utilisé une boucle while comme si ...

while (Regex.IsMatch(returnVal, @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", RegexOptions.Compiled | RegexOptions.IgnoreCase)) 
{ 
    returnVal = Regex.Replace(returnVal, @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", 
        delegate(Match match) 
        { 
         return String.Concat(match.Groups[1].Value, match.Groups[3].Value); 
        }, RegexOptions.Compiled | RegexOptions.IgnoreCase); 
} 

Pour les intéressés, voici toute la méthode que je utilise pour protéger contre les attaques XSS ...

/// <summary> 
///  'Helps' protect against XSS (Cross Site Scripting attacks) by stripping out known evil HTML elements 
///  such as script and style. Used for outputing text generated by a Rich Text Editor. Doesn't HTML encode! 
/// </summary> 
/// <param name="input">Input string to strip bad HTML elements from</param> 
public static string XSSProtect(string input) 
{ 
    string returnVal = input ?? ""; 

    returnVal = Regex.Replace(returnVal, @"\<script(.*?)\>(.*?)\<\/script(.*?)\>", "", RegexOptions.Singleline | RegexOptions.IgnoreCase); 
    returnVal = Regex.Replace(returnVal, @"\<style(.*?)\>(.*?)\<\/style(.*?)\>", "", RegexOptions.Singleline | RegexOptions.IgnoreCase); 

    while (Regex.IsMatch(returnVal, @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", RegexOptions.Compiled | RegexOptions.IgnoreCase)) 
    { 
     returnVal = Regex.Replace(returnVal, @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", 
         delegate(Match match) 
         { 
          return String.Concat(match.Groups[1].Value, match.Groups[3].Value); 
         }, RegexOptions.Compiled | RegexOptions.IgnoreCase); 
    } 

    return returnVal; 
} 
+0

Je dois avouer que je suis un peu nerveux avec cette approche, y at-il une situation où cela pourrait se retrouver dans une boucle infinie? –

+0

Je ne suis pas à l'aise aussi, vous aussi devrait ajouter un symbole supplémentaire \ s * after et before =, en évitant onclick = "alert()" –

1

Vous pouvez stocker l'ancien valeur de retour, puis faire un chèque dans la boucle while pour voir si rien n'a changé si oui sortir de la boucle

if(oldContent.Equals(newContent)) { break; } 
0

comme ça.

if (!String.prototype.replaceAll) { 
 
    (function() { 
 
    String.prototype.replaceAll = function(target, replacement) { 
 
     return this.split(target).join(replacement); 
 
    }; 
 
    })(); 
 
}; 
 

 
html = html.replaceAll(/onclick.*?\=(['""])[\s\S]*(['""])/ig,""); 
 
console.log(html);

Résultat: <p style="font-style: italic">Hello World</p>