@
remaerd Keys 和 1Password 都用了 Core Framework,不代表两者在关键信息的内存管理方式上就是一样的。
1Password 不一定不存在数据暴露的问题。
直接使用 CommonCrypto 也可能存在数据暴露的问题,但可能性远远小于二次封装的使用方式。
内存的分配和回收不是重点,重点是数据在内存中的映射方式。有太多的方式获得内存的 Raw 数据,但这样的数据并没有实际价值,只有在其基础上获得每一块内存的数据定义才有意义。
比如 Wrapper A 的实现,某个 key 在内存中是连续 32 Bytes 存储的,应用访问它的方式是通过某个指针获得起始内存地址。对于该应用本身而言,它是不关心 key 到底在内存的哪个位置,它只要知道访问它的指针即可。
对于另一应用 B 来说,如果通过某种手段获得了对 A 内存空间的访问权限,它获取的是某个内存页面的完整信息,但并不知道该 key 到底在哪个地址上。连续 32 Bytes 有太多可能性。
对于依赖操作系统进行内存管理的应用来说,对于确定的执行流程,数据在内存中的分布有很大可能性是“可预测的”。
更大的漏洞来源于非人工内存管理带来的多重副本问题。原则上如 key 这样的敏感信息,在内存中应当仅存在一份副本,依赖操作系统对应用内存进行管理时,很可能会造成该 key 在内存中存在多个副本。攻击方寻找一份 32 Bytes 的内容很困难,但是当内存快照中存在多个相同 32 Bytes 连续内容时,提取出该 key 的可能性就非常大了。
(PBKDF 的白皮书就推荐 pbkdf() 只通过引用传递而不是值拷贝的方式来传入 passphrase,目的是保证敏感信息在内存中只存在一份)
CommonCrypto/libssl 等底层实现在内存管理上都有特殊之处,就是为了避免当运行时内存被快照化提取后,关键信息不会(轻易)泄漏。理论上内存信息泄漏了,关键信息也随之泄漏了,改变关键信息在内存中分布的目的就是:即使攻击者可以获取内存,也知道关键信息一定在这段内存里,但就是不知道具体哪一部分才是关键信息。