Является ли SecureString когда-либо практичным в приложении C#?
не стесняйтесь поправлять меня, если мои предположения здесь неверны, но позвольте мне объяснить, почему я спрашиваю.
взято из MSDN, a SecureString:
представляет собой текст, который должен быть конфиденциальным. Текст шифруется для обеспечения конфиденциальности при использовании и удаляется из памяти компьютера, когда он больше не нужен.
я понимаю, что имеет смысл хранить пароль или другую личную информацию в SecureString на System.String, потому что вы может контролировать, как и когда он на самом деле хранится в памяти, потому что System.String:
является неизменяемым и, когда он больше не нужен, не может быть программно запланирован для сборки мусора; то есть экземпляр доступен только для чтения после его создания, и невозможно предсказать, когда экземпляр будет удален из памяти компьютера. Следовательно, если строковый объект содержит конфиденциальную информацию, такую как пароль, номер кредитной карты или личные данные, существует риск эта информация может быть обнаружена после ее использования, поскольку приложение не может удалить данные из памяти компьютера.
однако, в случае приложения GUI (например, клиента ssh),SecureStringдолжен быть построен сSystem.String. Все текстовые элементы управления использовать строку в качестве базового типа данных.
так, это означает, что каждый раз, когда пользователь нажимает клавишу, старая строка, которая была там выбросить, а новую строка строится для представления значения внутри текстового поля, даже если используется маска пароля. и мы не можем контролировать, когда или если все значения удаляются из памяти.
теперь пришло время войти на сервер. Знаешь что? вам нужно передать строку через соединение для аутентификации. Так что давайте преобразуем наш SecureString на System.String.... и теперь у нас есть строка в куче без возможности заставить ее пройти сборку мусора (или напишите 0 в его буфер).
моя точка зрения: независимо от того, что вы делаете, где-то вдоль линии, что SecureString и идет для преобразования в System.String, что означает, что он, по крайней мере, будет существовать в куче в какой-то момент (без какой-либо гарантии сбора мусора).
моя точка зрения не: существуют ли способы обхода отправки строки В ssh-соединение или обхода наличия управляющего хранилища строки (сделать A пользовательский элемент управления.) Для этого вопроса Вы можете заменить "ssh-соединение" на "форму входа", "регистрационную форму", "форму оплаты", "форму питания, которую вы будете кормить своим щенком, но не своими детьми" и т. д.
- Итак, в какой момент с помощью
SecureStringна самом деле стать
практично? - это когда-нибудь стоит дополнительное время разработки, чтобы полностью искоренить
использование
6 ответов:
на самом деле, очень практическое использование
SecureString.вы знаете, сколько раз я видел такие сценарии? (ответ: много!):
- пароль появляется в файле журнала случайно.
- пароль показывается где-то-как только GUI показал командную строку приложения, которое выполнялось, и командная строка состояла из пароля. Упс.
- использование профилировщика памяти для профилирования программного обеспечения с помощью ваш коллега. Коллега видит ваш пароль в памяти. Звучит нереально? Нисколько.
- я
RedGateпрограммное обеспечение, которое может захватить "значение" локальных переменных в случае исключения, удивительно полезно. Хотя, я могу себе представить, что он будет регистрировать "строковые пароли" случайно.- аварийный дамп, который включает строковый пароль.
знаете ли вы, как избежать всех этих проблем?
SecureString. Это обычно гарантирует, что вы не делаете глупых ошибок, как такие. Как этого избежать? Убедившись, что пароль зашифрован в неуправляемой памяти и реальное значение может быть доступно только тогда, когда вы на 90% уверены, что вы делаете.в смысле
SecureStringработает довольно легко:1) Все шифруется
2) пользователь звонит
AppendChar3) расшифровать все в неуправляемой памяти и добавить символ
4) шифровать все снова в неуправляемой памяти.
что если пользователь имеет доступ к вашему компьютеру? Сможет ли вирус получить доступ ко всем
SecureStrings? Да. Все, что вам нужно сделать, это подключить себя вRtlEncryptMemoryкогда память расшифровывается, вы получите местоположение незашифрованного адреса памяти и прочитаете его. Вуаля! На самом деле, вы можете сделать вирус, который будет постоянно сканировать для использованияSecureStringи регистрировать все действия с ним. Я не говорю, что это будет легко, но это можно сделать. Как видите, "мощь"SecureStringполностью ушел, как только есть пользователь/вирус в вашей системе.у вас есть несколько моментов в вашем посте. Конечно, если вы используете некоторые элементы управления пользовательского интерфейса, которые содержат "строковый пароль" внутри, используя actual
SecureStringэто не так полезно. Хотя, все же, он может защитить от некоторой глупости, которую я перечислил выше.кроме того, как отмечали другие, WPF поддерживает PasswordBox, который использует
SecureStringвнутренне через SecurePassword свойство.в нижней строке; если у вас есть конфиденциальные данные(пароли, номера кредитных карт, ..), используйте
SecureString. Это то, что c# Framework следует. Например,NetworkCredentialкласс хранит пароль какSecureString. Если вы посмотрите на этой, вы можете увидеть более ~80 различных использований в .NET frameworkSecureString.есть много случаев, когда вы должны преобразовать
SecureStringв строку, потому что некоторые API ожидает.обычная проблема либо:
- API является универсальным. Он не знает, что есть конфиденциальные данные.
- API знает, что он имеет дело с конфиденциальными данными и использует "строку" - это просто плохой дизайн.
вы подняли хороший вопрос: что происходит, когда
SecureStringпревращается вstring? Это может произойти только из-за первого пункта. Например, API не знает, что это конфиденциальные данные. Лично я такого не видел. Получение строки из SecureString не все так просто.это не просто по простой причине; он никогда не предназначался для того, чтобы позволить пользователю конвертировать SecureString в string, как вы заявили: GC вступит в силу. Если вы видите, что делаете это, вам нужно отступить назад и спросить себя: Зачем я вообще это делаю, или мне действительно это нужно, почему?
я видел один интересный случай. А именно, функция WinApi LogonUser принимает LPTSTR в качестве пароля, что означает, что вам нужно вызвать
SecureStringToGlobalAllocUnicode. Что в основном дает вам незашифрованный пароль, который живет в неуправляемой памяти. Вам нужно избавиться от этого, как только вы закончите:// Marshal the SecureString to unmanaged memory. IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password); try { //...snip... } finally { // Zero-out and free the unmanaged string reference. Marshal.ZeroFreeGlobalAllocUnicode(rawPassword); }вы всегда можете продлить
SecureStringкласс с методом расширения, такие какToEncryptedString(__SERVER__PUBLIC_KEY), что дает вамstringэкземплярSecureStringэто зашифровано с помощью открытого ключа сервера. Только сервер может расшифровать его. Проблема решена: сборка мусора никогда не увидит "исходную" строку, так как вы никогда не предоставляете ее в управляемой памяти. Это точно что делается вPSRemotingCryptoHelper(EncryptSecureStringCore(SecureString secureString)).и как-то очень почти, связанных с: Mono SecureString не шифрует вообще. Реализация была прокомментирована, потому что ..ждать его.. "это как-то вызывает поломку теста nunit", что подводит меня к последнему пункту:
SecureStringНе поддерживается везде. Если платформа / архитектура не поддерживаетSecureString, вы получите исключение. Там есть список платформы, которые поддерживаются в документации.
немного проблем в ваших предположениях.
прежде всего класс SecureString не имеет строкового конструктора. Чтобы создать его, вы выделяете объект, а затем добавляете символы.
в случае GUI или консоли вы можете очень легко передать каждую нажатую клавишу в защищенную строку.
класс разработан таким образом, что вы не можете по ошибке получить доступ к сохраненному значению. Это означает, что вы не можете получить
stringКак a пароль прямо от него.поэтому для его использования, например, для аутентификации через интернет, вам придется использовать соответствующие классы, которые также являются безопасными.
в .NET framework у вас есть несколько классов, которые могут использовать SecureString
- элемент управления PasswordBox WPF сохраняет пароль как SecureString внутри.
.Диагностика.Свойство пароля ProcessInfo является SecureString.- конструктор X509Certificate2 принимает SecureString для пароля.
В заключение, класс SecureString может быть полезен, но требует большего внимания со стороны разработчика.
все это, с примерами, хорошо описано в документации MSDN SecureString
SecureString полезен, если:
вы строите его символ за символом (например, из консольного ввода) или получаете его из неуправляемого API
вы используете его, передавая его в неуправляемый API (SecureStringToBSTR).
Если вы когда-нибудь преобразовать его в управляемую строку, вы победили его цель.
обновление в ответ на комментарий
... или тип BSTR, как вы упоминание, которое не кажется более безопасным
после его преобразования в BSTR неуправляемый компонент, который потребляет BSTR, может обнулить память. Неуправляемая память более безопасна в том смысле, что она может быть сброшена таким образом.
однако в .NET Framework очень мало API, которые поддерживают SecureString, поэтому вы правы, говоря, что сегодня он имеет очень ограниченное значение.
основной вариант использования, который я бы увидел, находится в клиентском приложении, которое требуется, чтобы пользователь ввел высокочувствительный код или пароль. Пользовательский ввод может использоваться символ за символом для построения SecureString, затем это может быть передано неуправляемому API, который обнуляет BSTR, который он получает после его использования. Любой последующий дамп памяти не будет содержать чувствительную строку.
в серверном приложении трудно увидеть, где это было бы полезно.
обновление 2
один пример .NET API, который принимает Объект SecureString составляет этот конструктор для класса X509Certificate. Если вы выполняете spelunk с ILSpy или подобным образом, Вы увидите, что SecureString внутренне преобразуется в неуправляемый буфер (
Marshal.SecureStringToGlobalAllocUnicode), который затем обнуляется при завершении (Marshal.ZeroFreeGlobalAllocUnicode).
как вы правильно определили,
SecureStringпредлагает одно специфическое преимущество надstring: детерминированные стирания. Есть две проблемы с этим:
- как уже упоминали другие и как вы сами заметили, этого недостаточно само по себе. Вы должны убедиться, что каждый шаг процесса (включая извлечение ввода, построение строки, использование, удаление, транспортировку и т. д.) происходит без ущерба для цели использования
SecureString. Это означает, что вы должны быть осторожны, чтобы никогда не создавать GC-управляемый неизменяемыйstringили любой другой буфер, который будет хранить конфиденциальную информацию (или вам придется отслеживать это как хорошо). На практике это не всегда легко достичь, потому что многие API предлагают только способ работы сstring, а неSecureString. И даже если вам удастся все правильно...SecureStringзащищает от очень специфических видов атаки (а для некоторых из них это даже не такой надежный). Например,SecureStringпозволяет вам уменьшить временное окно, в котором злоумышленник может сбросить память вашего процесса и успешно извлечь конфиденциальную информацию (опять же, как вы правильно указали), но надеяться, что окно слишком мало для злоумышленника, чтобы сделать снимок вашей памяти, не считается безопасностью вообще.Итак, когда вы должны использовать его? Только когда вы работаете с чем-то, что может позволить вам работать с
SecureStringдля всех ваших потребностей, и даже тогда вы все равно должны помнить, что это безопасно только в определенных обстоятельствах.
Я хотел бы обратиться к этому вопросу:
если у злоумышленника уже есть средства для проверки кучи, то они, скорее всего, либо (а) уже имеют средства для чтения нажатий клавиш, либо (б) уже физически есть машина... Так бы с помощью
SecureStringпредотвратить их от получения данных в любом случае?злоумышленник может получить полный доступ к компьютеру и программы, но может иметь средства для доступа к некоторым частям памяти процесс. Обычно это вызвано ошибками, такими как переполнение буфера, когда специально сконструированный ввод может привести к тому, что приложение откроет или перезапишет некоторую часть памяти.
HeartBleed утечка памяти
возьмите Heartbleed, например. Специально построенные запросы могут привести к тому, что код откроет злоумышленнику случайные части памяти процесса. Злоумышленник может извлечь SSL-сертификаты из памяти, но единственное, что ему нужно, это просто использовать искаженный запрос.
в мире управляемого кода переполнение буфера становится проблемой гораздо реже. И в случае WinForms, данные уже хранятся в небезопасной манере, и вы ничего не можете с этим поделать. Это делает защиту с
SecureStringбесполезны.однако, GUI можете быть запрограммированы, чтобы использовать
SecureString, и в таком случае сокращение окна доступности пароля в памяти может стоить того. Например, PasswordBox.SecurePassword от WPF имеет типSecureString.
ниже текст копируется из HP Fortify static Code analyzer
Аннотация: Метод PassString () в PassGenerator.cs хранит конфиденциальные данные небезопасным образом (т. е. в строке), что позволяет извлекать данные с помощью проверки кучи.
объяснение: Конфиденциальные данные (например, пароли, номера социального страхования, номера кредитных карт и т. д.) сохраненный в памяти может быть утечка, если это так хранится в управляемой строке объект. Строковые объекты не закреплены, поэтому сборщик мусора может перемещать эти объекты по желанию и оставьте несколько копий в памяти. Эти объекты не шифруются по умолчанию, поэтому любой, кто может прочитать память процесса, будет возможность видеть содержимое. Кроме того, если память процесса будет заменена на диск, незашифрованное содержимое строки будет записан в файл подкачки. Наконец, поскольку строковые объекты неизменяемы, удаление значения строки из памяти может только быть сделано сборщик мусора среды CLR. Сборщик мусора не требуется для запуска, если в среде CLR недостаточно памяти, поэтому есть никаких гарантий относительно того, когда сбор мусора пройдет. В случае сбоя приложения, дамп памяти приложение может раскрывать конфиденциальные данные.
рекомендации: Вместо хранения конфиденциальных данных в таких объектах, как строки, храните их в объекте SecureString. Каждый объект хранит свое содержимое в зашифрованном виде в памяти раз.
Comments