2008-10-15 8 views
19

Est-ce que quelqu'un a un moyen simple et efficace de vérifier qu'une chaîne ne contient pas de code HTML? Fondamentalement, je veux vérifier que certains champs contiennent uniquement du texte brut. J'ai pensé à la recherche du caractère <, mais cela peut facilement être utilisé en texte brut. Une autre façon peut-être de créer une nouvelle System.Xml.Linq.XElement en utilisant:Comment valider qu'une chaîne ne contient pas de code HTML en utilisant C#

XElement.Parse("<wrapper>" + MyString + "</wrapper>") 

et vérifiez que le XElement ne contient aucun élément enfant, mais cela semble un peu lourd pour ce que je dois.

+0

Pour ce faire, vous allez probablement devoir définir ce que vous entendez par « HTML » et « texte brut », par exemple: Allez-vous permettre à quelqu'un de mettre « » dans le texte, qui regarde * comme * un élément HTML mais n'est pas, et aussi, quels caractères autoriserez-vous .. – Rob

+0

Dans mon cas, je vais bien dire pas de balises du tout, donc ne serait pas autorisé. Mes utilisateurs sont un nombre limité d'employés qui entrent des produits sur le site Web de notre entreprise. Ils ont commencé à abuser un peu des champs et à inclure du HTML dans des champs qui n'étaient pas conçus pour contenir du HTML. –

Répondre

6

Je viens d'essayer ma solution XElement.Parse. J'ai créé une méthode d'extension de la classe de chaîne pour que je puisse réutiliser le code facilement:

public static bool ContainsXHTML(this string input) 
{ 
    try 
    { 
     XElement x = XElement.Parse("<wrapper>" + input + "</wrapper>"); 
     return !(x.DescendantNodes().Count() == 1 && x.DescendantNodes().First().NodeType == XmlNodeType.Text); 
    } 
    catch (XmlException ex) 
    { 
     return true; 
    } 
} 

Un problème que j'ai trouvé que esperluette texte brut et moins de caractères provoquent une XmlException et indiquent que le champ contient HTML (qui est faux). Pour corriger cela, la chaîne d'entrée transmise en premier doit avoir les esperluettes et moins que les caractères convertis en leurs entités XHTML équivalentes.J'ai écrit une autre méthode d'extension pour le faire:

public static string ConvertXHTMLEntities(this string input) 
{ 
    // Convert all ampersands to the ampersand entity. 
    string output = input; 
    output = output.Replace("&amp;", "amp_token"); 
    output = output.Replace("&", "&amp;"); 
    output = output.Replace("amp_token", "&amp;"); 

    // Convert less than to the less than entity (without messing up tags). 
    output = output.Replace("< ", "&lt; "); 
    return output; 
} 

Maintenant, je peux prendre une chaîne fournie par l'utilisateur et vérifier qu'il ne contient pas de HTML en utilisant le code suivant:

bool ContainsHTML = UserEnteredString.ConvertXHTMLEntities().ContainsXHTML(); 

Je ne suis pas sûr si c'est une preuve de balle, mais je pense que c'est assez bon pour ma situation.

+0

Vous vérifiez qu'il ne contient pas de XHTML. Vous ne vérifiez pas qu'il ne contient pas de code HTML, ce qui ne doit pas nécessairement être du format XML bien formé. En outre, votre code ne sera pas attraper "c'est XHTML". –

+0

En fait, le code HTML ancien qui n'est pas bien formé entraînera l'échec de la méthode XElement.Parse. Ma méthode suppose que l'échec de la méthode Parse signifie que la chaîne contient une forme de HTML. Je suppose que mon code recherche vraiment n'importe quelle forme de tags. –

+0

nous pouvons également utiliser regex patten, pour vérifier l'ouverture des étiquettes de fermeture. – bijayk

44

Ce qui suit correspond à tout ensemble de balises correspondant. à savoir < b> </b>

Regex tagRegex = new Regex(@"<\s*([^ >]+)[^>]*>.*?<\s*/\s*\1\s*>"); 

Ce qui suit correspond à aucun tag unique. c'est-à-dire < b> (il ne doit pas être fermé).

Regex tagRegex = new Regex(@"<[^>]+>"); 

Vous pouvez alors l'utiliser comme si

bool hasTags = tagRegex.IsMatch(myString); 
8

Ici, vous allez:

using System.Text.RegularExpressions; 
private bool ContainsHTML(string CheckString) 
{ 
    return Regex.IsMatch(CheckString, "<(.|\n)*?>"); 
} 

C'est la façon la plus simple, puisque les éléments entre crochets ne sont pas susceptibles de se produire naturellement.

2

Les cornières ne sont peut-être pas votre seul défi. D'autres caractères peuvent également être une injection de script potentiellement dangereux. Tels que le double trait d'union commun "-", qui peut également être utilisé dans l'injection SQL. Et il y en a d'autres.

Sur une page ASP.Net, si validateRequest = true dans machine.config, web.config ou la directive page, l'utilisateur recevra une page d'erreur indiquant "Une valeur Request.Form potentiellement dangereuse a été détectée sur le client" si une balise HTML ou d'autres attaques potentielles par injection de script sont détectées. Vous voulez probablement éviter cela et offrir une expérience d'interface utilisateur plus élégante et moins effrayante.

Vous pouvez tester les balises d'ouverture et de fermeture <> en utilisant une expression régulière, et autoriser le texte si un seul d'entre eux se produit. Autoriser < ou>, mais pas < suivi d'un texte, puis>, dans cet ordre.

Vous pouvez autoriser des chevrons et HtmlEncode le texte pour les conserver lorsque les données sont conservées.

+0

Si votre stratégie pour traiter l'injection SQL supprime "-" les entrées, vous avez un problème plus important. –

+1

Excellent point, Robert, mais je ne pensais pas que c'était l'endroit pour lancer une explication complète de la défense contre l'injection SQL, ou d'autres techniques d'injection de script. Ma première ligne de défense contre l'injection SQL utilise le SQL paramétré. Quel est ton? – DOK

20

Vous pouvez vous assurer du texte brut en codant l'entrée en utilisant HttpUtility.HtmlEncode.

En fait, selon la stricte que vous voulez que le chèque soit, vous pouvez l'utiliser pour déterminer si la chaîne contient HTML:

bool containsHTML = (myString != HttpUtility.HtmlEncode(myString)); 
+1

Une réponse simple mais efficace! –

+7

Malheureusement, cela ne fonctionne pas si votre chaîne contient des apostrophes, des esperluettes etc – PeteG

+0

@PeteG Bon point, oui, il semble qu'à partir de .NET 4 cette méthode encode plus de choses qu'auparavant, comme des guillemets simples. Cela rend cette technique moins utile. –

0

Prenez garde lors de l'utilisation de la méthode HttpUtility.HtmlEncode mentionnée ci-dessus. Si vous vérifiez du texte avec des caractères spéciaux, mais pas HTML, il évaluera incorrectement. Peut-être est-ce la raison pour laquelle J c a utilisé "... selon la rigueur que vous voulez que la vérification soit ..."

3

Ceci vérifie aussi des choses comme < br /> étiquettes auto-jointes avec espace blanc optionnel. la liste ne contient pas de nouvelles balises html5.

internal static class HtmlExts 
{ 
    public static bool containsHtmlTag(this string text, string tag) 
    { 
     var pattern = @"<\s*" + tag + @"\s*\/?>"; 
     return Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase); 
    } 

    public static bool containsHtmlTags(this string text, string tags) 
    { 
     var ba = tags.Split('|').Select(x => new {tag = x, hastag = text.containsHtmlTag(x)}).Where(x => x.hastag); 

     return ba.Count() > 0; 
    } 

    public static bool containsHtmlTags(this string text) 
    { 
     return 
      text.containsHtmlTags(
       "a|abbr|acronym|address|area|b|base|bdo|big|blockquote|body|br|button|caption|cite|code|col|colgroup|dd|del|dfn|div|dl|DOCTYPE|dt|em|fieldset|form|h1|h2|h3|h4|h5|h6|head|html|hr|i|img|input|ins|kbd|label|legend|li|link|map|meta|noscript|object|ol|optgroup|option|p|param|pre|q|samp|script|select|small|span|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|ul|var"); 
    } 
} 
Questions connexes