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_dev
和 st_ino
结果的值,调用 chdir("foo"),然后调用 stat() "."。比较生成的 st_dev
和 st_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/