在我的 J2EE/java 代码的一部分中,我对 的输出进行了 URLEncoding 以对其getRequestURI()
进行清理以防止 XSS 攻击,但 Fortify SCA 认为验证很差。
为什么?
关键是您需要将 HTML 特殊字符转换为 HTML 实体。这也称为“HTML 转义”或“XML 转义”。基本上,字符、<
、>
和"
需要替换为、、&
和。'
<
>
"
&
'
URL 编码不这样做。URL 编码将 URL 特殊字符转换为百分比编码值。这不是 HTML 转义。
在 Web 应用程序的情况下,HTML 转义通常在视图端完成,正是在那里您重新显示用户控制的输入。对于 Java EE Web 应用程序,这取决于您使用的视图技术。
如果 webapp 使用现代 Facelets 视图技术,那么您不需要自己转义它。Facelets 已经隐含地做到了这一点。
如果 webapp 使用旧的 JSP 视图技术,那么您需要确保使用 JSTL<c:out>
标记或fn:escapeXml()
函数来重新显示用户控制的输入。
<c:out value="${bean.foo}" />
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
如果 web 应用程序非常陈旧或设计不佳,并且使用 servlet 或scriptlet来打印 HTML,那么您的问题就更大了。没有内置标签或函数,更不用说可以转义 HTML 实体的 Java 方法了。您应该escape()
自己编写一些方法或为此使用 Apache Commons Lang StringEscapeUtils#escapeHtml()
。然后,您需要确保在打印用户控制输入的任何地方都使用它。
out.print("<p>" + StringEscapeUtils.escapeHtml(request.getParameter("foo")) + "</p>");
更好的办法是重新设计旧的 web 应用程序以使用带有 JSTL 的 JSP。
URL 编码不会影响某些重要字符,包括单引号 ( '
) 和括号,因此 URL 编码将通过不变的某些有效负载。
例如,
onload'alert(String.fromCharCode(120))'
某些浏览器会将其视为有效属性,当注入标签时会导致代码执行。
避免 XSS 的最佳方法是将所有不受信任的输入视为纯文本,然后在编写输出时,将所有纯文本正确编码为输出的适当类型。
如果您想过滤输入作为额外的安全层,请确保您的过滤器将所有引号(包括反引号)和括号视为可能的代码,并禁止它们,除非该输入有意义。