提问人:Thierry Roy 提问时间:8/24/2008 最后编辑:CommunityThierry Roy 更新时间:11/13/2022 访问量:98679
捕获 XSS(跨站点脚本)攻击的最佳正则表达式(在 Java 中)?
Best regex to catch XSS (Cross-site Scripting) attack (in Java)?
问:
Jeff 实际上在 Sanitize HTML 中发布了有关此内容的信息。但他的例子是用 C# 编写的,我实际上对 Java 版本更感兴趣。有没有人有更好的 Java 版本?他的示例是否足够好,可以直接从 C# 转换为 Java?
[更新]我对这个问题给予了赏金,因为当我问这个问题时,SO 并不像今天那样受欢迎 (*)。至于任何与安全有关的事情,研究得越多越好!
(*)事实上,我认为它仍处于封闭测试阶段
答:
使用 jeffs 代码的最大问题是目前不可用的 @。
如果需要,我可能会从 jeffs 代码中获取“原始”正则表达式并将其粘贴到
http://www.cis.upenn.edu/~matuszek/General/RegexTester/regex-tester.html
看到需要逃脱的东西被逃脱,然后使用它。
考虑到这个正则表达式的使用,我个人会确保我确切地理解我在做什么,为什么以及如果我没有成功会有什么后果,在复制/粘贴任何东西之前,就像其他答案试图帮助你一样。
(对于任何复制/粘贴来说,这都是相当合理的建议)
我不相信使用正则表达式是查找所有可疑代码的最佳方法。正则表达式很容易被欺骗,尤其是在处理损坏的 HTML 时。例如,“清理 HTML”链接中列出的正则表达式将无法删除所有在元素名称和属性“href”之间具有属性的“a”元素:
< alt=“xss 注入” href=“http://www.malicous.com/bad.php” >
删除恶意代码的一种更可靠的方法是依赖于 XML 解析器,该解析器可以处理所有类型的 HTML 文档(Tidy、TagSoup 等),并使用 XPath 表达式选择要删除的元素。一旦 HTML 文档被解析为 DOM 文档,就可以轻松安全地找到要 revome 的元素。使用 XSLT 甚至很容易做到这一点。
评论
不要使用正则表达式执行此操作。请记住,您不仅仅是在保护有效的 HTML;您正在防止 Web 浏览器创建的 DOM。浏览器可以很容易地被欺骗从无效的 HTML 生成有效的 DOM。
例如,请参阅此混淆 XSS 攻击列表。您是否准备好定制正则表达式来防止 IE6/7/8 上对 Yahoo 和 Hotmail 的这种真实世界攻击?
<HTML><BODY>
<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time">
<?import namespace="t" implementation="#default#time2">
<t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert("XSS")</SCRIPT>">
</BODY></HTML>
这种在IE6上有效的攻击怎么样?
<TABLE BACKGROUND="javascript:alert('XSS')">
本网站上未列出的攻击怎么办?Jeff 方法的问题在于,它不像声称的那样是白名单。正如该页面上的某个人熟练地指出的那样:
它的问题是 html 必须干净。在某些情况下, 你可以传入被黑的 HTML,它 不会匹配它,在这种情况下它会 返回被黑的 HTML 字符串,因为它 不会匹配任何要替换的东西。这 不是严格意义上的白名单。
我建议使用像 AntiSmy 这样的专用工具。它的工作原理是实际解析 HTML,然后遍历 DOM 并删除任何不在可配置白名单中的内容。主要区别在于能够优雅地处理格式错误的 HTML。
最好的部分是它实际上对上述站点上的所有 XSS 攻击进行了单元测试。此外,还有什么比这个 API 调用更容易的:
public String toSafeHtml(String html) throws ScanException, PolicyException {
Policy policy = Policy.getInstance(POLICY_FILE);
AntiSamy antiSamy = new AntiSamy();
CleanResults cleanResults = antiSamy.scan(html, policy);
return cleanResults.getCleanHTML().trim();
}
评论
[\s\w\.]*
.如果不匹配,则表示您有 XSS。或。请注意,此表达式只允许使用字母、数字和句点。出于对 XSS 的恐惧,它避免了所有符号,甚至是有用的符号。一旦你允许&,你就有烦恼了。仅仅用 & 替换所有实例是不够的。太复杂了,不能相信:P。显然,这将禁止大量合法文本(您可以用 ! 或其他东西替换所有不匹配的字符),但我认为它会杀死 XSS。&
将其解析为 html 并生成新 html 的想法可能会更好。
^(\s|\w|\d|<br>)*?$
这将验证字符、数字、空格以及标签。
如果您想要更多风险,可以添加更多标签,例如<br>
^(\s|\w|\d|<br>|<ul>|<\ul>)*?$
我从NoScript中提取了最好的Anti-XSS插件,这是它的正则表达式: 完美无瑕的工作:
<[^\w<>]*(?:[^<>"'\s]*:)?[^\w<>]*(?:\W*s\W*c\W*r\W*i\W*p\W*t|\W*f\W*o\W*r\W*m|\W*s\W*t\W*y\W*l\W*e|\W*s\W*v\W*g|\W*m\W*a\W*r\W*q\W*u\W*e\W*e|(?:\W*l\W*i\W*n\W*k|\W*o\W*b\W*j\W*e\W*c\W*t|\W*e\W*m\W*b\W*e\W*d|\W*a\W*p\W*p\W*l\W*e\W*t|\W*p\W*a\W*r\W*a\W*m|\W*i?\W*f\W*r\W*a\W*m\W*e|\W*b\W*a\W*s\W*e|\W*b\W*o\W*d\W*y|\W*m\W*e\W*t\W*a|\W*i\W*m\W*a?\W*g\W*e?|\W*v\W*i\W*d\W*e\W*o|\W*a\W*u\W*d\W*i\W*o|\W*b\W*i\W*n\W*d\W*i\W*n\W*g\W*s|\W*s\W*e\W*t|\W*i\W*s\W*i\W*n\W*d\W*e\W*x|\W*a\W*n\W*i\W*m\W*a\W*t\W*e)[^>\w])|(?:<\w[\s\S]*[\s\0\/]|['"])(?:formaction|style|background|src|lowsrc|ping|on(?:d(?:e(?:vice(?:(?:orienta|mo)tion|proximity|found|light)|livery(?:success|error)|activate)|r(?:ag(?:e(?:n(?:ter|d)|xit)|(?:gestur|leav)e|start|drop|over)?|op)|i(?:s(?:c(?:hargingtimechange|onnect(?:ing|ed))|abled)|aling)|ata(?:setc(?:omplete|hanged)|(?:availabl|chang)e|error)|urationchange|ownloading|blclick)|Moz(?:M(?:agnifyGesture(?:Update|Start)?|ouse(?:PixelScroll|Hittest))|S(?:wipeGesture(?:Update|Start|End)?|crolledAreaChanged)|(?:(?:Press)?TapGestur|BeforeResiz)e|EdgeUI(?:C(?:omplet|ancel)|Start)ed|RotateGesture(?:Update|Start)?|A(?:udioAvailable|fterPaint))|c(?:o(?:m(?:p(?:osition(?:update|start|end)|lete)|mand(?:update)?)|n(?:t(?:rolselect|extmenu)|nect(?:ing|ed))|py)|a(?:(?:llschang|ch)ed|nplay(?:through)?|rdstatechange)|h(?:(?:arging(?:time)?ch)?ange|ecking)|(?:fstate|ell)change|u(?:echange|t)|l(?:ick|ose))|m(?:o(?:z(?:pointerlock(?:change|error)|(?:orientation|time)change|fullscreen(?:change|error)|network(?:down|up)load)|use(?:(?:lea|mo)ve|o(?:ver|ut)|enter|wheel|down|up)|ve(?:start|end)?)|essage|ark)|s(?:t(?:a(?:t(?:uschanged|echange)|lled|rt)|k(?:sessione|comma)nd|op)|e(?:ek(?:complete|ing|ed)|(?:lec(?:tstar)?)?t|n(?:ding|t))|u(?:ccess|spend|bmit)|peech(?:start|end)|ound(?:start|end)|croll|how)|b(?:e(?:for(?:e(?:(?:scriptexecu|activa)te|u(?:nload|pdate)|p(?:aste|rint)|c(?:opy|ut)|editfocus)|deactivate)|gin(?:Event)?)|oun(?:dary|ce)|l(?:ocked|ur)|roadcast|usy)|a(?:n(?:imation(?:iteration|start|end)|tennastatechange)|fter(?:(?:scriptexecu|upda)te|print)|udio(?:process|start|end)|d(?:apteradded|dtrack)|ctivate|lerting|bort)|DOM(?:Node(?:Inserted(?:IntoDocument)?|Removed(?:FromDocument)?)|(?:CharacterData|Subtree)Modified|A(?:ttrModified|ctivate)|Focus(?:Out|In)|MouseScroll)|r(?:e(?:s(?:u(?:m(?:ing|e)|lt)|ize|et)|adystatechange|pea(?:tEven)?t|movetrack|trieving|ceived)|ow(?:s(?:inserted|delete)|e(?:nter|xit))|atechange)|p(?:op(?:up(?:hid(?:den|ing)|show(?:ing|n))|state)|a(?:ge(?:hide|show)|(?:st|us)e|int)|ro(?:pertychange|gress)|lay(?:ing)?)|t(?:ouch(?:(?:lea|mo)ve|en(?:ter|d)|cancel|start)|ime(?:update|out)|ransitionend|ext)|u(?:s(?:erproximity|sdreceived)|p(?:gradeneeded|dateready)|n(?:derflow|load))|f(?:o(?:rm(?:change|input)|cus(?:out|in)?)|i(?:lterchange|nish)|ailed)|l(?:o(?:ad(?:e(?:d(?:meta)?data|nd)|start)?|secapture)|evelchange|y)|g(?:amepad(?:(?:dis)?connected|button(?:down|up)|axismove)|et)|e(?:n(?:d(?:Event|ed)?|abled|ter)|rror(?:update)?|mptied|xit)|i(?:cc(?:cardlockerror|infochange)|n(?:coming|valid|put))|o(?:(?:(?:ff|n)lin|bsolet)e|verflow(?:changed)?|pen)|SVG(?:(?:Unl|L)oad|Resize|Scroll|Abort|Error|Zoom)|h(?:e(?:adphoneschange|l[dp])|ashchange|olding)|v(?:o(?:lum|ic)e|ersion)change|w(?:a(?:it|rn)ing|heel)|key(?:press|down|up)|(?:AppComman|Loa)d|no(?:update|match)|Request|zoom))[\s\0]*=
测试:http://regex101.com/r/rV7zK8
我认为它阻止了 99% 的 XSS,因为它是 NoScript 的一部分,NoScript 是一个定期更新的插件
评论
javascript:
一个旧线程,但也许这对其他用户有用。有一个用于 php 的维护安全层工具: https://github.com/PHPIDS/ 它基于一组正则表达式,您可以在此处找到该正则表达式:
https://github.com/PHPIDS/PHPIDS/blob/master/lib/IDS/default_filter.xml
这个问题完美地说明了计算理论研究的一个很好的应用。计算理论是一个专注于产生和研究用于计算的数学表示的领域。
计算理论中一些最深刻的研究包括说明各种语言关系的证明。
计算理论家已经证明的一些语言关系包括:
这表明上下文无关语言严格比常规语言更强大。因此,如果一种语言是显式的、与上下文无关的(与上下文无关且不规则),那么任何正则表达式都不可能识别它。
JavaScript 至少是与上下文无关的,因此我们百分之百地知道,设计一个能够捕获所有 XSS 的正则表达式(正则表达式)在数学上是一项不可能完成的任务。
对于 java,我使用了以下带有 replaceAll 的正则表达式,并为我工作
value.replaceAll("(?i)(\\b)(on\\S+)(\\s*)=|javascript:|(<\\s*)(\\/*)script|style(\\s*)=|(<\\s*)meta", "");
添加了 (?i) 以忽略字母的大小写。
public String validate(String value) {
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a src='...' type of expression
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a src="..." type of expression
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything in a src=... type of expression added because quotes are not necessary
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*(.*?)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...) expressions
scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid onload= expressions
scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything between script tags added - paranoid regex. note: if testing local PREP this must be commented
scriptPattern = Pattern.compile("<(.*?)[\r\n]*(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything between script tags added - paranoid regex
scriptPattern = Pattern.compile("<script(.*?)[\r\n]*(.*?)/script>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything between * tags like *(alert)* added
scriptPattern = Pattern.compile("\\*(.*?)[\r\n]*(.*?)\\*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid anything between + tags like +(alert)+ added
scriptPattern = Pattern.compile("\\+(.*?)[\r\n]*(.*?)\\+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Prohibit lines containing = (...) added
scriptPattern = Pattern.compile("=(.*?)\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// removing href link
scriptPattern = Pattern.compile("(?i)<[\\s]*[/]?[\\s]*a[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
//Avoid alert
scriptPattern = Pattern.compile("alert", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("[^\\dA-Za-z ]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
return value;
}
评论