5

一般的问题是:在 PHP 中未设置该变量后,是否可以从物理内存中删除字符串变量的值?

该问题源于安全标准的某些要求(在处理某些重要数据时,不应将数据从内存转储到磁盘)。根据“内存加密吗? ”主题没有加密内存数据的好方法。

因此,在 PHP 中取消设置 String 变量时,您不能确定内存中的数据已被覆盖。关于将新值设置为变量的相同故事。

因此,我很感兴趣是否可以在不更改unset方法核心代码的情况下从内存中清除变量值?

4

3 回答 3

5

首先,我不确定擦除字符串是否符合您描述的安全要求,因为理论上仍然可以在字符串被擦除之前转储内存。但这无论如何都是不可能的,因为如果没有将数据存储在内存中,您就无法处理数据。

无论如何,如果你想确保字符串被擦除,我认为在 PHP 中这样做的唯一方法是遍历字符串并修改每个字符:记住,内存的内容在被覆盖之前不会消失,即使你有没有对变量的引用并且 PHP GC 已经运行。

我相信这会奏效:

for( $i=0; $i < strlen($str); $i++ )
    $str[$i] = 'x';
于 2012-04-10T12:48:59.797 回答
0

tl; dr:在彻底测试了许多组合之后,似乎for覆盖每个字符的循环清除/更改了内存中的字符串内容。请注意初始内容的来源,它可能仍然存在于这些变量中!请参阅下面的更新

用 PHP 5.6 做了一些测试:

<?php
     $cc = 'AAAABBBBCCCCDDDD';
     #v1:  unset($cc);
     #v2:  $cc=null;
     #v3:  for( $i=0; $i < strlen($cc); $i++ ) $cc[$i] = 'x';
     sleep(500); // enough time for taking script pid and run the memory dump
?>

尝试了上述脚本的每个版本(启用#v1,启用#v2,启用#v3);转储进程的内存(请参阅https://serverfault.com/a/408929/374467)并且“AAAABBBBCCCCDDDD”字符串始终显示在生成的二进制文件中(其中包含进程内存)。当 $cc 值作为命令行参数 ($argv) 发送时也进行了测试。结果相同。

迄今为止,我发现在 PHP 中没有可靠的方法来做到这一点。

更新

正如评论中所建议的,使用字符串文字来初始化变量可能会影响结果,因为文字可能保存在内存中。因此,我更改了脚本,使其从 cli 获取参数并通过应用str_rot13()来初始化变量,确保变量的内容是new。我还添加gc_collect_cycles()了强制垃圾收集。所以测试脚本看起来像这样:

<?php
     $cc = str_rot13($argv[1]);
     #v1:  unset($cc);
     #v2:  $cc=null;
     #v3:  for( $i=0; $i < strlen($cc); $i++ ) $cc[$i] = 'x';
     gc_collect_cycles();
     sleep(120); // enough time for taking script pid and run the memory dump
     echo "done \n";
?>

似乎前两种方法(unset/null)不会从内存中清除$cc(即使 gc_collect_cycles 开启)但循环for实际上改变了它!即使使用或不使用 gc_collect_cycles。

使用 PHP 7.2.20 (cli) 测试。

注意您仍然可以在内存中找到参数 ($argv) 的初始值!

于 2016-11-18T15:10:12.810 回答
-2

据我了解,问题不在于使用unset()或 PHP 的垃圾收集器,而是确保使用的内存实际上在物理级别被清除?

简单的方法 - 只需在取消设置(或任何其他值)之前将其设置为 null 查看使用 PHP 释放内存的好处:unset() 或 $var = null

艰难而愚蠢的方法是用垃圾分配所有 php 内存,以确保其被覆盖,但我不确定虚拟内存是否固定在预定义的音调上,或者根据进程需要进行更改。

于 2012-04-10T12:38:14.020 回答