Talk about directory traversal attack

  spring-security

Order

This article mainly studies the directory traversal attack and its prevention.

directory traversal attack

Also known as Path Traversal attack, or directory traversal attack, is designed to access files/directories outside the web server root directory. Directory traversal is performed by passing “../”in a url or variable.

Through urls

such as

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

Or ..

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

By variable name

Usually in the file download interface, such as

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

Or ..

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

To guard against

For urls

Spring security provides DefaultHttpFirewall for processing to prevent some web frameworks from not following servlet specifications.
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;
    }

}

The url will be judged here.

Pass variable

This kind of framework has no built-in judgment and needs extra attention when developing application services. Here are some preventive methods.

  • Filter variable names
final Pattern INVALID_PATH_PATTERN = Pattern.compile("(\\.\\.\\/|\\.\\.\\\\)");
if(INVALID_PATH_PATTERN.matcher(path).find()){
    throw new BadRequestException("invalid path");
}
  • Using absolutePath and canonicalPath

AbsolutePath does not deal with ../and so on, while canonicalPath translates ../,and whether there is ../

        if (!file.getAbsolutePath().equals(file.getCanonicalPath())) {
            throw new BadRequestException("invalid path");
        }

Summary

When writing the file download service, you need to pay special attention to the directory traversal attack. Usually, the url-level web framework will help you prevent it, but the variable-level web framework needs to be developed with extra attention.

doc