将 AnsiString 对象归零的正确方法
Proper way to zero a AnsiString object
我们如何将 AnsiString 对象归零?例如:
void TesteClass::test()
{
AnsiString cardNumber = "1234567890123456";
..
}
AnsiString对象自动销毁,但其内部数据未清理,内存获取工具可以读取该信息。我们需要将此数据归零以避免敏感信息被捕获到内存中。
AnsiString class 有直接访问内部数据的方法 c_str()
,但不推荐这样做:
memset(cardNumber.c_str(), 0, cardNumber.Length());
在销毁对象之前将 AnsiString 内部数据置零的正确方法是什么?
如您所示,使用 memset()
没有任何问题。以这种方式使用 c_str()
是正确的(只要你不超过 Length()
,因为 c_str()
returns 如果 AnsiString
是指向常量内存的指针空白):
void TesteClass::test()
{
AnsiString cardNumber = "1234567890123456";
// ...
memset(cardNumber.c_str(), 0, cardNumber.Length());
}
既然担心信息泄露,可以考虑使用SecureZeroMemory()
instead of memset()
(see What’s the point of SecureZeroMemory?).
要自动归零(这样你就不必记住这样做),考虑将 AnsiString
包装在 RAII 样式 class
/struct
中(你不能直接从 AnsiString
派生,RTL 不允许),其析构函数执行归零,然后在需要的地方使用 class
/struct
而不是直接使用 AnsiString
。
请注意,因为 AnsiString
使用引用计数数据,所以不要将数据归零,除非您的 AnsiString
是引用数据的唯一实例:
class SaferAnsiString
{
private:
AnsiString m_Str;
void CheckZeroNeeded()
{
// AnsiString gained a public RefCount() method in C++Builder 2009.
// In earlier versions, access the reference count manually...
#ifdef _DELPHI_STRING_UNICODE
if (m_Str.RefCount() == 1)
#else
const void *data = m_Str.data();
if ((data) && (static_cast<const int*>(data)[-2] == 1))
#endif
SecureZeroMemory(m_Str.c_str(), m_Str.Length());
}
public:
SaferAnsiString(const AnsiString &src = AnsiString())
: m_Str(src)
{
}
~SaferAnsiString()
{
CheckZeroNeeded();
}
SaferAnsiString& operator=(const AnsiString &rhs)
{
CheckZeroNeeded();
m_Str = rhs;
return *this;
}
operator AnsiString () const { return m_Str; }
// other methods as needed...
};
void TesteClass::test()
{
SaferAnsiString cardNumber = "1234567890123456";
// ...
}
我们如何将 AnsiString 对象归零?例如:
void TesteClass::test()
{
AnsiString cardNumber = "1234567890123456";
..
}
AnsiString对象自动销毁,但其内部数据未清理,内存获取工具可以读取该信息。我们需要将此数据归零以避免敏感信息被捕获到内存中。
AnsiString class 有直接访问内部数据的方法 c_str()
,但不推荐这样做:
memset(cardNumber.c_str(), 0, cardNumber.Length());
在销毁对象之前将 AnsiString 内部数据置零的正确方法是什么?
如您所示,使用 memset()
没有任何问题。以这种方式使用 c_str()
是正确的(只要你不超过 Length()
,因为 c_str()
returns 如果 AnsiString
是指向常量内存的指针空白):
void TesteClass::test()
{
AnsiString cardNumber = "1234567890123456";
// ...
memset(cardNumber.c_str(), 0, cardNumber.Length());
}
既然担心信息泄露,可以考虑使用SecureZeroMemory()
instead of memset()
(see What’s the point of SecureZeroMemory?).
要自动归零(这样你就不必记住这样做),考虑将 AnsiString
包装在 RAII 样式 class
/struct
中(你不能直接从 AnsiString
派生,RTL 不允许),其析构函数执行归零,然后在需要的地方使用 class
/struct
而不是直接使用 AnsiString
。
请注意,因为 AnsiString
使用引用计数数据,所以不要将数据归零,除非您的 AnsiString
是引用数据的唯一实例:
class SaferAnsiString
{
private:
AnsiString m_Str;
void CheckZeroNeeded()
{
// AnsiString gained a public RefCount() method in C++Builder 2009.
// In earlier versions, access the reference count manually...
#ifdef _DELPHI_STRING_UNICODE
if (m_Str.RefCount() == 1)
#else
const void *data = m_Str.data();
if ((data) && (static_cast<const int*>(data)[-2] == 1))
#endif
SecureZeroMemory(m_Str.c_str(), m_Str.Length());
}
public:
SaferAnsiString(const AnsiString &src = AnsiString())
: m_Str(src)
{
}
~SaferAnsiString()
{
CheckZeroNeeded();
}
SaferAnsiString& operator=(const AnsiString &rhs)
{
CheckZeroNeeded();
m_Str = rhs;
return *this;
}
operator AnsiString () const { return m_Str; }
// other methods as needed...
};
void TesteClass::test()
{
SaferAnsiString cardNumber = "1234567890123456";
// ...
}