目录遍历安全问题

Posted

技术标签:

【中文标题】目录遍历安全问题【英文标题】:Directory traversal security issue 【发布时间】:2011-06-01 18:05:46 【问题描述】:

我有一个 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 中。

我在另一个运行在不同环境(Tomcat 6 with Java 7、Spring Security 3 和 Spring MVC)中的不同 webapp 上尝试了同样的事情,但我无法重现该问题。第二个 webapp 有一个过滤器来强制以 UTF-8 (org.springframework.web.filter.CharacterEncodingFilter) 对页面进行编码,所以我在第一个 webapp 上尝试了相同的配置,但它没有成功。 有什么想法吗?

谢谢。

【问题讨论】:

有没有什么方法可以更新系统上的 Spring 和/或 Java 版本?听起来像 CVE-2010-3700 很遗憾,这不是我能控制的。 那我建议限量发行。这是这个版本的一个已知问题,如果客户不升级到新版本,他将不得不忍受它给他带来的麻烦。我知道不是很有用。抱歉,也许其他人会想出一些办法。 我可以看到这确实是一个已知问题。谢谢,爱德华。 运行具有许多已发布漏洞的旧版本软件可能不是最好的主意。 【参考方案1】:

我将回答我自己的问题。 因此,由于我拥有的选项有限,我最终要做的是在 Spring Security 配置文件中添加一个安全规则,例如

<sec:intercept-url pattern="/**/WEB-INF/**" access="no-access"/>

它将对 WEB-INF 的访问限制为“禁止访问”角色,实际上这不是一个角色。这会阻止对所有用户的访问。这并不理想,但在升级之前可以解决问题。

【讨论】:

您可能还应该为 META-INF 添加一条规则。 您可以在 META-INF 中定义安全规则吗?这是如何工作的? 不,我的意思是你应该使用相同类型的规则来阻止对 META-INF 的访问,而不仅仅是 WEB-INF。【参考方案2】:

您可以通过另一个网络服务器/应用服务器或Web application firewalls 代理它们,在它们到达 Websphere 之前修复或拒绝这些请求。另一个 Java 应用程序服务器或类似 nginx 或 Varnish 的东西都可以解决问题。

当然,真正的解决方案是升级。这只是一个创可贴,可以被颠覆。这确实是“修复”安全问题的错误方法。

【讨论】:

很遗憾,我没有添加此类组件的选项。【参考方案3】:

过滤器更改请求正文的字符编码,而不是 URL。

要在tomcat中设置URL编码,需要在server.xml的元素中添加一个属性:

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

【讨论】:

谢谢 Maurice,但是在 Websphere 中有没有等价物?【参考方案4】:

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

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

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

哎呀

没注意到没注意到问题的年龄。

【讨论】:

您如何确定请求无效?您是否必须手动更新此类请求的列表?【参考方案5】:

这是我的实现

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>

【讨论】:

以上是关于目录遍历安全问题的主要内容,如果未能解决你的问题,请参考以下文章

目录遍历漏洞

目录遍历攻击详解

Android 安全开发之 ZIP 文件目录遍历

Android安全开发之ZIP文件目录遍历

目录遍历漏洞

CTFHub 目录便利 解题思路