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

Wil*_*ard 17 shell-script tmp caching

我读过将输出重定向到固定名称文件/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

Gil*_*il' 17

使用该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"
Run Code Online (Sandbox Code Playgroud)

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


Bra*_*ram 12

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

TMPFILE=`mktemp /tmp/example.XXXXXXXXXX` || exit 1
echo "program output" >> $TMPFILE
Run Code Online (Sandbox Code Playgroud)

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

也可能在脚本被信号终止时。这是否有必要是您必须决定的。

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