Security 从内存中显式删除敏感数据?

Security 从内存中显式删除敏感数据?,security,memory,Security,Memory,维基解密最近的泄密: 明确删除敏感数据(加密密钥、原始收集) 数据、外壳代码、上传的模块等)在 不再需要纯文本形式的数据 在终止时,不要依赖操作系统来执行此操作 执行 我是*nix世界的开发者;我认为这仅仅是改变变量的值(确保我不通过值传递,而是通过引用传递);如果它是一个100个字符的字符串;正在写入0,即101个字符。真的这么简单吗?如果没有,为什么要这样做,应该做些什么 注:有类似的问题问这个问题;但这是在C#和Windows世界。所以,我不认为这个问题是重复的。 在完成这些秘密之后,立即

维基解密最近的泄密:

明确删除敏感数据(加密密钥、原始收集) 数据、外壳代码、上传的模块等)在 不再需要纯文本形式的数据

在终止时,不要依赖操作系统来执行此操作 执行

我是*nix世界的开发者;我认为这仅仅是改变变量的值(确保我不通过值传递,而是通过引用传递);如果它是一个100个字符的字符串;正在写入0,即101个字符。真的这么简单吗?如果没有,为什么要这样做,应该做些什么

注:有类似的问题问这个问题;但这是在C#和Windows世界。所以,我不认为这个问题是重复的。

在完成这些秘密之后,立即清除秘密(密码、密钥等)是相当标准的做法。困难在于如何处理可能妨碍您的语言和平台特性

例如,如果编译器确定写后没有读取数据,C++编译器可以调用<代码> MyStuts<代码>。或者操作系统可能已经分页了,这样可能会留下可用的数据

我是*nix世界的开发者;我认为这仅仅是 更改变量的值(确保不传递值;以及 而是通过引用);如果它是一个100个字符的字符串; 正在写入0,即101个字符。真的这么简单吗?如果没有,, 为什么以及应该做些什么

应该是这么简单。魔鬼在于细节

  • 内存分配函数(如realloc)不能保证不占用内存(您不应该依赖它们以这种或那种方式完成—另请参见)。如果您分配1K内存,然后将其重新分配到10K,那么您原来的K可能仍在其他地方,包含其敏感负载。然后,它可能会被另一个不敏感的变量或缓冲区分配,也可能不会,通过新变量,它可能会访问部分或全部旧内容,就像某些文件系统上的空闲空间一样
  • 手动调零内存(对于大多数编译器,
    bzero
    memset
    都算作手动循环)可能会被轻松地优化掉,尤其是在对局部变量进行调零时(,有解决方法)
  • 有些函数可能会在本地缓冲区或它们分配和释放的内存中留下“跟踪”
  • 在某些语言和框架中,数据的整个部分最终可能会被移动(例如@gene注意到的所谓“垃圾收集”期间)。您可以告诉GC不要处理您的敏感区域,或者以其他方式“固定”敏感区域,如果是这样,则必须这样做。否则,数据可能会以多个部分副本的形式结束
  • 信息可能已经通过并留下了您不知道的痕迹(简单的示例:通过网络发送的密码可能会在网络库读取缓冲区中保留)
  • 活动内存可能被换出磁盘
realloc
执行其操作的示例。内存被部分重写,对于某些库,只有在“a”不是唯一分配的区域时,这才“起作用”(因此您还需要声明c,并在a之后立即分配一些内容,以便a不是最后一个对象,可以自由增长):

输出:

 a at 19828752 is Hello...world
 a at 19828752 is 8????...world, b at 19830832 is Hey!
因此,地址a的内存被部分重写——“你好”丢失,“世界”仍然存在(以及在b+200)

所以你需要自己处理敏感区域的重新分配;更好的是,在程序启动时预先分配所有资源。然后,告诉操作系统必须有一个敏感的内存区域。然后需要以编译器不会干扰的方式将其归零。你需要使用一个你确信不会自己做事情的方法:一个简单的字符串连接可以产生两到三个数据副本——我相当肯定它发生在PHP5.2中

很久以前,我为自己编写了一个小库,当时还没有valgrind,灵感来自Steve Maguire编写的可靠代码,除了覆盖各种内存和字符串函数外,我还覆盖了内存,然后计算了被覆盖缓冲区的校验和。这不是为了安全,我用它来跟踪缓冲区上/下的流,双重释放,释放内存的使用——诸如此类的事情

然后,你需要确保你的故障保护工作-例如,如果程序中止会发生什么?有没有可能让它故意中止

您需要实施纵深防御,并始终寻找尽可能少地保留信息的方法-例如,在计算过程中清除中间缓冲区,而不是等待并在最后一次性释放整个批次,或者在退出程序时;尽可能保留哈希而不是密码;等等


当然,所有这些都取决于信息的敏感程度以及攻击面可能是什么(强制xkcd参考:)。使用映像重新启动电脑可能是一种可行的选择。设想一台双引导计算机,将memtest86设置为测试内存,并将电脑断电作为默认引导选项。当您想关闭系统时。。。你可以重新启动它。电脑将重新启动,默认情况下输入memtest86,在永久断电之前,它将开始用0和1组成的行进队伍填充所有可用的RAM。幸运的是,我找到了关于特定gcc“bug”(这不是一个bug-优化器按预期工作)的讨论,并找到了解决方法。您忘记了一点:在使用分代垃圾收集等语言的情况下,收集器可以在程序运行时或多或少地将数据复制到新位置,这是它看不见的。拷贝在数据的上一代中被留下。一个能抓拍竞技场的坏蛋可以看到你的程序的一大块前镜头
 a at 19828752 is Hello...world
 a at 19828752 is 8????...world, b at 19830832 is Hey!