安全地使用临时文件

时间:2013-01-09 08:17:32

标签: c++ windows winapi temporary-files

我的程序中使用了一个静态库,它只能将文件名作为输入,而不是实际的文件内容。关于图书馆的源代码,我无能为力。所以我想:创建一个全新的文件,将数据存储到处理中,将其刷新到磁盘上(?),将其名称传递给库,然后将其删除。

但我也希望这个过程相当安全:
1)文件必须重新创建,没有任何虚假数据(可能不是关键,但无论如何);
2)除了我的进程之外的任何人都不能能够读取或写入此文件(我希望库能够处理我的实际数据,而不是虚假数据一些明智的设法插上);
3)在我完成这个文件之后,必须被删除(好吧,如果有人TerminateProcess()我,我想没有什么可以做的,但仍然是。)

该库似乎使用非Unicode fopen()来打开给定的文件,因此我不太清楚如何处理所有这些,因为该程序旨在在Windows上运行。有什么建议吗?

6 个答案:

答案 0 :(得分:4)

你已经提出了很多建议,但我提到的另一个选择是使用命名管道。它将取决于所讨论的库是否有效,但它可能值得一试。您可以使用CreateNamedPipe函数在应用程序中创建命名管道,并将管道名称传递给库进行操作(您将传递的文件名为 \\。\ pipe \ PipeName < /强>)。您是否需要尝试使用这样的文件名,但是如果它起作用,则优点是您的文件永远不必实际写入磁盘。

答案 1 :(得分:2)

这可以使用CreateFileGetTempFileName函数来实现(如果您不知道是否可以写入当前工作目录,您可能还想使用GetTempPath )。

  1. 确定存储临时文件的目录;当前目录(“。”)或GetTempPath的结果将是很好的候选人。
  2. 使用GetTempFileName创建临时文件名。
  3. 最后,请致电CreateFile以创建临时文件。
  4. 最后一步,有几点需要考虑:

    • dwFlagsAndAttributes的{​​{1}}参数应该包含CreateFile
    • FILE_ATTRIBUTE_TEMPORARY参数可能还应该包含dwFlagsAndAttributes以确保文件被删除无论如何(如果您的进程崩溃,这可能也有效,在这种情况下系统会为您关闭所有句柄)。
    • FILE_FLAG_DELETE_ON_CLOSE的{​​{1}}参数可能应为dwShareMode,以便其他尝试打开文件的操作会成功,但仅用于阅读。这意味着您的库代码将能够读取该文件,但没有人能够写入它。

答案 2 :(得分:1)

This article应该就此问题提供一些很好的指导。

问题的关键在于:

  • POSIX mkstemp()功能是可用的安全和首选解决方案。不幸的是,它在Windows中不可用,因此您需要找到一个使用Windows API调用正确实现此功能的包装器。
  • 在Windows上,tmpfile_s()函数是唯一一个以原子方式实际打开临时文件的函数(而不是简单地生成文件名),保护您免受竞争条件的影响。不幸的是,此功能不允许您指定将在哪个目录中创建文件,这是一个潜在的安全问题。

答案 3 :(得分:0)

首先,您可以在用户的​​临时文件夹中创建文件(例如C:\ Users \\ AppData \ Local \ Temp) - 这是此类文件的理想之选。其次,当creating a file时,您可以指定您提供的访问共享类型。

MSDN上的CreateFile帮助页面的片段:

  

dwShareMode

     
      
  • 0 防止其他进程打开文件或设备   如果他们请求删除,读取或写入访问权限。
  •   
  • FILE_SHARE_DELETE 启用对文件或设备的后续打开操作   请求删除访问权限否则,其他进程无法打开文件或设备   请求删除访问权限如果未指定此标志,但已打开文件或设备以进行删除访问,则该功能将失败。注意:删除访问权限允许删除和重命名操作。
  •   
  • FILE_SHARE_READ 在a上启用后续打开操作   请求读访问的文件或设备。否则,如果其他进程请求读取访问权限,则无法打开该文件或设备。如果未指定此标志,但已打开文件或设备以进行读取访问,则该函数将失败。
  •   
  • FILE_SHARE_WRITE 启用文件或设备上的后续打开操作以请求   写入权限。   否则,其他进程无法打开文件或设备   请求写入权限。   如果未指定此标志,但已打开文件或设备   对于写访问或具有写访问的文件映射,该函数   失败。
  •   

答案 4 :(得分:0)

虽然给出的建议很好,例如使用FILE_SHARE_READ,FILE_DELETE_ON_CLOSE等,但我认为没有一种完全安全的方法可以做到这一点。

我已经使用Process Explorer来关闭旨在阻止第二个进程启动的文件 - 我之所以这样做是因为第一个进程被卡住并且“不能杀死而且没有死,但没有响应”,所以我有一个正当的理由这样做 - 我不希望由于系统上运行的其他进程而在该特定点重启机器。

如果有人使用某种类型的调试器[包括非商业用途,专门为此目的编写],附加到正在运行的进程,设置断点并停止代码,然后关闭已打开的文件,它可以写入到你刚刚创建的文件。

你可以让它变得更难,但你不能阻止有足够特权/技能/能力的人拦截你的程序和操纵数据。

请注意,文件/文件夹保护仅在您可靠地知道用户在计算机上没有特权帐户时才有效 - 典型的Windows用户可以是管理员,也可以有其他帐户用于管理目的 - 我可以访问sudo / root几乎在我工作中使用的所有Linux机器上 - 有些文件服务器我不[也不应该]具有root访问权限。但是我自己使用的所有盒子或者可以借用测试目的,我可以进入根环境。这不是很不寻常。

我能想到的解决方案是找到一个使用不同接口的不同库[或者获取库的源代码并对其进行修改]。并非这可以防止使用上述调试器方法进行“停止,修改和转移”攻击。

答案 5 :(得分:-1)

使用CreateFile API在可执行文件夹中创建文件,每次创建文件名时都可以给文件名一些UUID,这样任何其他进程都无法猜出文件名来打开它。并将其属性设置为隐藏。使用它之后,只需删除文件即可。够了吗?