Перетворити рядок у 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, правда? Можливо, якась затуманення часу компіляції також допоможе ... тобто, якщо ви жорстко кодуєте паролі.
Саміс

5
Це кульгавий аргумент. Де взяти пароль? З форми або з командного рядка. Поки вони не створять метод зчитування захищеної рядки безпосередньо з аргументів пристрою чи командного рядка, нам потрібно буде перетворити рядок у SecureString.
Quarkly

1
@DonaldAirey ви отримуєте пароль від менеджера секретів. Загалом секрети, про які ми тут говоримо, - це не паролі користувачів, а речі, які потенційно можуть призвести до ескалації привілеїв або витоку даних. Це означає, що паролі призначені для інших служб, і їх не слід передавати в командних рядках або в чистому режимі через мережеві канали.
Баррі Келлі

160

Існує також інший спосіб перетворення між SecureStringі String.

1. Рядок для SecureString

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

2. SecureString для String

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

Ось посилання


4
Це найкраще рішення на сьогодні для найпоширенішого випадку використання!
Ден Бешард

16
Немає сенсу використовувати, SecureStringякщо ваш код створить stringоб'єкт зі значенням, яке ви хочете захистити. Мета SecureString- уникнути наявності рядка в керованій пам'яті, тому зловмисник, що вивчає цю пам'ять, може виявити значення, яке ви хочете приховати. Оскільки NetworkCredentialконструктор, якого ви телефонуєте, вимагає рядок, це не шлях ... Безумовно, ваш код - це простий спосіб перетворення в SecureString і з нього, але використовуючи його, ваш код стає таким же безпечним, як і простийstring
Gian Paolo

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" в першу чергу. Просто вказавши на це майбутнім людям, які приходять і використовують цей код.
Коді

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

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 запропонував ідею НЕ встановлювати рядок зі своїм паролем, тому що якщо ви цього не зробите, то не залишається жодної переваги для використання захищеного рядка. У вашому випадку, якщо ви ввели пароль у простому тексті, ви не забезпечите нічого, пізніше використовуючи захисну нитку. Я сподіваюся, ви зрозуміли, що захисний рядок мав на меті захистити вашу струну від людей, які дивляться на демонтаж або налагоджувач, щоб побачити що в ІЛ / пам'яті.
користувач734028

8

Я викину це туди. Чому?

Ви не можете просто змінити всі свої рядки на безпечні рядки і раптом ваша програма стає "захищеною". Безпечний рядок призначений для збереження зашифрованого рядка якомога довше і розшифровується лише на дуже короткий проміжок часу, витираючи пам'ять після того, як операція виконується над ним.

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


1
Я просто хочу використовувати його, щоб встановити пароль для ProcessStartInfo та запустити свій exe як інший користувач .. Це працювало для мене ...
Developer404

4
Мій додаток захищено, запустивши його в захищеній системі. Мені було менше цікаво, щоб ця конкретна рядок була зашифрована в пам'яті. Існує набагато важливіша інформація про цю систему, яку потрібно хвилювати, якщо вона коли-небудь буде порушена. SecureString просто необхідний API Microsoft, який моя програма повинна використовувати. Мається на увазі, що розробник розглядає власний випадок використання та визначає, чи перетворення рядків у SecureStrings є дійсною операцією в контексті.
Ден Бешард

Тож цей метод не завадить комусь побачити пароль, якщо він використовує декомпілятор, наприклад DotPeek? Чи є спосіб приховати рядки в цьому випадку?
M.Parent

Існує кілька методів, залежно від загрози, яку ви намагаєтесь перемогти. Якщо це захистити інформацію про користувачів від будь-кого, крім місцевого адміністратора, ви можете використовувати методи DPAPI у Windows, щоб зашифрувати файл і зберегти там секрет, прочитати його в захищений рядок і потім викинути його. Якщо це стосується таємниці компанії, то коротка відповідь - якщо ваша програма може її розшифрувати, так може зрештою і користувач.
Спенс

6
unsafe 
{
    fixed(char* psz = password)
        return new SecureString(psz, password.Length);
}

5

немає фантазії linq, не додаючи всі символи вручну, просто просто і просто:

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

навіть більш
фантазії

ось один лайнер: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

Якщо ви хочете стиснути перетворення stringa 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.