如何从 shell 脚本安全地创建和访问临时文件?

如何从 shell 脚本安全地创建和访问临时文件?

我读过,将输出重定向到固定名称文件/tmp可能存在安全风险,因为如果攻击者(或恶意者)注意到/tmp/tmpfileformyscript.tmp在我运行脚本时创建了一个文件(即使他没有对我的脚本的读取访问权限)脚本),例如,他可以创建一个符号链接,这将导致我在运行脚本时ln -s ~wildcard/.bashrc /tmp/tmpfileformyscript.tmp销毁我的文件。.bashrc

所以我可以使用类似的东西filename="tmpfile.tmp.$RANDOM" ; echo outputtext > "$filename"

但是,有时我想使用 tmp 文件进行缓存,在这种情况下,我想知道“tmpfile.tmp.*”是否与其中的任何内容匹配,/tmp如果是,则使用该文件而不是创建一个新文件。不幸的是,据我所知,test等效项不支持文件通配。[ -f filename ]

因此我的问题是双重的:

  1. 如何安全地创建临时文件?是"predictablename.$RANDOM"一种可以接受的做法还是有更好(更安全、更简单)的方法?
  2. 我如何轻松访问该文件和/或稍后通过检查来确定其存在predictablename

答案1

使用mktemp实用程序创建具有不可预测名称的临时文件。它没有被 POSIX 标准化,但可以在 *BSD 和 Linux 上使用。

> /tmp/predictable.$RANDOM不是一个好的选择,因为它基本上是可预测的,这会使您的脚本遭受攻击,攻击者可以欺骗您的脚本覆盖您具有写访问权限的文件,或授予他们对临时文件的访问权限。这是一不安全的临时文件脆弱性。mktemp不存在此漏洞,因为安全地创建文件(即使涉及符号链接,它也不会覆盖现有文件)并使用足够不可预测的名称来避免拒绝服务。

如果创建一个临时文件并使用它还不够好,请使用 , 创建一个临时目录mktemp -d,然后在其中工作。

mktemp如果变量已设置,则还要小心使用,如果变量未设置$TMPDIR,则回退到该变量。/tmp

越来越多的发行版设置TMPDIR为私有目录,例如您的 UID 在/run/1234/tmp哪里。1234这消除了临时文件漏洞的风险,代价是不再能够在用户之间共享临时文件(偶尔有用,但不经常使用;/tmp仍然可用,只是不可用TMPDIR)。

如果您需要可重复的文件名,请在用户的主目录下创建一个具有明确定义的名称(没有随机组件)的文件。现代惯例是XDG用户目录规范。如果可以删除该文件而不导致数据丢失,请使用XDG_CACHE_HOME环境变量,默认为~/.cache.您可能应该创建一个以您的应用程序命名的子目录并在其中工作。

CACHE_DIR="${XDG_CACHE_HOME:-"$HOME/.cache"}"/Wildcard-scripts
[ -d "$CACHE_DIR" ] || mkdir -p -- "$CACHE_DIR"
CACHE_FILE="$CACHE_DIR/tmpfileformyscript"

¹不仅$RANDOM只需要 32767 个可能的值,而且无需尝试许多值即可轻松预测。 Bash 的随机数生成器是LCG由 PID 和首次使用时间播种。 Zsh 是该平台rand按启动时间播种的。 ATT Ksh 是平台的randPID 种子。 Mksh 是一种 LCG,具有更复杂的种子,但仍然不具备安全质量。所有这些都可以通过另一个过程来预测,并且成功的机会相当大。

答案2

mktemp 就是为此而设计的。从手册页:

TMPFILE=`mktemp /tmp/example.XXXXXXXXXX` || exit 1
echo "program output" >> $TMPFILE

mktemp 将创建文件或以非零退出状态退出。逻辑或 (||) 确保在 mktemp 无法创建文件时脚本将退出。执行此命令后,您可以确定该文件可用。无需再次检查。您可能需要添加的唯一一件事是清理脚本末尾的文件。

当脚本被信号终止时也可能如此。是否有必要,这是你必须决定的事情。

两者都可以使用命令完成trap

相关内容