#open #secure #chroot

obnth

允许在 *nix 系统上安全地打开不受信任目录中的文件

2 个版本

0.1.1 2021 年 2 月 5 日
0.1.0 2021 年 1 月 3 日

1128文件系统

37 次每月下载

MIT 许可证

91KB
2K SLoC

obnth

crates.io Docs GitHub Actions Cirrus CI codecov

允许在 *nix 系统上安全地打开不受信任目录中的文件。

警告:此 crate 尚未准备好用于生产环境。您可能更愿意使用 libpathrs


lib.rs:

此 crate 有什么用途?

obnth 使您能够轻松地在不受信任的目录中安全地打开文件。例如,在从用户控制的 "webdocs" 目录中提供文件的 Web 服务器中,或者在需要根据用户提供的信息打开文件的 set-UID 程序中,这可能非常有用。

作为一个更具体的例子,假设您正在从 /srv/user1 提供文件

let dir = Dir::open("/srv/user1").unwrap();

// If `a` and/or `a/index.html` are symlinks, they will be followed, but
// they can't escape `/srv/user1`.
let file = dir.open_file().open("a/index.html").unwrap();

这为什么危险?为什么我不能只使用 Path::join()

上述用例的简单实现可能如下所示

// DO NOT DO THIS
let file = File::open(Path::new("/srv/user1").join("a/index.html")).unwrap();

然而,这非常危险。只需考虑以下情况:如果 /srv/user1/a/index.html 是指向,例如,/etc/shadow 的符号链接。如果相关的程序是 Web 服务器,这基本上会将系统控制权交给任何可以创建目标目录中符号链接的人。

下一个合乎逻辑的尝试是使用 Path::canonicalize() 并在打开之前验证路径

// DO NOT DO THIS
let path = Path::new("/srv/user1").join("a/index.html").canonicalize().unwrap();
assert!(path.starts_with("/srv/user1"));
let file = File::open(path).unwrap();

然而,在调用 Path::canonicalize() 和调用 File::open() 之间,攻击者可能会将 a/index.html 替换为指向另一个文件的符号链接,并仍然欺骗程序打开它不应该打开的文件。

为什么不用 openatlibpathrs Crates?

  • openat*at() 函数提供友好的接口。然而,它不对提供的路径执行任何验证,并且您很容易通过指定绝对路径或包含 .. 组件的路径来逃离目录。

    openat 非常有用,例如,如果您需要以非常受控的方式遍历目录树,并且您只需要稍微高级一些的 *at() 函数的接口,那么这个工具就非常有用。然而,如果您只想在给定的目录内打开文件(并保证它不会逃逸),那么 obnth 可能会更加有用。

  • libpathrs 在这个库中扮演着类似的角色,但它非常特定于 Linux。 obnth 在 Linux、macOS 和 BSD(这需要语义上的某些差异)上运行。

依赖关系

~150KB