【发布时间】:2016-12-06 18:36:57
【问题描述】:
考虑一个场景,其中std::string 用于存储秘密。一旦它被消耗并且不再需要,最好清理它,即覆盖包含它的内存,从而隐藏 secret。
std::string 提供了一个函数 const char* data() 返回指向(C++11 起)连续内存的指针。
现在,由于内存是连续的并且由于范围结束,变量将在清理后立即销毁,是否安全:
char* modifiable = const_cast<char*>(secretString.data());
OpenSSL_cleanse(modifiable, secretString.size());
根据此处引用的标准:
$5.2.11/7 - 注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写操作由
const_cast产生,它丢弃了const-qualifier68 可能会产生未定义的行为 (7.1.5.1)。
这会建议其他情况,但上述条件(连续、即将删除)是否使其安全?
【问题讨论】:
-
不使用
OpenSSL_cleanse和可能的UB,为什么不遍历字符串并从PRNG 中为其分配随机值? -
另请注意,从 C++17 开始
data被重载以返回一个非 const 指针,以便您可以使用它。 -
@NathanOliver:我假设 OpenSSL_cleanse 已优化为使用尽可能少的
rand()(或类似)调用,同时保证可接受的安全性。想象一下在硬件上调用rand()的情况,并且可能代价高昂。此外,重新发明轮子......另一件事 - 正如@ilotXXI 在下面的评论中所说 - 天真的清晰可能会被优化掉(通常是)。 -
请注意,您还需要正确执行其他几件事才能进行秘密处理。其中包括使用 mlock'd 内存,因此它不能在交换中写入磁盘,确保它没有跨越缓存线边界,因此攻击者无法尝试使用超线程和缓存线反弹计数来检测有关它的东西。等等。真正考虑使用适当的安全库并使用它的数据结构,而不是 std::string。
-
你知道,你真的不想使用
std::string,而是一个真正的安全字符串类型来确保所有缓冲区都被清除。查看codereview.stackexchange.com/questions/107991/…,了解破解std::basic_string以满足需求的方法。