编码HTML的正则表达式

时间:2009-07-17 13:40:46

标签: html regex validation sanitization html-encode

我想创建一个匹配包含href属性的开始<a>标记的正则表达式:

<a href="doesntmatter.com">

它应匹配上述内容,但在添加其他属性时不匹配:

<a href="doesntmatter.com" onmouseover="alert('Do something evil with Javascript')">

通常情况下这很简单,但HTML是经过编码的。所以编码上面的两个,我需要正则表达式来匹配这个:

&#60;a href&#61;&#34;doesntmatter.com&#34; &#62;

但不符合这个:

&#60;a href&#61;&#34;doesntmatter.com&#34; onmouseover&#61;&#34;alert&#40;&#39;do something evil with javascript.&#39;&#41;&#34; &#62;

假设所有编码的HTML都是“有效的”(没有奇怪的格式错误的XSS技巧),并假设我们不需要遵循任何HTML清理最佳实践。我只需要与A)相匹配的最简单的正则表达式而不是B)。

谢谢!

3 个答案:

答案 0 :(得分:2)

首先想到的正则表达式为/<a href=".*?">/;惰性表达式(.*?)可用于匹配引号之间的字符串。但是,正如评论中所指出的那样,因为正则表达式由&gt;锚定,所以它也会匹配无效标记,因为仍然会进行匹配。

为了解决此问题,您可以使用atomic grouping。原子分组告诉正则表达式引擎,“一旦你找到了这个组的匹配,接受它” - 这将解决正则表达式返回的问题,并在找不到&gt;后匹配第二个字符串。一个href的结尾。具有原子组的正则表达式如下所示:

/<a (?>href=".*?")>/

使用HTML实体替换字符时,如下所示:

/&#60;a (?>href&#61;&#34;.*?&#34;)&#62;/

答案 1 :(得分:1)

喂!我最近不得不做类似的事情。我建议首先解码html然后尝试获取你想要的信息。这是我在C#中的解决方案:

private string getAnchor(string data)
    {
        MatchCollection matches;
        string pattern = @"<a.*?href=[""'](?<href>.*?)[""'].*?>(?<text>.*?)</a>";
        Regex myRegex = new Regex(pattern, RegexOptions.Multiline);
        string anchor = "";

        matches = myRegex.Matches(data);

        foreach (Match match in matches)
        {
            anchor += match.Groups["href"].Value.Trim() + "," + match.Groups["text"].Value.Trim();
        }

        return anchor;
    }

我希望有所帮助!

答案 2 :(得分:0)

我不知道一个人与另一个人有什么不同?你只是在寻找你刚才所写的内容,使doesntmatter.com部分成为你捕获的部分。我想匹配任何内容,直到&#34;(不是&quot;?)会出现问题,但你在正则表达式中这样做:

  

(?:(?!&#34;).)*

它实质上意味着:

  • 将以下组匹配0次或更多次
    • 如果以下字符串为"&#34;"
    • ,则匹配失败
    • 匹配任何字符(新行除外,除非指定DOTALL)

完整的正则表达式为:

/&#60;a href&#61;&#34;(?>(?:[^&]+|(?!&#34;).)*)&#34;&#62;/s

这比使用非贪婪表达更有效。

感谢Daniel Vandersluis提醒我the atomic group!为了优化,它非常适合这种情况(如果必须回溯,这种模式永远不会匹配。)

我还投入了一个额外的[^&]+组,以避免重复多次负面预测。

或者,可以使用possessive quantifier,它基本上做同样的事情(你的正则表达式引擎可能不支持它):

/&#60;a href&#61;&#34;(?:[^&]+|(?!&#34;).)*+&#34;&#62;/s

正如您所看到的那样稍微更短。