如何在JSP/Servlet Web应用程序中防止XSS攻击?
<c:out>
标签或fn:escapeXml()
EL函数来防止XSS攻击,当重新显示用户控制的输入时。这包括请求参数、头部、Cookie、URL、正文等从请求对象中提取的任何内容。此外,需要在重新显示时对存储在数据库中的先前请求的用户控制输入进行转义。<p><c:out value="${bean.userControlledValue}"></p>
<p><input name="foo" value="${fn:escapeXml(param.foo)}"></p>
<
、>
、"
、'
和&
,转换为HTML/XML实体,如<
、>
、"
、'
和&
。&
变成&amp;
而不是&
,最终用户将看到&
被呈现),或者数据库存储的数据变得不可移植(例如,当将数据导出为JSON、CSV、XLS、PDF等格式时,根本不需要进行HTML转义)。您还将失去社交控制,因为您不再知道用户实际填写了什么。作为站点管理员,您真的想知道哪些用户/IP正在尝试执行XSS攻击,以便您可以轻松跟踪它们并采取相应的措施。只有在您确实需要尽快修复糟糕开发的遗留Web应用程序时,才应该在请求处理过程中进行转义。但是,最终您应该重写JSP文件以确保防止XSS攻击。<c:out>
之类的“转义”术语涉及到完全不同的事情。HTML消毒器基本上会清理包含可能恶意HTML的字符串,以便将其用作安全HTML 而无需转义。也就是说,当您实际上打算将用户控制的输入直接解释为HTML时,包括<div>
、<p>
、<img>
等标签。HTML转义器基本上会阻止它们被解释,以便它们显示为纯文本。换句话说,您根本不需要预先消毒任何您已经打算转义的HTML。PreparedStatement
而不是Statement
。在JPA术语中,请使用Query
。
<c:out>
和相关内容。还可以参考JSF中的CSRF、XSS和SQL注入攻击预防措施。<div><c:out value="${htmlContent}" escapeXml="false" /></div>
,这里的htmlContent
值类似于<span><h1>Hi</h1></span>
(此值来自数据库),现在如果我从c:out
中删除escapeXml="false"
,则它将按原样显示在页面上,但是如果保留escapeXml="false"
,则它将正确解析dom对象,但是当我的htmlContent包含一些脚本代码时,xss问题就会出现。 - Venkaiah Yepuri我在所有的Spring Controllers上使用OWASP Anti-Samy和一个AspectJ advisor,成功地阻止了跨站脚本攻击(XSS)。
public class UserInputSanitizer {
private static Policy policy;
private static AntiSamy antiSamy;
private static AntiSamy getAntiSamy() throws PolicyException {
if (antiSamy == null) {
policy = getPolicy("evocatus-default");
antiSamy = new AntiSamy();
}
return antiSamy;
}
public static String sanitize(String input) {
CleanResults cr;
try {
cr = getAntiSamy().scan(input, policy);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cr.getCleanHTML();
}
private static Policy getPolicy(String name) throws PolicyException {
Policy policy =
Policy.getInstance(Policy.class.getResourceAsStream("/META-INF/antisamy/" + name + ".xml"));
return policy;
}
}
你可以从这篇stackoverflow帖子中获取AspectJ顾问。如何防止 XSS 已被多次询问。您可以在 StackOverflow 上找到许多信息。此外,OWASP 网站有一个 XSS 预防备忘单,建议您仔细阅读。
关于要使用的库,OWASP 的 ESAPI 库 有一个 Java 版本。建议尝试一下。此外,您使用的每个框架都有一些防止 XSS 的保护措施。同样,OWASP 网站提供了大部分流行框架的信息,因此我建议您浏览他们的网站。
没有一种简单的、开箱即用的解决XSS的方案。OWASP ESAPI API在转义方面提供了一些非常有用的支持,并且他们有标签库。
我的方法基本上是通过以下方式扩展stuts 2标签。
如果您不想修改步骤1中的类,则另一种方法是将ESAPI标签导入到freemarker模板中,并根据需要进行转义。然后,如果您需要在JSP中使用s:property标签,请使用ESAPI标签进行包装。
我在这里写了一个更详细的解释。
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
我同意转义输入并不理想。
...
<c:forEach items="${orders}" var="item">
<p>${item.name}</p>
<p>${item.price}</p>
<p>${item.description}</p>
</c:forEach>
...
<enhance:out escapeXml="false">
中。 - Brad Parks$
运算符不会受到XSS攻击,您可以实现ServletContextListener
并在那里进行一些检查。@WebListener
public class EscapeXmlELResolverListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(EscapeXmlELResolverListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener initialized ...");
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new EscapeXmlELResolver());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener destroyed");
}
/**
* {@link ELResolver} which escapes XML in String values.
*/
public class EscapeXmlELResolver extends ELResolver {
private ThreadLocal<Boolean> excludeMe = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (excludeMe.get()) {
return null;
}
// This resolver is in the original resolver chain. To prevent
// infinite recursion, set a flag to prevent this resolver from
// invoking the original resolver chain again when its turn in the
// chain comes around.
excludeMe.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(
context, base, property);
if (value instanceof String) {
value = StringEscapeUtils.escapeHtml4((String) value);
}
return value;
} finally {
excludeMe.remove();
}
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base){
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value){
throw new UnsupportedOperationException();
}
}
}
再次强调:这只保护了$
。请参考其他答案。
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
String str=request.getParameter("urlParam");
String safeOuput = StringEscapeUtils.escapeXml(str);