Подтвердить что ты не робот

Как безопасно очистить std::string?

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

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

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

4b9b3361

Ответ 1

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

#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

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

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

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

Ответ 3

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

Ответ 4

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

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

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