如何确保编译器优化不会带来安全风险?

ere*_*eOn 39 c++ memory compiler-construction security optimization

我必须编写一个Windows服务,在某些时候处理机密数据(如PIN码,密码等).这些信息需要很短的时间:通常它们几乎立即被发送到智能卡读卡器.

让我们考虑这段代码:

{
  std::string password = getPassword(); // Get the password from the user

  writePasswordToSmartCard(password);

  // Okay, here we don't need password anymore.
  // We set it all to '\0' so it doesn't stay in memory.
  std::fill(password.begin(), password.end(), '\0');
}
Run Code Online (Sandbox Code Playgroud)

现在我关心的是编译器优化.在这里,编译器可能会检测到密码即将被删除,并且此时更改其值是无用的,只需删除该调用即可.

我不希望我的编译器关心未来未引用的内存的价值.

我的担忧是否合法?我怎么能确定这样的代码不会被优化?

sha*_*oth 34

是的,您的担忧是合法的.您需要使用SecureZeroMemory()等专门设计的函数来防止优化修改代码行为.

不要忘记字符串类应该是专门为处理密码而设计的.例如,如果类重新分配缓冲区以保存更长的字符串,则必须先擦除缓冲区,然后再将其重新调整到内存分配器.我不确定,但它可能std::string不会这样做(至少在默认情况下).使用不合适的字符串处理类会使您的所有问题变得毫无价值 - 您甚至可以在程序内存中复制密码.

  • @ereOn:这很简单,编译程序时代码不会出现给编译器,因此编译器无法看到它并确定它"没有任何用处".例如,它可以编译成DLL,并且只能动态链接到. (2认同)

ybu*_*ill 9

这是有问题的,但另一个原因.谁说std::string password = getPassword();不会在记忆中留下另一份副本?(可能你需要在"destruct"或"deallocate"上为这个零内存写一个"安全"的分配器类)

在您的代码安静中,您可以通过获取指向字符串数据的易失性指针(我不知道您是否可以以标准方式执行)来避免优化,然后将数据归零.


sne*_*rch 8

不要使用std::string密码,因为在进行重新分配或破坏时它不会将其内存归零 - ConfidentialString而是设计自己的类.在设计该类时,您可能希望利用CryptProtectMemory ...并且在需要使用解密版本时非常非常小心,尤其是在调用外部代码时.