как безопасно очистить std :: string? - PullRequest
17 голосов
/ 18 апреля 2011

Как хранить конфиденциальные данные (например, пароли) в std::string?

У меня есть приложение, которое запрашивает у пользователя пароль и передает его на нижестоящий сервер во время настройки соединения.Я хочу безопасно сбросить значение пароля после установления соединения.

Если я сохраню пароль в виде массива char *, я могу использовать API-интерфейсы, такие как SecureZeroMemory , чтобы избавиться отконфиденциальные данные из памяти процесса.Тем не менее, я хочу избежать массива символов в моем коде и ищу что-то подобное для std::string?

Ответы [ 4 ]

12 голосов
/ 20 апреля 2011

Основываясь на ответе, данном здесь , я написал распределитель для безопасного обнуления памяти.

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

Однако, в зависимости от того, как реализовано std::string, получается, чтоВозможно, что распределитель даже не вызывается для небольших значений.Например, в моем коде deallocate даже не вызывается для строки bar (в Visual Studio).

Таким образом, ответ заключается в том, что мы не можем использовать std :: string дляхранить конфиденциальные данные.Конечно, у нас есть возможность написать новый класс, который обрабатывает сценарий использования, но мне было особенно интересно использовать std::string, как определено.

Спасибо всем за вашу помощь!

2 голосов
/ 03 октября 2012

Для потомков я однажды решил проигнорировать этот совет и в любом случае использовать std :: string и написал метод zero (), используя c_str () (и отбрасывая константу) и volatile. Если я был осторожен и не вызывал перераспределение / перемещение содержимого, и я вручную вызывал ноль () там, где мне нужно было это очистить, казалось, что все работало правильно. Увы, я обнаружил еще один серьезный недостаток: сложный способ: std :: string также может быть объектом, на который ссылаются ... Разрыв памяти в c_str () (или памяти, на которую указывает объект, на который указывает ссылка) неосознанно разрушит другой объект .

1 голос
/ 18 апреля 2011

std :: string основан на символе *.Где-то позади вся динамическая магия как символ *.Поэтому, когда вы говорите, что не хотите использовать char * в своем коде, вы все еще используете char *, он просто на заднем плане с кучей мусора, сложенного поверх него.

Я не слишком разбираюсь в памяти процесса, но вы всегда можете перебирать каждый символ (после того, как вы зашифровали и сохранили пароль в БД?) И установить для него другое значение.

Естьтакже std :: basic_string, но я не уверен, какая помощь вам поможет.

0 голосов
/ 18 апреля 2011
std::string mystring;
...
std::fill(mystring.begin(), mystring.end(), 0);

или даже лучше написать свою собственную функцию:

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