Вопрос

Я пытаюсь понять назначение SecureString в .NET.NET.Из MSDN:

Экземпляр System.Класс String является неизменяемым и, когда он больше не нужен, не может быть программно запланирован для сборки мусора;то есть экземпляр доступен только для чтения после его создания, и невозможно предсказать, когда экземпляр будет удален из памяти компьютера.Следовательно, если объект String содержит конфиденциальную информацию, такую как пароль, номер кредитной карты или личные данные, существует риск, что информация может быть раскрыта после ее использования, поскольку ваше приложение не может удалить данные из памяти компьютера.

Объект SecureString похож на объект String в том смысле, что он имеет текстовое значение.Однако значение объекта SecureString автоматически шифруется, может быть изменено до тех пор, пока ваше приложение не пометит его как доступное только для чтения, и может быть удалено из памяти компьютера либо вашим приложением, либо сборщиком мусора .NET Framework.

Значение экземпляра SecureString автоматически шифруется при инициализации экземпляра или изменении значения.Ваше приложение может сделать экземпляр неизменяемым и предотвратить дальнейшие изменения, вызвав метод MakeReadOnly.

Является ли автоматическое шифрование большим выигрышем?

И почему я не могу просто сказать:

SecureString password = new SecureString("password");

вместо того, чтобы

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

Какой аспект SecureString я упускаю из виду?

Это было полезно?

Решение

Некоторые части фреймворка, которые в настоящее время используют SecureString:

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

Как уже говорили другие, причина, по которой вы должны создать SecureString посимвольный переход происходит из-за первого очевидного недостатка в противном случае:предположительно, у вас уже есть секретное значение в виде простой строки, так в чем же смысл?

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

Другие советы

Множество отличных ответов;вот краткий обзор того, что уже обсуждалось.

Корпорация Майкрософт внедрила класс SecureString в попытке обеспечить лучшую безопасность конфиденциальной информации (например, кредитных карт, паролей и т.д.).Это автоматически обеспечивает:

  • шифрование (в случае сброса памяти или кэширования страниц)
  • закрепление в памяти
  • возможность пометки "только для чтения" (для предотвращения любых дальнейших изменений)
  • безопасная конструкция, НЕ позволяющая передавать постоянную строку в

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

Основываясь на этой информации, конструктор SecureString не должен просто брать строку и нарезать ее до массива символов, поскольку прописывание строки противоречит назначению SecureString .

Дополнительная информация:

  • A Публикация из блога .NET Security говорится о том же, о чем и описано здесь.
  • И еще один один возвращаюсь к нему и упоминаю инструмент , который МОЖЕТ выгружать содержимое SecureString.

Редактировать:Мне было трудно выбрать лучший ответ, так как во многих книгах есть хорошая информация;очень жаль, что нет дополнительных вариантов ответа.

Краткий Ответ

почему я не могу просто сказать:

SecureString password = new SecureString("password");

Потому что теперь у вас есть password в памяти;без возможности стереть его - в чем как раз и заключается смысл Безопасная строка.

Длинный Ответ

Причина Безопасная строка существует потому, что вы не можете использовать Нулевая память чтобы стереть конфиденциальные данные, когда вы закончите с этим.Он существует для решения существующей проблемы потому что из CLR.

В обычном родной приложение, которое вы бы назвали SecureZeroMemory:

Заполняет блок памяти нулями.

Примечание:SecureZeroMemory идентична ZeroMemory, за исключением того, что компилятор не будет его оптимизировать.

Проблема в том, что вы не могу звонить ZeroMemory или SecureZeroMemory внутри.СЕТЬ.А в .NET строки неизменяемы;ты даже не можешь перезаписать содержимое строки, как вы можете сделать на других языках:

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

Так что же вы можете сделать?Как мы можем предоставить в .NET возможность стереть пароль или номер кредитной карты из памяти, когда мы закончим с этим?

Единственный способ, которым это можно сделать, - поместить строку в какой-нибудь родной блок памяти, где вы может тогда звони ZeroMemory.Собственный объект памяти, такой как:

  • a BSTR
  • глобальный объект
  • Неуправляемая память CoTaskMem

SecureString возвращает утраченную способность

В .NET строки не могут быть удалены, когда вы закончите с ними:

  • они неизменяемы;вы не можете перезаписать их содержимое
  • ты не можешь Dispose из них
  • их очистка зависит от сборщика мусора

SecureString существует как способ обеспечить безопасность строк и быть в состоянии гарантировать их очистку, когда вам это нужно.

Вы задали этот вопрос:

почему я не могу просто сказать:

SecureString password = new SecureString("password");

Потому что теперь у вас есть password в памяти;без возможности стереть его.Он застрял там до тех пор, пока среда CLR случайно не решит повторно использовать эту память.Вы вернули нас к тому, с чего мы начали;запущенное приложение с паролем, от которого мы не можем избавиться, и где дамп памяти (или монитор процесса) может видеть пароль.

SecureString использует API защиты данных для хранения зашифрованной строки в памяти;таким образом, строка не будет существовать в файлах подкачки, аварийных дампах или даже в окне локальных переменных, когда коллега просматривает ваш should.

Как мне прочитать пароль?

Тогда возникает вопрос:как мне взаимодействовать со строкой?Ты абсолютно не надо хотите такой метод, как:

String connectionString = secureConnectionString.ToString()

потому что теперь вы вернулись к тому, с чего начали, - к паролю, от которого вы не можете избавиться.Ты хочешь сила разработчикам необходимо правильно обрабатывать чувствительную строку - так, чтобы она может быть стертым из памяти.

Вот почему .NET предоставляет три удобные вспомогательные функции для преобразования SecureString в неуправляемую память:

Вы преобразуете строку в неуправляемый большой двоичный объект памяти, обрабатываете его, а затем снова стираете.

Некоторые API принимают Защитные нити.Например, в ADO.net 4.5 SqlConnection.Учетные данные требуется набор SqlCredential ( исходный код ):

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

Вы также можете изменить пароль в строке подключения:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

И внутри есть много мест .NET, где они продолжают принимать обычную строку в целях совместимости, затем быстро разворачиваются и помещают ее в SecureString .

Как поместить текст в SecureString?

Это все еще оставляет проблему:

Как мне вообще ввести пароль в SecureString?

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

Иногда функциональность уже предусмотрена для вас.Например, WPF Поле пароля система управления может вернуть вам введенный пароль в качестве Безопасная строка непосредственно:

Поле пароля.Свойство SecurePassword

Получает пароль, который в данный момент хранится у Поле пароля в качестве Безопасная строка.

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

Преобразовать SecureString достаточно просто:

  • SecureStringToBSTR
  • PtrToStringBSTR

как в:

private static string CreateString(SecureString secureString)
{
    IntPtr intPtr = IntPtr.Zero;
    if (secureString == null || secureString.Length == 0)
    {
        return string.Empty;
    }
    string result;
    try
    {
        intPtr = Marshal.SecureStringToBSTR(secureString);
        result = Marshal.PtrToStringBSTR(intPtr);
    }
    finally
    {
        if (intPtr != IntPtr.Zero)
        {
            Marshal.ZeroFreeBSTR(intPtr);
        }
    }
    return result;
}

Они просто на самом деле не хотят, чтобы ты это делал.

Но как мне перевести строку в SecureString?Ну, что вам нужно сделать, это перестать иметь пароль в Строка в первую очередь.Тебе нужно было иметь это в виду что - то ещё.Даже Char[] массив был бы полезен.

Вот тогда вы сможете добавлять каждый символ и сотрите открытый текст, когда закончите:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

Вам нужно, чтобы ваш пароль хранился в некоторые память, которую вы можете стереть.Оттуда загрузите его в SecureString.


tl;dr: Безопасная строка существует для обеспечения эквивалента Нулевая память.

Некоторые люди не видят смысла в удаление пароля пользователя из памяти при блокировке устройства, или протирание удаление нажатий клавиш из памяти после их аутентификации.Эти люди не используют SecureString.

Существует очень мало сценариев, в которых вы можете разумно использовать SecureString в текущей версии Фреймворка.Это действительно полезно только для взаимодействия с неуправляемыми API-интерфейсами - вы можете маршалировать его с помощью Marshal.SecureStringToGlobalAllocUnicode.

Как только вы конвертируете его в / из System.String, вы нарушаете его назначение.

MSDN - сервер образец генерирует SecureString по символу за раз из консольного ввода и передает защищенную строку неуправляемому API.Это довольно запутанно и нереалистично.

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

  • Консоль SecureString.ReadLineSecure() или аналогично для чтения консольных входных данных в SecureString без всего запутанного кода в примере.

  • Замена текстового поля WinForms, которая сохраняет его текстовое поле.Свойство Text в виде защищенной строки, позволяющей безопасно вводить пароли.

  • Расширения к API, связанным с безопасностью, позволяющие передавать пароли в виде SecureString.

Без вышесказанного SecureString будет иметь ограниченное значение.

Я полагаю, что причина, по которой вам нужно добавлять символы вместо одного плоского экземпляра, заключается в том, что в фоновом режиме передача "password" конструктору SecureString помещает эту строку "password" в память, что противоречит назначению secure string.

Добавляя, вы за раз помещаете в память только символ, который, скорее всего, не находится рядом друг с другом физически, что значительно затрудняет восстановление исходной строки.Здесь я могу ошибаться, но именно так мне это объяснили.

Цель класса - предотвратить раскрытие защищенных данных с помощью дампа памяти или аналогичного инструмента.

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

Одним из больших преимуществ SecureString является то, что предполагается, что он исключает возможность сохранения ваших данных на диске из-за кэширования страницы.Если у вас есть пароль в памяти, а затем вы загружаете большую программу или набор данных, ваш пароль может быть записан в файл подкачки, поскольку ваша программа выгружается из памяти.С помощью SecureString, по крайней мере, данные не будут бесконечно храниться на вашем диске в виде открытого текста.

Я предполагаю, это потому, что строка должна быть безопасной, т.е.хакер не должен быть в состоянии прочитать это.Если вы инициализируете его строкой, хакер сможет прочитать исходную строку.

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

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

Я бы перестал использовать SecureString .Похоже, ребята из PG прекращают его поддержку.Возможно, даже потянет это в будущем - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

Мы должны удалить шифрование из SecureString на всех платформах в .NET Core - Мы должны использовать устаревшую SecureString - Вероятно, нам не следует предоставлять SecureString в .NET Core

Другой вариант использования - это когда вы работаете с платежными приложениями (POS) и вам просто не удается использовать неизменяемые структуры данных для того, чтобы хранить конфиденциальные данные, потому что вы тщательный разработчик.Например:если я сохраню конфиденциальные данные карты или метаданные авторизации в неизменяемой строке, всегда будет случай, когда эти данные будут доступны в памяти в течение значительного периода времени после того, как они были удалены.Я не могу просто перезаписать его.Еще одно огромное преимущество заключается в том, что такие конфиденциальные данные хранятся в памяти в зашифрованном виде.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top