Java JSP/Servlet web应用中的XSS防范

Java JSP/Servlet web应用中的XSS防范,java,security,jsp,servlets,xss,Java,Security,Jsp,Servlets,Xss,如何在JSP/Servlet web应用程序中防止XSS攻击?如何防止XSS已经被问了好几次了。您将在StackOverflow中找到大量信息。还有,你应该通过 在要使用的库上,具有java风格。你应该试试看。除此之外,您使用的每个框架都有一些针对XSS的保护。同样,OWASP网站有关于大多数流行框架的信息,所以我建议浏览他们的网站。XSS可以通过在JSP中使用标记或EL函数来防止重新显示用户控制的输入。这包括请求参数、头、cookie、URL、正文等。从请求对象提取的任何内容。此外,在重新显示

如何在JSP/Servlet web应用程序中防止XSS攻击?

如何防止XSS已经被问了好几次了。您将在StackOverflow中找到大量信息。还有,你应该通过


在要使用的库上,具有java风格。你应该试试看。除此之外,您使用的每个框架都有一些针对XSS的保护。同样,OWASP网站有关于大多数流行框架的信息,所以我建议浏览他们的网站。

XSS可以通过在JSP中使用标记或EL函数来防止重新显示用户控制的输入。这包括请求参数、头、cookie、URL、正文等。从请求对象提取的任何内容。此外,在重新显示期间,需要转义存储在数据库中的来自先前请求的用户控制输入

例如:

这将转义可能使呈现的HTML格式错误的字符,例如,'和&,变成,,'及

注意,您不需要在Javaservlet代码中转义它们,因为它们在那里是无害的。有些人可能会选择在请求处理过程中转义它们,就像在Servlet或过滤器中那样,而不是像在JSP中那样在响应处理过程中转义,但这样做可能会导致数据不必要地得到双重转义,例如&been&;amp;而不是&;最终,最终用户将看到&;显示,或者数据库存储的数据变得不可移植,例如,将数据导出为JSON、CSV、XLS、PDF等时,根本不需要HTML转义。你也将失去社会控制,因为你不再知道用户实际填写了什么。作为一名站点管理员,您很想知道哪些用户/IP正在尝试执行XSS,这样您就可以轻松地跟踪他们并采取相应的措施。请求处理过程中的转义应该并且只能在您确实需要在尽可能短的时间内修复开发不良的遗留web应用程序的故障时作为最新的手段使用。不过,您最终还是应该重写JSP文件,使其成为XSS安全的

如果希望将用户控制的输入重新显示为HTML,其中只允许特定的HTML标记子集,如、、等,则需要通过白名单对输入进行清理。您可以使用类似的HTML解析器进行此操作。但是,更好的方法是引入一种人性化的标记语言,比如Markdown,它在这里也用于堆栈溢出。然后,您可以使用这样的标记解析器。它还具有内置的HTML清理功能。另见

服务器端关于数据库的唯一问题是预防。您需要确保从不在SQL或JPQL查询中直接串接用户控制的输入,并且始终使用参数化查询。在JDBC术语中,这意味着您应该使用而不是语句。在JPA术语中,使用


另一种方法是从JSP/Servlet迁移到JavaEE的MVC框架。它有内置的XSS和CSRF!预防无处不在。另请参见。

我建议定期使用自动化工具测试漏洞,并修复发现的任何漏洞。一般来说,建议一个库来帮助解决特定的漏洞要比建议所有XSS攻击容易得多


是一个来自谷歌的开源工具,我一直在研究:它发现了很多东西,似乎值得使用。

我个人的观点是,你应该避免使用JSP/ASP/PHP/etc页面。相反,输出到一个类似于SAX的API,该API只设计用于调用而不是处理。这样,就有一个层必须创建格式良好的输出。

我很幸运地在我所有的Spring控制器上安装了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;
    }

}
您可以从


我认为这是一种比c:out更好的方法,特别是如果您使用大量javascript。

没有简单的、现成的解决方案来对付XSS。OWASP ESAPI对转义有一些非常有用的支持,并且它们有标记库

我的方法基本上是通过以下方式扩展stuts2标签

修改s:property标记,以便它可以获取额外的属性,说明需要哪种类型的转义escapehtmlatAttribute=true等。。这涉及到创建新属性和PropertyTag类。属性类使用OWASP ESAPI进行转义。 更改freemarker模板以使用新版本的s:property并设置转义。 如果您不想在步骤1中修改类,另一种方法是将ESAPI标记导入freemarker模板并根据需要转义。然后,如果需要在JSP中使用s:property标记,请使用和ESAPI标记将其包装起来

我在这里写了更详细的解释


我同意这种情况并不理想

如果希望自动转义所有JSP变量而不必显式包装每个变量,可以 使用EL分解器,并详细讨论:

例如,通过使用上述EL解析器,您的JSP代码将保持原样,但解析器将自动转义每个变量

...
<c:forEach items="${orders}" var="item">
  <p>${item.name}</p>
  <p>${item.price}</p>
  <p>${item.description}</p>
</c:forEach>
...

如果你想强制默认在施普灵河逃逸,你也可以考虑这个问题,但是它不能逃避EL表达式,只是标签输出,我想:

注意:另一种使用XSL转换预处理JSP文件的EL转义方法可以在这里找到:


管理XSS需要来自客户端的多个验证和数据

输入验证形成服务器端的验证。有多种方法可以做到这一点。您可以尝试JSR303bean验证,或者。虽然我自己还没有尝试过,但是有一个注释可以检查safe html@safe html。实际上,您可以将Hibernate validator与Spring MVC一起用于bean验证-> 转义URL请求-对于所有HTTP请求,使用某种XSS筛选器。我在我们的web应用程序中使用了以下内容,它负责清理HTTP URL请求- 返回给客户端的转义数据/html请参见上面的@BalusC解释。
如果您想确保您的$operator不会遭受XSS攻击,您可以实现ServletContextListener并在那里进行一些检查

完整的解决方案位于:


再次声明:这只保护$。请参阅其他答案。

预防比诊断更好,例如先诊断鱼鳞鱼,然后再进行快速修复。我不同意。没有诊断的预防只是教条。将诊断作为CI周期的一部分运行,以避免快速修复问题。仅因为您使用Hibernate,并不意味着您可以安全地避免SQL注入。查德:那不是真的。只有当您在SQL/HQL/JPQL查询中直接将用户控制的输入串接在一起时,才会出现这种情况,比如选择。。。其中SOMEVAL=+SOMEVAL,而不是如您所示使用参数化查询。没有一个ORM可以防止这种开发人员的错误。我认为您也必须在服务器上进行验证。通过更改HTTP参数可以绕过所有验证。有时,您保存的数据可能会被企业应用程序中的其他应用程序使用。有时您无法访问其他应用程序的视图,因此需要在持久化到数据库之前清理输入。@Guido:您不了解问题所在。@peater:是的,在JS代码中放入不受信任的数据时,您需要使用HTML编码而不是HTML编码。而且,当将不可信数据放入CSS代码中时,您需要CSS编码而不是HTML编码。而且,当将不受信任的数据放入URL中时,您需要进行编码,而不是HTML编码。HTML编码只应用于将不可信数据放入HTML代码中。如何在不同情况下防止XSS攻击的伟大文章张贴在那里:通常的做法是在重新显示期间,而不是在servlet中处理提交的数据期间,也不是在DB中存储期间,HTML转义任何用户控制的数据。如果您在处理提交的数据和/或存储在DB中的过程中对其进行HTML转义,那么它将分布在业务代码和/或数据库中。这只是维护方面的问题,当你在不同的地方进行操作时,你会面临双重或更多的风险。业务代码和数据库反过来对XSS不敏感。只有景色是美丽的。然后,你应该只在视图中显示它。是和否。虽然通常的做法是在显示时显示,但有很多原因你可能需要在书写时进行消毒。在某些情况下,您确实希望用户输入HTML的子集,尽管您可以在显示时进行清理,但这实际上相当缓慢,甚至会让用户感到困惑。第二,如果您与第三方服务(如外部API)共享数据,则这些服务可能会或可能不会自行进行适当的消毒。正如您和我都提到的,通常的做法是在显示时逃逸。您在上面的评论中提到的是更具体的用例,因此需要具体的解决方案。是的,我也许应该让我的用例更清楚。我主要从事内容管理和HTML编辑工作。OWASP备忘单已经转移到GitHub。这是XSS预防备忘单的链接嗨,Brad,上面的用例是我正在寻找的。你能帮我解释一下在上面的场景中你如何防止XSS吗?每个场景我现在唯一记得的是使用EL解析器-这就是我们公司最终使用的。基本上,它会自动转义所有内容,如果您真的不想转义某些内容,您可以按照本文中的详细说明进行包装。
@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();
        }

    }

}