Преобразовать строку в SecureString


Ответы:


137

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

var s = new SecureString();
s.AppendChar('d');
s.AppendChar('u');
s.AppendChar('m');
s.AppendChar('b');
s.AppendChar('p');
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('d');

13
«Комбинация 12345... такие вещи у идиота в багаже!»
Каньон Колоб

8
Все, что я вижу, это*****
Ян Бойд

AppendCharне выполняется до времени выполнения, поэтому эти символы все еще можно прочитать из IL, верно? Может быть, некоторая обфускация во время компиляции тоже поможет ... то есть, если вы жестко кодируете пароли.
samis

5
Это неубедительный аргумент. Где взять пароль? Из формы или из командной строки. Пока они не создадут метод для чтения защищенной строки непосредственно из устройства или аргументов командной строки, нам нужно будет преобразовать строку в SecureString.
Quarkly

1
@DonaldAirey, вы получаете пароль от секретного менеджера. Обычно секреты, о которых мы говорим здесь, - это не пароли пользователей, а вещи, которые потенциально могут привести к эскалации привилегий или утечке данных. Это означает, что пароли предназначены для других служб и не должны передаваться в командной строке или в открытом виде по сетевым каналам.
Барри Келли

160

Существует также другой способ преобразования между SecureStringи String.

1. Строка в SecureString

SecureString theSecureString = new NetworkCredential("", "myPass").SecurePassword;

2. SecureString в строку

string theString = new NetworkCredential("", theSecureString).Password;

Вот ссылка


4
На сегодняшний день это лучшее решение для наиболее распространенного варианта использования!
Дэн

16
Нет смысла использовать a, SecureStringесли ваш код создает stringобъект со значением, которое вы хотите защитить. Цель SecureStringсостоит в том, чтобы избежать попадания строки в управляемую память, чтобы злоумышленник, исследующий эту память, мог обнаружить значение, которое вы хотите скрыть. Поскольку NetworkCredentialвызываемый вами конструктор требует строки, это не выход ... Конечно, ваш код - это простой способ преобразования в SecureString и обратно, но его использование делает ваш код таким же безопасным, как использование простогоstring
Джан Паоло

15
@GianPaolo, хотя теоретически это верно, на практике нам все еще нужно использовать SecureStringпри работе с некоторыми библиотеками. И давайте будем честными: если кто-то активно сканирует память вашего приложения, значит, вы уже проиграли. Даже если вы правильно использовали SecureString, чего я никогда не видел, вам придется извлечь другие ценные данные.
Джонатан Аллен

1
@JonathanAllen: Вы, наверное, правы, но только потому, что у нас есть культура относиться к безопасности как к второстепенному. Если вы создаете веб-сайт с рецептами, Северная Корея вряд ли попытается сканировать память вашей программы. Если вы пишете банковское программное обеспечение, угроза гораздо более реальна.
Эрик Дж.

58

метод ниже помогает преобразовать строку в безопасную строку

private SecureString ConvertToSecureString(string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    var securePassword = new SecureString();

    foreach (char c in password)
        securePassword.AppendChar(c);

    securePassword.MakeReadOnly();
    return securePassword;
}

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

19
@Cody Это правда, и это хороший аргумент, но многие из нас не заботятся о том, является ли SecureString безопасным или нет, и используют его только потому, что некоторые API Microsoft требуют его в качестве параметра.
Дэн

3
@Cody Оказывается, даже класс SecureString не может сохранить строку в зашифрованном виде. Вот почему MS рассматривает возможность отказа от типа github.com/dotnet/platform-compat/blob/master/docs/DE0001.md .
Мартин Браун

19

Вы можете следить за этим:

string password = "test";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();

11

Вот дешевый трюк с linq.

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();

32
Этот ответ представляет собой упражнение, чтобы увидеть, сколько временных копий простого текста можно создать за один снимок
Майк Кэрон,

1
поскольку @ john-dagg предложил идею НЕ устанавливать строку с вашим паролем, потому что, если вы это сделаете, не останется никаких преимуществ для использования защищенной строки. В вашем случае вы ввели пароль в виде обычного текста, вы ничего не защищаете, используя позже безопасную строку. Я надеюсь, вы понимаете, что securestring была предназначена для защиты вашей строки от людей, которые смотрят на разборку или отладчик, поэтому посмотрите, что находится в IL / памяти.
user734028

8

Я выкину это там. Зачем?

Вы не можете просто изменить все свои строки на защищенные, и вдруг ваше приложение станет «безопасным». Защищенная строка предназначена для хранения строки в зашифрованном виде как можно дольше и дешифрования только в течение очень короткого периода времени, стирая память после выполнения операции с ней.

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


1
Я просто хочу использовать его для установки пароля для ProcessStartInfo и запуска моего exe от имени другого пользователя. У меня это сработало ...
Developer404,

4
Мое приложение защищено, запустив его в защищенной системе. Мне наплевать, что эта конкретная строка зашифрована в памяти. В этой системе есть гораздо более важные части информации, о которых стоит беспокоиться, если она когда-либо будет взломана. SecureString просто требуется для API Microsoft, который моя программа должна использовать. Подразумевается, что разработчик рассматривает свой собственный вариант использования и определяет, является ли преобразование String в SecureStrings допустимой операцией в контексте.
Дэн

Значит, этот метод не помешает кому-то увидеть пароль, если он использует декомпилятор, такой как DotPeek? Есть ли способ в этом случае скрыть строки?
M.Parent

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


5

нет причудливого linq, не добавляя все символы вручную, просто и просто:

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);

еще интереснее, не нужно определять переменную
bigworld12

вот один лайнер:var sc = new SecureString(); foreach(char c in "foo") sc.appendChar(c);
bigworld12

4

Я согласен со Спенсом (+1), но если вы делаете это для изучения или тестирования заливок, вы можете использовать foreach в строке, добавляя каждый символ в защищенную строку с помощью метода AppendChar.


3

Я просто хочу указать всем, кто говорит: «Дело не в этом SecureString», что многие из людей, задающих этот вопрос, могут быть в приложении, где по какой-либо причине, оправданной или нет, они не особенно обеспокоены тем, что временная копия пароля находится в куче как строка с поддержкой GC, но они должны использовать API, который принимает толькоSecureString объекты. Итак, у вас есть приложение, в котором вам все равнонаходится ли пароль в куче, возможно, он предназначен только для внутреннего использования, а пароль существует только потому, что он требуется базовыми сетевыми протоколами, и вы обнаружите, что эта строка, в которой хранится пароль, не может использоваться, например, для настройки удаленной оболочки PowerShell Пространство выполнения - но нет простого и понятного однострочника для создания того, SecureStringчто вам нужно. Это небольшое неудобство - но , вероятно , стоит того , чтобы гарантировать , что приложения , которые действительно делают нужно SecureStringделать не искушать автор к использованию System.Stringили System.Char[]посредникам. :-)


2

Если вы хотите , чтобы сжать преобразование stringк SecureStringв LINQзаявлении можно выразить следующим образом :

var plain  = "The quick brown fox jumps over the lazy dog";
var secure = plain
             .ToCharArray()
             .Aggregate( new SecureString()
                       , (s, c) => { s.AppendChar(c); return s; }
                       , (s)    => { s.MakeReadOnly(); return s; }
                       );

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

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


2

Следующие 2 расширения должны помочь:

  1. Для charмассива

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
  2. И для string

    public static SecureString ToSecureString(this string _self)
    {
        SecureString knox = new SecureString();
        char[] chars = _self.ToCharArray();
        foreach (char c in chars)
        {
            knox.AppendChar(c);
        }
        return knox;
    }

Спасибо Джону Дэггу за AppendCharрекомендацию.


0

вы можете использовать этот простой скрипт

private SecureString SecureStringConverter(string pass)
{
    SecureString ret = new SecureString();

    foreach (char chr in pass.ToCharArray())
        ret.AppendChar(chr);

    return ret;
}

1
Этот ответ был опубликован 15 месяцев назад . На самом деле не было необходимости выкладывать это снова.
GSerg
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.