今天负责了一些漏洞修复的工作,其中一个感觉的比较常见,拿出来说一下,给出的漏洞描述是这样的
输入验证
高危:路径遍历
应用程序对用户可控制的输入未经合理校验,就传送给一个文件API。攻击者可能会使用一些特殊的字符(如..和/)摆脱受保护的限制,访问一些受保护的文件或目录。
例如:下面代码片段通过验证输入路径是否以/safe_dir/为开头,来判断是否进行创建、删除操作。
String path = getInputPath();
if (path.startsWith(“/safe_dir/”)){
File f = new File(path);
f.delete()
}
攻击者可能提供类似下面的输入:
/safe_dir/../important.dat
程序假定路径是有效的,因为它是以/safe_dir/开头的,但是../将导致程序删除important.dat文件的父目录。
修复建议
预防路径遍历的威胁,有以下三种方法:
程序对非受信的用户输入做过滤和验证,对网站用户提交的文件路径进行硬编码或统一编码,过滤非法字符。
对文件后缀进行白名单控制,拒绝包含了恶意的符号或空字节。
合理配置Web服务器的目录访问权限。
先说一下我自己的做法,就是用正则表达式去检测传进来的文件路径和不合规
代码如下
private static final Pattern VALID_FILENAME_CHARS = Pattern.compile("^[a-zA-Z0-9_-]+$");
String userInputFileName = "example.zip";
// 验证文件名是否包含只允许的字符
if (!VALID_FILENAME_CHARS.matcher(userInputFileName).matches()) {
throw new IllegalArgumentException("Invalid file name");
}
但是这个考虑的情况比较少,不合规的情况有好多,这个不一定能过滤掉所有。然后了解到File类中有两个方法可以检验路径是否合法,我们来看一下
Java File getCanonicalPath() 方法
// Java program to demonstrate the
// use of getCanonicalPath() function
import java.io.*;
public class solution {
public static void main(String args[])
{
// try-catch block to handle exceptions
try {
// Create a file object
File f = new File("c:\\program");
// Get the Canonical path of file f
String canonical = f.getCanonicalPath();
// Display the file path of the file object
// and also the file path of Canonical file
System.out.println("Original file path : "
+ f.getPath());
System.out.println("Canonical file path : "
+ canonical);
}
catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
输出
Java File getCanonicalFile()方法
如果我们使用 “program.txt “的路径创建一个文件对象,它将指向保存可执行程序的同一目录下的文件(如果你使用的是IDE,它将指向你保存该程序的文件)。这里,上述文件的路径是 “program.txt”,但这个路径不是绝对的(即不完整)。函数getCanonicalFile()将返回一个文件,其路径将是一个来自根目录的绝对和唯一的路径。一个现有文件的经典形式可能与同一不存在的文件的经典形式不同,一个现有文件的经典形式可能与同一文件被删除时的经典形式不同。
// Java program to demonstrate the
// use of getCanonicalFile() function
import java.io.*;
public class solution {
public static void main(String args[])
{
// try-catch block to handle exceptions
try {
// Create a file object
File f = new File("program.txt");
// Get the Canonical file
// of the given file f
File canonical = f.getCanonicalFile();
// Display the file path of the file object
// and also the file path of Canonical file
System.out.println("Original file path: "
+ f.getPath());
System.out.println("Canonical file path: "
+ canonical.getPath());
}
catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
输出
根据需要可以查看选择两个方法中的一种