защищенные строки
Часто объекты
String
применяют для хранения конфиденциальных данных, таких
как пароли или информация кредитной карты. К сожалению, объекты
String
хра-
нят массив символов в памяти, и если разрешить выполнение небезопасного или
неуправляемого кода, он может просмотреть адресное пространство кода, найти
строку с конфиденциальной информацией и использовать ее в своих неблаговид-
ных целях. Даже если объект
String
существует недолго и становится добычей
уборщика мусора, CLR может не сразу задействовать ранее занятую этим объектом
память (особенно если речь идет об объектах
String
предыдущих версий), оставляя
символы объекта в памяти, где они могут стать добычей злоумышленника. Кроме
того, поскольку строки являются неизменяемыми, при манипуляции ими старые
400
Глава.14 .Символы,.строки.и.обработка.текста
версии «висят» в памяти, в результате разные версии строки остаются в различных
областях памяти.
В некоторых государственных учреждениях действуют строгие требования
безопасности, гарантирующие определенный уровень защиты. Для решения таких
задач специалисты Microsoft добавили в FCL безопасный строковый класс
System.
Security.SecureString
. При создании объекта
SecureString
его код выделяет блок
неуправляемой памяти, которая содержит массив символов. Уборщику мусора об
этой неуправляемой памяти ничего не известно.
Символы строки шифруются для защиты конфиденциальной информации от
любого потенциально опасного или неуправляемого кода. Для дописывания в конец
строки, вставки, удаления или замены отдельных символов в защищенной строке
служат соответственно методы
AppendChar
,
InsertAt
,
RemoveAt
и
SetAt
. При вызове
любого из этих методов код метода расшифровывает символы, выполняет операцию
и затем обратно шифрует строку. Это означает, что символы находятся в незашифро-
ванном состоянии в течение очень короткого периода времени. Это также означает,
что символы строки модифицируются в том же месте, где хранятся, но скорость
операций все равно конечна, так что прибегать к ним желательно пореже.
Класс
SecureString
реализует интерфейс
IDisposable
, служащий для надежного
уничтожения конфиденциальной информации, хранимой в строке. Когда при-
ложению больше не нужно хранить конфиденциальную строковую информацию,
достаточно вызвать метод
Dispose
типа
SecureString
или использовать экземпляр
SecureString
в конструкции
using
. Внутренняя реализация
Dispose
обнуляет со-
держимое буфера памяти, чтобы предотвратить доступ постороннего кода, и только
после этого буфер освобождается. Объект
SecureString
содержит внутренний
объект класса, производного от
SafeBuffer
, в котором хранится сама строка. Класс
SafeBuffer
наследует от класса
CriticalFinalizerObject
(см. главу 21), что га-
рантирует вызов метода
Finalize
попавшего в распоряжение уборщика мусора
объекта
SecureString
, обнуление строки и последующее освобождение буфера.
В отличие от объекта
String
, при уничтожении объекта
SecureString
символы
зашифрованной строки в памяти не остаются.
Теперь, когда вы знаете, как создавать и изменять объект
SecureString
, можно
поговорить о его использовании. К сожалению, в последней версии FCL поддерж-
ка класса
SecureString
ограничена — вернее, методов, принимающих параметр
SecureString
, очень немного. В версии 4 инфраструктуры .NET Framework пере-
дать
SecureString
в качестве пароля можно:
при работе с криптографическим провайдером (Cryptographic Service Provider,
CSP) см. класс
System.Security.Cryptography.CspParameters
;
при создании, импорте или экспорте сертификата в формате X.509 см. классы
System.Security.Cryptography.X509Certificates.X509Certificate
и
System.
Security.Cryptography.X509Certificates.X509Certificate2
;
при запуске нового процесса под определенной учетной записью пользователя см.
классы
System.Diagnostics.Process
и
System.Diagnostics.ProcessStartInfo
;
401
Защищенные.строки
при организации нового сеанса записи журнала событий см. класс
System.
Diagnostics.Eventing.Reader.EventLogSession
;
при использовании элемента управления
System.Windows.Controls.PasswordBox
см. класс свойства
SecurePassword
.
Наконец, вы можете создавать собственные методы, принимающие в качестве
аргумента объект
SecureString
. В методе надо задействовать объект
SecureString
для создания буфера неуправляемой памяти, хранящего расшифрованные символы,
до использования этого буфера в методе. Чтобы сократить до минимума временное
«окно» доступа к конфиденциальным данным, ваш код должен обращаться к рас-
шифрованной строке минимально возможное время. После использования строки
следует как можно скорее обнулить буфер и освободить его. Никогда не размещайте
содержимое
SecureString
в типе
String
— в этом случае незашифрованная строка
находится в куче и не обнуляется, пока память не будет задействована повторно
после уборки мусора. Класс
SecureString
не переопределяет метод
ToString
спе-
циально — это нужно для предотвращения раскрытия конфиденциальных данных
(что может произойти при преобразовании их в
String
).
Следующий пример демонстрирует инициализацию и использование
Secure-
String
(при компиляции нужно указать параметр
/unsafe
компилятора C#):
using System;
using System.Security;
using System.Runtime.InteropServices;
public static class Program {
public static void Main() {
using (SecureString ss = new SecureString()) {
Console.Write("Please enter password: ");
while (true) {
ConsoleKeyInfo cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.Enter) break;
// Присоединить символы пароля в конец SecureString
ss.AppendChar(cki.KeyChar);
Console.Write("*");
}
Console.WriteLine();
// Пароль введен, отобразим его для демонстрационных целей
DisplaySecureString(ss);
}
// После 'using' SecureString обрабатывается методом Disposed,
// поэтому никаких конфиденциальных данных в памяти нет
}
// Этот метод небезопасен, потому что обращается к неуправляемой памяти
private unsafe static void DisplaySecureString(SecureString ss) {
Char* pc = null;
try {
// Дешифрование SecureString в буфер неуправляемой памяти
продолжение
402
Do'stlaringiz bilan baham: |