写入文件并以原子方式执行

问题描述

假设我在内存中有一个可执行文件(或 bat 脚本,无关紧要)的内容,并希望将它作为一个新进程运行。这很容易。

File.WriteAllBytes(filePath,contents);
// gap
Process.Start(filePath)

但我想确保执行的文件没有被任何其他进程篡改。文件创建和执行之间存在差距。它提供了使用正确工具篡改文件的机会。

因此,我没有打开 File.WriteAllBytes,而是打开一个 FileStream FileShare.Read 并保持打开状态,直到执行完成。

using(var fileStream = new FileStream(filePath,FileMode.CreateNew,FileAccess.Write,FileShare.Read))
{
    Process.Start(filePath)
}

但这行不通。 Process.Start 失败:

System.ComponentModel.Win32Exception (32):该进程无法访问该文件,因为它正被另一个进程使用。

This question and its answer explains why I think。简而言之,Process.Start 将尝试使用 FileShare.Read 打开文件并失败,因为打开的 FileStream 已经具有写入权限,因此进程的 FileShare.Read 尝试失败。

有没有办法干净利落地做到这一点?

一种解决方法我能想到的就是保存文件,关闭它,用FileShare.ReadFileAccess.Read打开一个新的FileStream,确保内容还是一样的在执行之前。但这并不漂亮。

解决方法

您所描述的是一个典型的 Time of check to time of use 漏洞案例。

任何涉及检查某些内容然后执行它的解决方案,并且这两个操作不是原子的,仍然会让您容易受到攻击。例如:

在执行之前确保内容仍然相同。但这并不漂亮

“确保内容仍然相同”和“执行它”之间仍然存在(较小的)差距(时间窗口)。

2004 年发表了一个不可能的结果,表明没有可移植的、确定性的技术来避免 TOCT-TOU 竞争条件

-https://web.cecs.pdx.edu/~markem/CS333/handouts/tocttou.pdf

你可以做一些事情来缓解它:

  • 不要使用文件!你说你的内存中有一些代码需要执行:你能在同一个进程中自己执行吗?

  • 减少时间窗口。

  • 使文件名随机且难以预测其他进程。

  • 在攻击者(或恶意程序)运行的可能性较小的情况下,以单独的用户身份运行您的程序,并将文件读/写限制为仅限新用户。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...