security - shell 命令列表中的竞争条件

标签 security bash shell symlink race-condition

shell(或 bash)中的命令列表在竞争条件下的安全性如何?

if [ -h "$dir" ]; then
  echo 'Directory exists and is a symlink'
  exit 1
fi
cd "$dir"

上面的代码显然容易出现竞争条件:攻击者可以在检查之后创建一个符号链接(symbolic link),但仍然是在将目录更改为符号链接(symbolic link)之前。

同样适用于 || 命令列表吗?换句话说:下面的命令是否不受竞争条件的影响,或者与上面相同的规则是否仍然适用?

[ -h "$dir" ] || cd "$dir"

错误信息:

[ -h "$dir" ]
  && { echo 'Directory exists and is a symlink'; exit 1; }
  || cd "$dir"

最佳答案

只有两种安全且相对便携的方法可以在不遵循符号链接(symbolic link)的情况下更改目录。在 shell 脚本中这两者都不容易实现。

为了便于讨论,假设我们正在尝试安全地将 chdir 放入“foo”。第一种方式是用open(".", O_RDONLY)lstat()将当前目录保存在一个打开的文件描述符中,将"foo"目录,记录st_devst_ino 结果的值,调用 chdir("foo"),然后调用 stat() "."。比较生成的 st_devst_ino 值。如果它们相同,则您赢得了比赛。如果没有,发出一条错误消息,fchdir() 使用您保存的 fd 返回,然后中止或重试。

第二种不太便携的方法是使用 fd = open("foo", O_RDONLY|O_NOFOLLOW) 然后使用 fchdir(fd)。您也可以在此处使用 openat 而不是 open。可移植性问题是并非所有系统都有 O_NOFOLLOW 并且一些较旧的内核不会正确解释该标志(相反它们会忽略它,这是一个安全问题)。

有关更多信息,请查看 GNU find 的源代码,其中我使用与上述方法非常相似的方法来避免此类问题。

关于在shell脚本中解决这个问题:

如果您的系统有 stat(1) 命令或类似 Perl 的东西,您可以使用它们来执行统计操作;您可以将结果记录在 shell 变量中。这意味着您可以或多或少地在 shell 脚本中实现第一个方法,除了需要使用 fchdir 来恢复。如果当您的 shell 脚本输掉比赛时可以立即简单地中止,那么您当然可以调整第一种方法以在 shell 中使用。但最终在 shell 中编写安全代码非常非常困难。

关于security - shell 命令列表中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9549293/

相关文章:

shell - 在 UNIX 中遍历文件

linux - 通过本地重定向从本地脚本远程 sudo

Javascript 安全 : is storing sensitive data in a self invoking function more secure than cookies?

android - 在 Android 上自定义/系统挂载点

c# - 使用 Forefront Identity Manager 进行自助式密码重置有哪些选项?

r - 调度属于 R 包的函数

bash - 如何在完成执行后终止由 bash 脚本启动的后台进程/作业?

php - 如何检查跨域请求是否被禁用

bash - 如何检查可执行文件的路径扩展

bash - 检查传递的参数是 Bash 中的文件还是目录