聊聊directory traversal attack

本文主要研究一下directory traversal attack及其防範php

directory traversal attack

又稱Path Traversal attack,即目錄遍歷攻擊,旨在訪問web服務器根目錄外的文件/目錄。經過是經過url或變量裏頭傳遞"../"來進行目錄遍歷。java

經過url

好比web

http://some_site.com.br/../../../../some dir/some file

或者spring

http://some_site.com.br/../../../../etc/shadow

經過變量名

一般是在文件下載接口中,好比服務器

http://some_site.com.br/get-files?file=/etc/passwd

或者app

http://some_site.com.br/get-files?file=../../../../some dir/some file

防範

針對url

spring security提供了DefaultHttpFirewall來進行處理,是爲了防止一些web框架沒有遵循servlet規範而進行的防範。
spring-security-web-4.2.3.RELEASE-sources.jar!/org/springframework/security/web/firewall/DefaultHttpFirewall.java框架

/**
 * Default implementation which wraps requests in order to provide consistent
 * values of the {@code servletPath} and {@code pathInfo}, which do not contain
 * path parameters (as defined in
 * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>). Different
 * servlet containers interpret the servlet spec differently as to how path
 * parameters are treated and it is possible they might be added in order to
 * bypass particular security constraints. When using this implementation, they
 * will be removed for all requests as the request passes through the security
 * filter chain. Note that this means that any segments in the decoded path
 * which contain a semi-colon, will have the part following the semi-colon
 * removed for request matching. Your application should not contain any valid
 * paths which contain semi-colons.
 * <p>
 * If any un-normalized paths are found (containing directory-traversal
 * character sequences), the request will be rejected immediately. Most
 * containers normalize the paths before performing the servlet-mapping, but
 * again this is not guaranteed by the servlet spec.
 *
 * @author Luke Taylor
 */
public class DefaultHttpFirewall implements HttpFirewall {
    private boolean allowUrlEncodedSlash;

    @Override
    public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
        FirewalledRequest fwr = new RequestWrapper(request);

        if (!isNormalized(fwr.getServletPath()) || !isNormalized(fwr.getPathInfo())) {
            throw new RequestRejectedException("Un-normalized paths are not supported: " + fwr.getServletPath()
                    + (fwr.getPathInfo() != null ? fwr.getPathInfo() : ""));
        }

        String requestURI = fwr.getRequestURI();
        if (containsInvalidUrlEncodedSlash(requestURI)) {
            throw new RequestRejectedException("The requestURI cannot contain encoded slash. Got " + requestURI);
        }

        return fwr;
    }

    @Override
    public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
        return new FirewalledResponse(response);
    }

    /**
     * <p>
     * Sets if the application should allow a URL encoded slash character.
     * </p>
     * <p>
     * If true (default is false), a URL encoded slash will be allowed in the
     * URL. Allowing encoded slashes can cause security vulnerabilities in some
     * situations depending on how the container constructs the
     * HttpServletRequest.
     * </p>
     *
     * @param allowUrlEncodedSlash
     *            the new value (default false)
     */
    public void setAllowUrlEncodedSlash(boolean allowUrlEncodedSlash) {
        this.allowUrlEncodedSlash = allowUrlEncodedSlash;
    }

    private boolean containsInvalidUrlEncodedSlash(String uri) {
        if (this.allowUrlEncodedSlash || uri == null) {
            return false;
        }

        if (uri.contains("%2f") || uri.contains("%2F")) {
            return true;
        }

        return false;
    }

    /**
     * Checks whether a path is normalized (doesn't contain path traversal
     * sequences like "./", "/../" or "/.")
     *
     * @param path
     *            the path to test
     * @return true if the path doesn't contain any path-traversal character
     *         sequences.
     */
    private boolean isNormalized(String path) {
        if (path == null) {
            return true;
        }

        for (int j = path.length(); j > 0;) {
            int i = path.lastIndexOf('/', j - 1);
            int gap = j - i;

            if (gap == 2 && path.charAt(i + 1) == '.') {
                // ".", "/./" or "/."
                return false;
            } else if (gap == 3 && path.charAt(i + 1) == '.' && path.charAt(i + 2) == '.') {
                return false;
            }

            j = i;
        }

        return true;
    }

}
這裏會對url進行判斷

經過變量

這種框架沒有內置進行判斷,須要本身在開發應用服務的時候額外關注。這裏談談幾種防範方法。ide

  • 對變量名進行過濾
final Pattern INVALID_PATH_PATTERN = Pattern.compile("(\\.\\.\\/|\\.\\.\\\\)");
if(INVALID_PATH_PATTERN.matcher(path).find()){
    throw new BadRequestException("invalid path");
}
  • 利用absolutePath與canonicalPath
absolutePath不會處理../之類的,而canonicalPath會翻譯../,判斷二者是否相等便可判斷是否有../
if (!file.getAbsolutePath().equals(file.getCanonicalPath())) {
            throw new BadRequestException("invalid path");
        }

小結

在編寫文件下載服務的時候,須要特別關注directory traversal attack。一般url層面的web框架會幫你防範,可是變量層面的,則須要本身開發額外注意。this

doc

相關文章
相關標籤/搜索