ajd*_*jd. 17 c++ string passwords secure-coding
如何存储敏感数据(例如:密码)std::string?
我有一个应用程序,提示用户输入密码,并在连接设置期间将其传递给下游服务器.我想在建立连接后安全地清除密码值.
如果我将密码存储为char *数组,我可以使用SecureZeroMemory等 API 来清除进程内存中的敏感数据.但是,我想在代码中避免使用char数组,并且正在寻找类似的东西std::string?
ajd*_*jd. 12
根据这里给出的答案,我写了一个分配器来安全地记忆零.
#include <string>
#include <windows.h>
namespace secure
{
template <class T> class allocator : public std::allocator<T>
{
public:
template<class U> struct rebind { typedef allocator<U> other; };
allocator() throw() {}
allocator(const allocator &) throw() {}
template <class U> allocator(const allocator<U>&) throw() {}
void deallocate(pointer p, size_type num)
{
SecureZeroMemory((void *)p, num);
std::allocator<T>::deallocate(p, num);
}
};
typedef std::basic_string<char, std::char_traits<char>, allocator<char> > string;
}
int main()
{
{
secure::string bar("bar");
secure::string longbar("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,事实证明,根据std::string实现的方式,甚至可能不会为小值调用分配器.例如,在我的代码中,deallocate甚至没有调用字符串bar(在Visual Studio上).
答案是,我们不能使用std :: string来存储敏感数据.当然,我们可以选择编写一个处理用例的新类,但我特别感兴趣的是使用std::string定义的.
谢谢大家的帮助!
这是一个复杂的话题,因为优化编译器会对你不利。像循环字符串和覆盖每个字符这样的直接方法并不可靠,因为编译器可能会优化它。memset然而,与 相同,C11 添加了memset_s,它应该是安全的,但可能不适用于所有平台。
因此,我强烈建议使用可信的加密库来完成该任务,并让其作者负责可移植性。安全擦除是一项基本操作(获取 C 数组并安全地覆盖它),所有库都必须在某个时候实现它。请注意, a 中的基础数据std::string是连续的(按照C++11 标准的规定,但实际上,即使在 C++98/03 中,您也可以假设它)。std::string因此,您可以通过将视为数组来使用加密库的安全擦除功能。
在 OpenSSL 中,安全擦除是由该OPENSSL_cleanse函数提供的。加密++有memset_z:
std::string secret;
// ...
// OpenSSL (#include <openssl/crypto.h> and link -lcrypto)
OPENSSL_cleanse(&secret[0], secret_str.size());
// Crypto++ (#include <crypto++/misc.h> and link -lcrypto++)
CryptoPP::memset_z(&secret[0], 0, secret.size());
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果您从头开始设计 API,请考虑std::string在存储机密时完全避免。它的设计目标不是std::string防止泄露秘密(或在调整大小或复制过程中泄露部分秘密)。
openssl 经历了几次安全擦除字符串的迭代,直到它采用这种方法:
#include <string.h>
#include <string>
// Pointer to memset is volatile so that compiler must de-reference
// the pointer and can't assume that it points to any function in
// particular (such as memset, which it then might further "optimize")
typedef void* (*memset_t)(void*, int, size_t);
static volatile memset_t memset_func = memset;
void cleanse(void* ptr, size_t len) {
memset_func(ptr, 0, len);
}
int main() {
std::string secret_str = "secret";
secret_str.resize(secret_str.capacity(), 0);
cleanse(&secret_str[0], secret_str.size());
secret_str.clear();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7852 次 |
| 最近记录: |