Delphi:如何从内存中完全删除字符串[重复]

Posted

技术标签:

【中文标题】Delphi:如何从内存中完全删除字符串[重复]【英文标题】:Delphi : how to completely remove String from the memory [duplicate] 【发布时间】:2013-12-06 15:57:58 【问题描述】:
Var
S1:String;
S2:String;
begin
   S1:='Sensitive Data';
   S2:=Crypt(S1,'encryption key');
   S1:='';
   FreeAndNil(S1);
end;

现在,当我使用“WinHex”之类的程序搜索我的进程内存时,我可以轻松找到未加密的字符串! 即使我尝试制作新表单来加密此字符串然后卸载表单但它仍然存在

有什么办法可以彻底消除

提前致谢

【问题讨论】:

所有字符串字面量将始终保留在内存中,因此如果您在测试项目中使用字符串字面量,但在真实代码中获取用户输入,您的测试将失败。 如果从内存中删除字符串会有什么帮助?它已经在可执行文件中。 处理完敏感数据后,将其覆盖。是的,取而代之的是安全的环境。 你为什么在字符串上调用 Free?你需要更好地理解。 如果您在加密时对其进行硬编码,并对加密值进行硬编码。该字符串将在内存中清晰可见,否则在可执行文件中可见。请记住,使用正确工具的人可以在解密并读取密钥时停止您的程序。打开一个十六进制编辑器并在你的 EXE 中搜索字符串——你会很明显地看到它。如果您在源外部对其进行加密,则加密字符串将可见。这不是一种安全的方法,但它确实可以让某人真正找到密钥。 【参考方案1】:

完成后,您需要用零覆盖字符串。像这样:

ZeroMemory(Pointer(s), Length(s)*SizeOf(Char));

如果您怀疑编译器会优化掉 ZeroMemory,那么您可以使用 SecureZeroMemory。但是,Delphi 编译器不会优化掉 ZeroMemory,所以这有点没有实际意义。

如果你只是写:

s := '';

然后内存将按原样返回给内存管理器。然后,您将无法控制内存管理器何时重用或归还内存。

显然,您需要对字符串的所有副本都这样做,因此唯一明智的方法是不要复制敏感数据。

根据您的问题,这对代码没有任何帮助,因为您的敏感数据是字符串文字,因此存储在可执行文件中。这种方法只能有意义地应用于动态数据。我认为您的真实程序不会将敏感数据放在文字中。

哦,永远不要将字符串传递给 FreeAndNil。您只能将对象变量传递给 FreeAndNil,但该过程使用无类型的 var 参数,因此编译器无法将您从错误中解救出来。

【讨论】:

谢谢,这正是我要说的:) 编译器可以决定优化它吗?也许通过优化关闭语句(如 win api 中的 SecureZeroMemory)(并在 jedi apilib 中实现)【参考方案2】:
Var
  S1:String;
  S2:String;
begin
   S1:='Sensitive Data';
   S2:=Crypt(S1,'encryption key');
   UniqueString(S1); // <-- if reference count of S1 is not 1
   ZeroMemory(Pointer(S1), Length(S1)*SizeOf(Char));
   // or better: SecureZeroMemory(Pointer(S1), Length(S1)*SizeOf(Char));
   S1:='';
end;

【讨论】:

我们应该确保 S1 仅通过引用传递给 Crypt 吗? @MarcusAdams:在这种情况下没关系,因为字符串是引用计数的,所以它仍然以一种或另一种方式相同的内存块.. 应该注意的是,您所呈现的以及您上面的 David 的代码将会崩溃。字符串S1 位于进程地址空间的只读页面中。你最好有一个BurnString 方法,它通过引用获取字符串,并调用System.UniqueString。这样您就不必担心那些秘密引用计数为零的“常量”字符串。 @IanBoyd: 大概'Sensitive Data''encryption key' 不是用户生产代码中的实际字面量,而是在运行时动态获取,从用户输入,加载一个键文件等。除了崩溃之外,如果它们是 actual 文字,那将是一个很大的安全风险,正如 Daniel Chapman 之前评论的那样。 你是绝对正确的。只需指出单个函数调用(在 99.99% 的情况下会变成无操作)就可以阻止奇怪的崩溃(例如,您有一个单元测试,以确保您开始使用的字符串与您的字符串匹配)最后)

以上是关于Delphi:如何从内存中完全删除字符串[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何删除一个字符串中某个字符或汉字——Delphi乐园

从单词中删除一个字母[重复]

每日一题-Day10-无重复最长字串

在delphi中如何获取字符串的内存地址

Javascript:从内存中删除一个 element.cloneNode() [重复]

如何在perl中的foreach循环中的字符串中查找和删除重复值的出现