相对路径遍历(CWE-22)
漏洞描述:
相对路径遍历(CWE-22)是指应用程序在处理文件 / 目录访问时,未对用户可控的输入路径进行严格校验,导致攻击者可通过 “../” 等路径穿越字符突破预设访问范围。
更详细的解析是相对路径遍历漏洞是指在应用程序处理文件或目录访问时,路径名受外部控制的输入数据影响,且程序没有对能够解析到目录外位置的字符序列(如 “../”)进行有效处理。当攻击者可以操控输入的路径信息时,就能够利用这些特殊字符序列改变原本预期的访问路径,从而突破应用程序预设的目录访问限制。例如,在一个文件下载功能中,用户本应只能下载指定目录内的文件,但攻击者通过在输入的文件名参数中加入 “../”,就可能访问到服务器上其他非授权目录中的文件。
在《信息安全技术 网络安全等级保护基本要求》 中 “应用安全” 章节要求:
三级及以上等级保护对象需满足 “应对输入数据进行有效性校验”“应采用最小权限原则配置文件访问权限”,相对路径遍历漏洞直接违反上述要求,可能导致非授权文件访问,不符合等级保护合规性要求。
漏洞风险:
- 信息泄露:攻击者能够访问到限制目录之外的敏感文件,如系统配置文件、用户数据文件等,从而获取敏感信息,包括用户账号密码、系统密钥、业务机密数据等,进而导致用户隐私泄露、业务数据被盗用等严重后果。在等保要求中有“应保证敏感信息传输和存储的保密性” 要求,信息泄露在三级及以上系统中可能被判定为 “高危风险”。
- 恶意代码执行:如果攻击者能够访问到可执行文件所在目录,或者能够上传恶意文件到服务器,结合路径遍历漏洞,就有可能执行恶意代码,控制服务器,进行进一步的攻击活动,如安装后门程序、发动分布式拒绝服务(DDoS)攻击等。违反等保中 “应禁止未授权的代码执行” 条款,可能导致系统控制权丧失,属于 “超危风险”。
- 系统破坏:攻击者可以删除、修改非授权目录中的重要系统文件或业务数据文件,导致系统无法正常运行,业务中断,给企业或用户带来巨大的经济损失和声誉损害。违反等保中 “应保证系统数据的完整性” 要求,在关键业务系统中可能造成服务中断,符合标准中 “重大损失” 的风险定义。
修复或规避建议:
- 输入验证:除正则校验(如^((?!\\.\\.).)*[A-Za-z0-9_. -]+$)外,需补充长度限制(如文档示例中 “filename 不超过 10 个字符”),并禁止空字符、特殊控制字符(如/ \)。建议结合GB/T 34944-2017附录中的 “输入验证指南”,采用 “白名单” 机制仅允许明确合法的字符集。
- 使用绝对路径:
File file = new File(path); String canonicalPath = file.getCanonicalPath(); if (!canonicalPath.startsWith(dataPath)) { throw new SecurityException("路径越界,拒绝访问"); } |
强制使用绝对路径时,需通过File.getCanonicalPath()对拼接后的路径进行规范化,确保实际访问路径在预设目录内。例如:
此操作可防止因符号链接、相对路径解析差异导致的绕过,符合标准中 “访问控制粒度应满足业务需求” 的要求。
- 权限最小化:应用程序运行账户应仅授予必要目录的 “读 / 写” 权限(如dataPath目录),禁止对系统目录(如/etc C:\Windows)的访问,符合等保中 “用户权限应遵循最小授权原则”。
- 安全测试与合规性验证:定期对应用程序进行安全测试,包括渗透测试、代码审计等,及时发现和修复潜在的路径遍历漏洞。在系统上线前、重大变更后进行专项漏洞扫描,使用符合标准的工具(如OWASP ZAP)并保留测试记录,作为合规性证明。可以使用专业的安全测试工具,如OWASP ZAP、Nmap 等进行扫描检测。
- 安全框架和库:使用经过安全审计的文件处理框架和库。这些框架通常内置了对路径遍历漏洞的防护机制,能够帮助开发者更方便地编写安全的文件操作代码。
示例1:不规范用法
import java.io.*; public class Example{ private String dataPath; //本例中允许访问的目录 public void exampleFun(String filename) { //filename为用户的输入数据,不超过10个字符 //filename可能包含".."字符序列导致访问dataPath目录之外的文件; String path = dataPath + filename; try { File file = new File(path); if(file.exists()) { file.open(); //其它语句 } //其它语句 } catch (Exception e) { System.err.println("访问文件时出现错误: " + e.getMessage());
} } |
相对路径遍历是一个比较容易实现的攻击行为,只要攻击者能够输入路径,可能会试探通过增加../改变路径,从而可以访问到其它非授权路径,所以还是要进行控制。
示例2:规范用法之一
import java.io.File; public class Example { private String dataPath; // 本例中允许访问的目录 public Example(String dataPath) { this.dataPath = dataPath; } public void exampleFun(String filename) { // 校验文件名,允许字母、数字、下划线、点和短横线,且不能包含路径穿越字符 ".." String regex = "^((?!\\.\\.).)*[A-Za-z0-9_. -]+$"; if (filename.matches(regex)) { // 拼接路径和文件名 String path = dataPath + File.separator + filename; File file = new File(path); try { if (file.exists()) { // 这里可以进行文件打开等操作,示例中简单打印路径 System.out.println("文件存在,路径为: " + path); // 真正使用时,可以进行 file.open() 等具体操作 } else { System.out.println("文件不存在"); } } catch (Exception e) { System.err.println("访问文件时出现错误: " + e.getMessage()); } } else { System.err.println("文件名不合法,可能存在路径遍历风险"); } } public static void main(String[] args) { Example example = new Example("/allowed/directory/"); example.exampleFun("合法文件名.txt"); example.exampleFun("../../恶意路径/file.txt"); } } |
通过正则表示式对用户输入的路径和文件名进行处理。
示例3:规范用法之二
import java.io.File; import java.io.IOException; public class SecureExample { private final String dataPath; // 预设允许访问的绝对路径 public SecureExample(String dataPath) throws IOException { // 初始化时校验基础目录的合法性(绝对路径+存在性) File baseDir = new File(dataPath); if (!baseDir.isAbsolute() || !baseDir.exists() || !baseDir.isDirectory()) { throw new IllegalArgumentException("基础目录不合法,不符合安全要求"); } this.dataPath = baseDir.getCanonicalPath(); // 规范化基础路径 } public void safeFileAccess(String filename) throws IOException { // 1. 输入长度与字符校验(符合GB/T 34944输入验证要求) if (filename == null || filename.length() > 10) { throw new SecurityException("文件名长度超限"); } String regex = "^((?!\\.\\.).)*[A-Za-z0-9_. -]+$"; if (!filename.matches(regex)) { throw new SecurityException("文件名包含非法字符,可能存在路径遍历风险"); } // 2. 路径拼接与规范化 File file = new File(dataPath, filename); // 避免字符串直接拼接,使用File构造器自动处理分隔符 String canonicalPath = file.getCanonicalPath(); // 3. 强制校验路径边界(核心控制,符合访问控制要求) if (!canonicalPath.startsWith(dataPath)) { throw new SecurityException("路径越界,拒绝访问"); } // 4. 最小权限操作(仅执行必要的文件打开) if (file.exists() && file.isFile()) { file.canRead(); // 验证读权限 System.out.println("安全访问文件:" + canonicalPath); } else { System.out.println("文件不存在或不是常规文件"); } } } |
明确了绝对路径、相对路径的基础概念及相对路径遍历的技术细节,更与GB/T 34944-2017 的等级保护要求深度结合,可指导企业在合规框架下开展漏洞修复与风险管控。