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


14

我已经读到将输出重定向到其中的一个固定名称文件/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

Answers:


13

使用该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的随机数生成器是由PID和首次使用时间设定的LCG。Zsh是平台rand启动时间的种子。ATT Ksh是randPID播种的平台。Mksh是一个LCG,它具有更复杂的内容,但仍然不是安全质量种子。所有这些都可以通过另一个过程来预测,并且成功的可能性很大。


其实你的讨论$TMPDIR,并~/.cache是正是我需要的。经过进一步的思考,我意识到我想要它的唯一原因/tmp是分区-因此缓存无法填满/home分区。但是对于这个用例来说,这实际上是一个完全不存在的问题,因此,一个~/.cache适合我的需求的子目录完全可以避免安全问题。
2015年

mktemp在AIX上不可用,在Windows上不可用。看起来file.$RANDOM$RANDOM是便携式解决方案。在$RANDOM$RANDOM应增加空间以2 ^ 32,假设击随机结果是独立和不弱。

@jww Bash的随机结果很弱:它是一个LCG,它的可预测性与它一样好,同时对于许多不需要不可预测性的应用程序也足够好。
吉尔斯(Gillles)“所以-别再作恶了”

9

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

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

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

并且可能还在脚本被信号终止时。是否必须这样做是您必须决定的。

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


啊! 这非常有用;那我不需要打电话$RANDOM。但是,我的问题的第二部分–我以后如何访问该文件,或者在以后的脚本运行中检查该文件是否已经存在?(以实现非常简单的缓存。)
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.