checkmarx - 如何解决存储的绝对路径遍历问题?

2024-05-23

Checkmarx - v 9.3.0 HF11

我将 env 值作为 dev/uat 服务器中使用的 docker 文件中的数据目录路径传递

ENV DATA /app/data/

在本地,使用以下环境变量

数据 = C:\项目\应用程序\数据\

getDataDirectory("我的目录名称"); // MyDirectoryName 存在于数据文件夹中

public String getDataDirectory(String dirName)
{
    String path = System.getenv("DATA");
    if (path != null) {
        path = sanitizePathValue(path);
        path = encodePath(path);

        dirName = sanitizePathValue(dirName);
        if (!path.endsWith(File.separator)) {
            path = path + File.separator;
        } else if (!path.contains("data")) {
            throw new MyRuntimeException("Data Directory path is incorrect");
        }
    } else {
        return null;
    }

    File file = new File(dirName); // NOSONAR

    if (!file.isAbsolute()) {
        File tmp = new File(SecurityUtil.decodePath(path)); // NOSONAR

        if (!tmp.getAbsolutePath().endsWith(Character.toString(File.separatorChar))) {
            dirName = tmp.getAbsolutePath() + File.separatorChar + dirName;
        } else {
            dirName = tmp.getAbsolutePath() + dirName;
        }

    }

    return dirName;
}

public static String encodePath(String path) {
        try {
            return URLEncoder.encode(path, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error("Exception while encoding path", e);
        }
        return "";
}

public static String validateAndNormalizePath(String path) {
        path = path.replaceAll("/../", "/");
        path = path.replaceAll("/%46%46/", "/");
        path = SecurityUtil.cleanIt(path);
        path = FilenameUtils.normalize(path); // normalize path
        return path;

    }

public static String sanitizePathValue(String filename){
    filename = validateAndNormalizePath(filename);
    String regEx = "..|\\|/";
    // compile the regex to create pattern
    // using compile() method
    Pattern pattern = Pattern.compile(regEx);
    // get a matcher object from pattern
    Matcher matcher = pattern.matcher(filename);

    // check whether Regex string is
    // found in actualString or not
    boolean matches = matcher.matches();
    if(matches){
        throw new MyAppRuntimeException("filename:'"+filename+"' is bad.");
    }
    return  filename;
}

public static String validateAndNormalizePath(String path) {
    path = path.replaceAll("/../", "/");
    path = path.replaceAll("/%46%46/", "/");
    path = SecurityUtil.cleanIt(path);
    path = FilenameUtils.normalize(path); // normalize path
    return path;

}

[尝试] - 更新我在少数成员的帮助下尝试的代码,以防止路径遍历问题。

尝试清理字符串并规范化字符串,但没有运气并遇到同样的问题。

如何解决存储绝对路径遍历问题?


你的第一次尝试不会成功,因为单独逃脱并不能阻止路径遍历。考虑到您需要确保有人使用以下命令设置属性/环境变量,用双引号替换单引号也不会这样做../../etc/resolv.conf无法成功欺骗您的代码覆盖/读取敏感文件。我相信Checkmarx不会寻找StringUtils作为将其识别为已清理的一部分,因此下面的简单工作示例类似,无需使用StringUtils.

您的第二次尝试将不起作用,因为它是一个验证器,在引发异常时使用控制流来防止错误输入。 Checkmarx 分析数据流。什么时候filename作为参数传递给sanitizePathValue并在最后按原样返回,数据流分析认为这没有对原始值进行更改。

您的系统中似乎还存在一些可识别的自定义设置System.getProperty and System.getenv作为不受信任的输入。默认情况下,这些不会以这种方式识别,因此任何试图扫描您的代码的人可能不会获得绝对路径遍历的任何结果。您的应用程序的风险状况可能要求您将属性和环境变量调用为不受信任的输入,因此您实际上不能仅删除它们并恢复为 OOTB 设置。

正如 Roman 所提到的,查询中的逻辑确实会查找附加到此不受信任输入的值,以将这些数据流作为结果删除。下面的代码显示了如何使用 Roman 的方法来欺骗扫描仪。 (我强烈建议您不要选择欺骗扫描仪的路线......非常糟糕的主意。)可能还有其他字符串文字值可以使用此方法,但它需要一些控制运行时的操作执行(如使用 chroot)以确保它确实解决了问题。

如果您扫描下面的代码,您应该只会看到一个易受攻击的数据路径。最后一个示例可能与您可以用来修复问题的内容类似。这实际上取决于您想要对正在创建的文件执行什么操作。

(我在 9.2 上对此进行了测试;它应该适用于之前的版本。如果不起作用,请发布您的版本,我可以查看该版本的查询。)

// Vulnerable
String fn1 = System.getProperty ("test");
File f1 = new File(fn1);


// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn2 = System.getProperty ("test");
File f2 = new File(Paths.get ("", fn2).toString () );

// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn3 = System.getProperty ("test");
File f3 = new File("" + fn3);

// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn4 = System.getProperty ("test");
File f4 = new File("", fn4);

// Sanitized by stripping path separator as defined in the JDK
// This would be the safest method
String fn5 = System.getProperty ("test");
File f5 = new File(fn5.replaceAll (File.separator, ""));


因此,总而言之(TL;DR),替换不受信任的输入值中的文件分隔符:

String fn5 = System.getProperty ("test");
File f5 = new File(fn5.replaceAll (File.separator, ""));

Edit为可能在寻找答案时遇到此问题的其他 Checkmarx 用户进行更新。

在我回答之后,OP 更新了问题,表明发现的问题是由于为代码在不同环境中运行而编写的机制造成的。在 Docker 出现之前,这就是使用的方法。该漏洞仍然会被检测到,但大多数行动方案都是说“我们的部署环境周围有安全措施,以防止不良行为者将不需要的路径注入到我们存储基本路径的环境变量中。”

但现在,有了 Docker,这一切都成为了过去。一般来说,Docker 的目的是创建运行的应用程序部署方式在任何地方都相同 https://www.docker.com/resources/what-container。在环境中使用基本路径可能意味着 OP 在容器外部执行代码以进行开发(基于显示 Windows 路径的更新),并在容器内部执行代码以进行部署。为什么不按照 Docker 的预期直接在容器中运行代码进行开发和部署呢?

大多数答案倾向于解释OP应该使用静态路径。这是因为他们意识到没有办法避免这个问题,因为(从环境中)获取不受信任的输入并将其作为路径的前缀是绝对路径遍历的确切问题.

OP可以遵循这里许多海报的好建议,在代码中放置一个静态基本路径,然后使用Docker 卷 https://docs.docker.com/storage/volumes/ or Docker 绑定挂载 https://docs.docker.com/storage/bind-mounts/.

它困难吗?没有。如果我是OP,我会将代码中的基本路径前缀修复为静态值/app/data并在开发过程中进行简单的卷绑定。 (当您考虑一下时,如果在部署期间容器中存储了数据,那么部署环境必须执行此操作/app/data除非在容器的生命周期结束后不再保留数据。)

基本路径固定为/app/data,OP 运行其开发版本的一种选择是:

docker run -it -v"C:\\projects\\app\\data":/app/data {container name goes here}

应用程序写入的所有数据都将出现在C:\projects\app\data与使用环境变量时的方式相同。主要区别在于,没有环境变量前缀路径,因此静态分析扫描仪不会产生绝对路径遍历结果。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

checkmarx - 如何解决存储的绝对路径遍历问题? 的相关文章

随机推荐