C++ std::filesystem路径超出根目录检测方法与行为性质咨询
关于std::filesystem路径解析行为的问题解答
你观察到的行为属于设计特性,不是Bug
std::filesystem的路径解析逻辑完全对齐操作系统原生的路径处理规则,POSIX标准明确规定:根目录/的父目录仍然是根目录本身。因此路径/home/../..经过系统解析后等价于/,本身是合法存在的路径,不会抛出异常,fs::exists返回1属于预期行为。
如何通过C++标准库检测路径越界
通常说的「路径超出根目录边界」指的是路径超出业务侧指定的工作根目录(比如用户上传文件仅允许存储的目录,用于防范路径穿越攻击),可以通过标准库自带的路径规范化能力实现检测:
实现逻辑
- 首先使用
fs::canonical将指定的工作根目录转为规范化的绝对路径(要求该目录真实存在) - 对目标路径做规范化处理:
- 若目标路径不需要解析软链接、允许不存在:调用
fs::absolute转为绝对路径后,再调用lexically_normal()做纯词法层面的规范化,仅通过字符串处理消除路径中的.、..和多余分隔符 - 若目标路径包含软链接需要解析:调用
fs::weakly_canonical,该方法会解析所有存在的路径组件和软链接,不需要全路径真实存在
- 若目标路径不需要解析软链接、允许不存在:调用
- 检测规范化后的目标路径是否以工作根目录为前缀,C++20及以上可以直接使用
fs::path的starts_with()方法,低版本可以手动迭代路径组件对比
代码示例
#include <filesystem> #include <iostream> namespace fs = std::filesystem; // 检测target路径是否超出基准目录base bool is_path_out_of_bound(const fs::path& base, const fs::path& target) { // 基准目录转为规范化的绝对路径,要求base真实存在 const auto norm_base = fs::canonical(base); // 目标路径做词法规范化,不需要目标存在 const auto norm_target = fs::absolute(target).lexically_normal(); // 检测是否以基准目录为前缀,返回true表示超出边界 return !norm_target.starts_with(norm_base); } int main() { const fs::path base = "/home/test"; std::cout << std::boolalpha; // 输出false,未超出边界 std::cout << is_path_out_of_bound(base, "/home/test/../test/a.txt") << "\n"; // 输出true,超出边界 std::cout << is_path_out_of_bound(base, "/home/test/../../etc/passwd") << "\n"; return 0; }
如果你是要判断路径是否超出系统根目录,不需要额外检测:系统原生逻辑会自动把所有指向根目录以上的路径解析为根目录本身,不存在真正越界的可能。
内容的提问来源于stack exchange,提问作者kmosk
相关产品推荐
相关产品推荐

