Безопасно ли обнулять длину BSTR вручную, потому что ZeroFreeBSTR нет? (с SecureString) - PullRequest
0 голосов
/ 28 августа 2018

SecureString в .NET хранит символы в зашифрованном виде, однако доступ к открытому тексту можно получить с помощью Marshal.SecureStringToBSTR, который расшифровывает буфер в неуправляемый буфер, а затем можно проверить строку. В соответствии с передовой практикой этот буфер должен быть очищен с использованием Marshal.ZeroFreeBSTR, чтобы гарантировать отсутствие в памяти символов экземпляра SecureString, например, приведенный ниже код безопасно выполняет итерацию по каждому символу в SecureString таким образом, чтобы предотвратить вся строка копируется в управляемую память:

SecureString ss = ...
IntPtr bstr = Marshal.SecureStringToBSTR( ss );
if( bstr != IntPtr.Zero )
{
    try
    {
        Int32 length = Marshal.ReadInt32( bstr, -4 ) / 2; // a BSTR length is stored in the 4 bytes immediately before the first character of the string.
        for( Int32 i = 0; i < length; i++ )
        {
            Char c = (Char)Marshal.ReadInt16( bstr, i * 2 );
            Console.Write( c );
        }
    }
    finally
    {
        Marshal.ZeroFreeBSTR( bstr );
        bstr = IntPtr.Zero;
    }
}

Макет памяти BSTR имеет 4-байтовый префикс длины непосредственно перед первым символом строки, однако я заметил, что хотя Marshal.ZeroFreeBSTR обнуляет символы строки, он не обнуляет длину BSTR префикс - это означает, что существует вероятность раскрытия информации (в частности, длины пароля), если другой процесс отслеживает память моего процесса.

Я мог бы обойти это, вручную обнулив его:

    finally
    {
        Marshal.ZeroFreeBSTR( bstr );
        Marshal.WriteInt16( bstr, -4, 0 );
        bstr = IntPtr.Zero;
    }

... но я не знаю, есть ли причина ZeroFreeBSTR не очищает префикс длины, возможно, он используется в другом месте для домашнего хозяйства? Это безопасно?

Вот несколько скриншотов окна Памяти в VS.

Вот буфер BSTR в памяти непосредственно перед вызовом ZeroFreeBSTR, красная область - это поле длиной 4 байта, а синяя область - это символы wchar_t с нулевым символом в конце:

enter image description here

Вот та же память сразу после возврата ZeroFreeBSTR. Символы были обнулены, но значение длины (6 == 0x0C) остается:

enter image description here

...