是否有客观上更好的方法在 bash 脚本中创建临时文件?
我通常只是将它们命名为我想到的任何东西,例如 tempfile-123,因为它会在脚本结束时被删除。除了覆盖当前文件夹中可能的 tempfile-123 之外,这样做有什么缺点吗?或者以更谨慎的方式创建临时文件有什么好处?
手册页解释得mktemp(1)
很好:
传统上,许多 shell 脚本以 pid 作为后缀的程序名称并将其用作临时文件名。这种命名方案是可预测的,它创造的竞争条件很容易让攻击者获胜。一种更安全但仍然较差的方法是使用相同的命名方案创建一个临时目录。虽然这确实可以保证临时文件不会被破坏,但它仍然允许简单的拒绝服务攻击。由于这些原因,建议改用 mktemp。
在脚本中,我调用 mktemp 类似
mydir=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")
它创建了一个我可以在其中工作的临时目录,并且我可以在其中安全地将实际文件命名为可读且有用的名称。
mktemp
不是标准的,但它确实存在于许多平台上。“X”通常会被转换成一些随机性,更多的可能会更随机;但是,某些系统(例如,busybox ash)比其他系统更明显地限制了这种随机性
顺便说一句,临时文件的安全创建不仅对 shell 脚本很重要。这就是为什么 python 有tempfile, perl 有File::Temp, ruby 有Tempfile等等……</p>
你可能想看看mktemp
mktemp 实用程序采用给定的文件名模板并覆盖其中的一部分以创建唯一的文件名。模板可以是附加了一些“X”的任何文件名,例如/tmp/tfile.XXXXXXXXXX。尾随的“X”被当前进程号和随机字母的组合替换。
更多细节:man mktemp
以更谨慎的方式创建临时文件有什么好处吗
/tmp
临时文件通常创建在所有其他用户和进程具有读写权限的临时目录(例如)中(任何其他脚本都可以在那里创建新文件)。因此脚本应该小心创建文件,例如使用正确的权限(例如只读所有者,请参阅:),help umask
并且文件名应该不容易猜到(理想情况下是随机的)。否则,如果文件名不是唯一的,它可能会与多次运行的同一脚本产生冲突(例如竞争条件) 或者一些攻击者可以劫持一些敏感信息(例如,当权限太开放并且文件名很容易猜到时)或者用他们自己的代码版本创建/替换文件(比如根据正在替换的命令或 SQL 查询存储)。
您可以使用以下方法来创建临时目录:
TMPDIR=".${0##*/}-$$" && mkdir -v "$TMPDIR"
或临时文件:
TMPFILE=".${0##*/}-$$" && touch "$TMPFILE"
然而,它仍然是可预测的,并不被认为是安全的。
根据man mktemp
,我们可以阅读:
传统上,许多 shell 脚本以 pid 作为后缀的程序名称并将其用作临时文件名。这种命名方案是可预测的,它创造的竞争条件很容易让攻击者获胜。
所以为了安全起见,建议使用mktemp
命令创建唯一的临时文件或目录(-d
)。
mktemp
可能是最通用的,特别是如果您打算使用该文件一段时间。
如果您只需要临时将该文件作为另一个命令的输入,您也可以使用进程替换运算符,例如: <()
$ diff <(echo hello world) <(echo foo bar)
mktemp
文档有一些很好的例子。
如果您的临时文件需要特定的后缀(文件扩展名)。您可以执行以下操作
$ myfile=$(mktemp --suffix ".txt")
$ echo "$myfile"
/tmp/tmp.9T9soL2QNp.txt
如果您不想创建文件,而只是想要一个名称,则可以另外使用该-u/--dry-run
标志。
$ myfile=$(mktemp -u --suffix ".txt")
$ echo "$myfile"
/tmp/tmp.Y8cMDJ1DDr.txt
但请注意,使用时-u/--dry-run
使用此命令的输出创建一个新文件本质上是不安全的,因为在生成名称和使用它之间有一个时间窗口,另一个进程可以创建同名对象。