how does one securely clear std::string?

拟墨画扇 提交于 2019-12-17 09:41:56

问题


How does one store sensitive data (ex: passwords) in std::string?

I have an application which prompts the user for a password and passes it to a downstream server during connection setup. I want to securely clear the password value after the connection has been established.

If I store the password as a char * array, I can use APIs like SecureZeroMemory to get rid of the sensitive data from the process memory. However, I want to avoid char arrays in my code and am looking for something similar for std::string?


回答1:


Based on the answer given here, I wrote an allocator to securely zero memory.

#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");
  }
}

However, it turns out, depending on how std::string is implemented, it is possible that the allocator isn't even invoked for small values. In my code, for example, the deallocate doesn't even get called for the string bar (on Visual Studio).

The answer, then, is that we cannot use std::string to store sensitive data. Of course, we have the option to write a new class that handles the use case, but I was specifically interested in using std::string as defined.

Thanks everyone for your help!




回答2:


For posterity, I once decided to ignore this advice and use std::string anyway, and wrote a zero() method using c_str() (and casting away the constness) and volatile. If I was careful and didn't cause a reallocate/move of the contents, and I manually called zero() where I needed it clean, all seemed to function properly. Alas, I discovered another serious flaw the hard way: std::string can also be a referenced-counted object... blasting the memory at c_str() (or the memory the referenced object is pointing to) will unknowingly blast the other object.




回答3:


std::string is based on a char*. Somewhere behind all the dynamic magic as a char*. So when you say you don't want to use char*'s on your code, you are still using a char*, it's just in the background with a whole bunch of other garbage piled on top of it.

I'm not too experienced with process memory, but you could always iterate through each character (after you've encrypted and stored the password in a DB?), and set it to a different value.

There's also a std::basic_string, but I'm not sure what help that would do for you.




回答4:


std::string mystring;
...
std::fill(mystring.begin(), mystring.end(), 0);

or even better write your own function:

void clear(std::string &v)
{
  std::fill(v.begin(), v.end(), 0);
}



回答5:


openssl went through a couple of iterations of securely erasing a string until it settled on this approach:

#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;
}


来源:https://stackoverflow.com/questions/5698002/how-does-one-securely-clear-stdstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!