目录遍历安全问题

7
我有一个Java webapp容易受到目录遍历(也称路径遍历)攻击,通过URL编码。在经过身份验证后:
  • 如果我访问http://localhost:8080/Web/WEB-INF/web.xml,我会得到404(这是好的)
  • 如果我访问http://localhost:8080/Web/%c0%ae/WEB-INF/web.xml,我可以读取文件(这显然不好)
根据Servlet规范,WEB-INF文件夹不应该公开访问,但在这种情况下它似乎有效。 我正在使用Websphere 5.1与Java 1.4、Spring Security 2.0.5和Struts 1.3。 从我所了解的来看,它似乎与编码有关,%c0%ae在UTF-8中表示'.'(点号)。
我尝试在不同的环境中运行相同的webapp(Tomcat 6与Java 7、Spring Security 3和Spring MVC),但无法重现此问题。第二个webapp有一个过滤器,强制将页面编码为UTF-8(org.springframework.web.filter.CharacterEncodingFilter),因此我在第一个webapp上尝试了相同的配置,但没有成功。 有什么想法吗?
谢谢。

6
你能否在部署此系统的服务器上更新Spring和/或Java版本?听起来像是CVE-2010-3700。 - Eduard Thamm
很遗憾,这不在我的控制范围内。 - Emmanuel Ballerini
那么我建议进行有限发布。这个版本已知存在问题,如果客户不升级到新版本,他将不得不忍受它带来的麻烦。我知道这并不是很有用。抱歉,也许其他人会想出什么办法。 - Eduard Thamm
我可以看到这确实是一个已知的问题。谢谢,Eduard。 - Emmanuel Ballerini
3
使用存在许多已公开漏洞的旧版软件可能并不是最好的想法。 - Tom Hawtin - tackline
5个回答

2
我将回答自己的问题。
所以,在我有限的选择中,最终我做的是在Spring Security配置文件中添加了一个安全规则,例如
<sec:intercept-url pattern="/**/WEB-INF/**" access="no-access"/>

它将对WEB-INF的访问限制为“无访问权限”角色,实际上并不是一个角色。这可以防止所有用户访问。虽然不是理想的解决方案,但在升级之前可以使用。


你可能也应该为 META-INF 添加一个规则。 - Dmitri
您可以在META-INF中定义安全规则吗?这是如何工作的? - Emmanuel Ballerini
不,我的意思是你应该使用相同类型的规则来阻止对META-INF的访问,而不仅仅是WEB-INF。 - Dmitri

1

在请求到达Websphere之前,您可以通过将它们通过另一个Web服务器/应用服务器或Web应用程序防火墙进行代理来修复或拒绝这些请求。另一个Java应用服务器或可能类似于NginxVarnish的东西可以解决问题。

当然,真正的解决方案是升级。这只是一个临时措施,可能会被破坏。这确实是“修复”安全问题的错误方式。


很遗憾,我没有添加这种组件的选项。 - Emmanuel Ballerini

0

过滤器会改变请求体的字符编码,而不是URL。

要在Tomcat中设置URL编码,您需要在server.xml的<Connector>元素中添加一个属性:

<Connector port="8080" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           URIEncoding="UTF-8"
           redirectPort="8443" />

谢谢Maurice,但是在Websphere中有相应的东西吗? - Emmanuel Ballerini

0

如果您无法升级(古老的WebSphere + Java 1.4,糟糕!),一个可能的解决方法(实际上更像是hackaround)是编写一个简单的过滤器,映射到每个请求,执行适当的字符集转换并拒绝无效请求。

我相信通过一些挖掘,您可以找到一个实现,检查您可能没有考虑到的事情。

当然,这仍然留下了8年的其他安全(更不用提生产力)问题。

哎呀

没注意到问题有多旧。


你如何确定一个请求是无效的呢?你需要手动维护这样的请求列表吗? - Emmanuel Ballerini

0

这是我的实现

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author davidandrade
 */
public class RestrictURL implements Filter {

    private FilterConfig fcgConfFiltr_t;

    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(RestrictURL.class.getName());

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        fcgConfFiltr_t = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String strUrlPetici_t = req.getRequestURL().toString();
        String strUrlBase___t = strUrlPetici_t.substring(0, strUrlPetici_t.indexOf(fcgConfFiltr_t.getServletContext().getContextPath()) + fcgConfFiltr_t.getServletContext().getContextPath().length());

        try {

            res.addHeader("X-Frame-Options", "SAMEORIGIN");
            log.info("URL Req: " + strUrlPetici_t);

            if (strUrlPetici_t.toLowerCase().contains("%co") || strUrlPetici_t.toLowerCase().contains("%ae")) {
                sendErrorRedirect(req, res, "/404.jsf", new Exception("DirectoryTransversalRequired"));
            } else {
                try {
                    fcgConfFiltr_t.getServletContext().getRequestDispatcher(strUrlPetici_t).forward(request, response);
                } catch (IllegalArgumentException e) {
                    chain.doFilter(request, response);
                }
            }

        } catch (Exception e) {
            log.error("", e);
            sendErrorRedirect(req, res, "/404.jsf", e);

        }
    }

    protected void sendErrorRedirect(HttpServletRequest request, HttpServletResponse response, String errorPageURL, Throwable e) throws ServletException, IOException {
        request.setAttribute("exception", e);
        fcgConfFiltr_t.getServletContext().getRequestDispatcher(errorPageURL).forward(request, response);
    }

    @Override
    public void destroy() {
        fcgConfFiltr_t = null;
    }

}

并在我的web.xml中添加过滤器

<filter>
        <filter-name>DirectoryTransversalFilter</filter-name>
        <filter-class>com.sec.RestrictURL</filter-class> <!-- mandatory -->
    </filter>
    <filter-mapping>
        <filter-name>DirectoryTransversalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接