альманах
програ ста
Тематический сборник материалов
MSDN" Library и IN/ISDN' Magazine
Microsoft"
Безопасность в .NET
Шифрование
Н.РШШР Е
альманах программиста
Microsoft*
Составитель Ю. Е. Купцевич
Москва 2004
И.РШШ Р Е Ц П Ц У
УДК 004.45
ББК 32.973.26-018.2
А57
УДК 004.45
ББК 32.973.26-018.2
Шифрование 7
Дэн Фокс
Шифрование Пространство имен Cryptography
в .NET Framework 9
Джеймс Мак-Каффри
Шифрование Защита данных с помощью
Advanced Encryption Standard 25
Кит Браун
Безопасный код Хэширование паролей,
атрибут AllowPartiallyTrustedCallers 52
Стефен Тауб
.NET Remoting Защита трафика .NET Remoting с помощью
приемников каналов асимметричного шифрования 60
Дон Бокс
Защита в .NET Сервисы признаков, политик, разрешений
и применения политик в инфраструктуре CLR 83
Microsoft
Принципы безопасного кодирования для .NET Framework 122
Кит Браун
Безопасный код Обзор расширений S4U Kerberos
в Windows Server 2003 155
Уэйн Берри
Защита в IIS 6.0 Новые средства IIS надежно защищают
информацию и серверные процессы 166
Кит Браун
Авторизация Ролевая защита на основе Authorization
Manager в .NET-приложениях на промежуточном уровне 179
Оглавление
Нирадж Сривастава
Безопасность Защита SOAP-пакетов на основе WS-Security
и приемников каналов Remoting 195
Майкл Говард
Оценка уязвимостей Полезные советы по выявлению
уязвимостей в вашем коде 210
Габриэл Торок и Билл Лич
Затемнение кода Пресечение попыток обратного
проектирования вашего кода Visual Basic .NET или С# 219
Алек Дэвис
Защита Закрытие доступа к строкам подключения
баз данных и другим секретным параметрам в коде 233
Джейсон Фишер
Охота на вирусы Знание типичных механизмов
вирусных атак поможет лучше защитить приложения 251
Стэн Зундблат и Пер Зундблат
Шаблоны Архитектура автономного приложения 268
Михаил Коготков-Лизин
Защищенный вход Средства безопасной аутентификации
через Microsoft .NET Passport 280
От составителя
Уважаемый читатель!
Альманах программиста представляет собой тематический сборник статей
из Microsoft MSDN Library и журнала «MSDN Magazine* по наиболее ак-
туальным и перспективным технологиям разработки программного обес-
печения. Он выпускается издательством «Русская Редакция» периодичес-
ки, по мере накопления материалов. Альманах избавляет вас от поисков
нужной информации, опубликованной в отдельных номерах журнала
«MSDN Magazine» или документах MSDN Library за 2002-2003 гг. Пер-
вый том был посвящен работе с базами данных, второй — технологиям
ASP/ASP.NET, третий — основным программным продуктам, образующим
платформу 2003 (Windows Server 2003, IIS 6.0, Visual Studio .NET 2003 и
Microsoft Office System, в том числе Microsoft InfoPath 2003), а четвертый
адресован программистам, желающим освоить методы шифрования и за-
щиты кода и данных на платформе 2003.
Четвертый том альманаха состоит из двух тематических рубрик.
• Шифрование. Пространство имен Cryptography в .NET Framework и
его применение для шифрования по различным алгоритмам, шифрова-
ние с применением AES (Advanced Encryption Standard), хэширование
паролей, атрибут AllowParti ally Trusted Callers, использование прием-
ников каналов асимметричного шифрования для защиты трафика
.NET Remoting.
• Защита кода и данных. Модель защиты по нравам доступа кода, об-
зор расширений S4U Kerberos в Windows Server 2003, новые средства
IIS 6.0 для надежной защиты информации и серверных процессов, ро-
левая защита на основе Authorization Manager в .NET-приложениях,
защита SOAP-пакетов на основе WS-Security и приемников каналов
Remoting, рекомендации по выявлению уязвимостей в вашем коде, за-
темнение кода для пресечения попыток обратного проектирования ва-
шего кода, написанного на Visual Basic .NET или С#, закрытие досту-
па к строкам подключения баз данных и другим секретным параметрам
в коде, типичные механизмы вирусных атак, архитектура защищенно-
го автономного приложения и средства безопасной аутентификации
через Microsoft .NET Passport.
От составителя
Шифрование
Пространство имен
Cryptography в .NET
Framework*
Элемент Описание
Алгоритмы шифрования
Пространство имен Cryptography, в частности, открывает доступ к алго-
ритмам симметричного шифрования (далее — симметричные алгоритмы).
Симметричные алгоритмы называются так потому, что для шифрования и
дешифрования используется один секретный ключ. Очевидно, что и от-
правитель, и получатель должны держать такой ключ в секрете, иначе
шифрование станет бессмысленным. Кроме того, в режиме СВС симмет-
ричные алгоритмы используют IV — несекретное двоичное значение; оно
инициализирует алгоритм и вносит дополнительные вариации в процесс
шифрования. SymmetricAlgorithm является абстрактным базовым клас-
сом, от которого наследуют другие классы, специфичные для конкретных
алгоритмов.
SymmetricAlgorithm
RijiidaelManaged
TripleDES
TripieDESCryptoServiceProvider
For 1 * 1 To (oEnc.KeySize / 8)
strKey &= o€nc.Key(i - t>.ToStrlna &
Next
for i » 1 To 16
striv &« oBie.lVCi - D.ToStrlng & "
Next
Car»sole.«rlt8Llfle<strIV)
Console. *fiteUne(o£oc.KeySlze.T^trina>
Console. WriteLineCoEnc. BlockSize. Tostring)
Asymmetric Algorithm
RSAOAEPKeyExchangeDeformatter DSASignatureDeformatter
RSAPKCSfKeyExchangeFormatter H5 RSAPKCSlSignatureFormatter
KeyedHashAlgorithm
HMACSHA1
MACTripleDES
SAH256Managed
SHA3B4Managed
SHA512Managed
гЗ = CType(CryptoConfig.CreateFromName("Rijndael"), RijndaelManaged)
г2 = CTypeCSymmetricAlgorithm.Create, flijndaelManaged)
M = CType(Rijndael. Create, RijndaelManaged)
г = New RijndaelManagedO
<iascorlib>
<с rypt08raphySettlfigs>
<cryptoKaHieMapping>
<cryptQClasses>
«coryptoClass rayH05=
"System. Security, Cryptog ra phy.RBSCryptoServieeProvlder,
mscorUb, Ver=1. 0.2411.0, CuUure=neutral,
PubliGKeyToken=b77a5c561934e089"/>
</c ryptoClasses>
<naraeEntry пагвевМая" class="fliyHD5*V>
<fiante Entry/ na«eis"SyBteieI Security. Cryptography. HashAigorithtn
</cryptoNaKeMapping>
</cryptograpliySettings>
Dim m, ml As MDSCryptoServlceProvider
m = CType(HashAlgorithm.Create,
MDSCryptoServiceProvider)
ml = CType(CryptoConfig,CreateFroiriName("dan"),
MDSCryptoServlceProvider)
Imports System.S&curity.Cryptography
rtports System.10
Imports System.Threading
Public Class TextFileCrypto
' Шифрует и расшифровывает текстовый на основе ключа
Private mstrFlle As String ' расшифровываемый файл
Private mstrKey As String ' файя ключа
Private aiKey(7) As lyte ' ключ oes
Private iBDES As PESCryptoServlceProvider
Private nIV(7) As Byte ' ректор инициализации
см. след. стр.
Пространство имен Cryptography в ,NET Framework
ifistrKey =
End Function
arInput(Convert.ToInt32CfsInput.Lefigtti - t)>
fsInput,Bead(arlnputr Q, Convert. Tolnt32(fslnpjat. Length))
fsInput.CloseO
клвч
If вКеу Is Nothing Than
Throw New ExceptionC'You must have a key in place first.")
Return False
End If
' Очистка
swWriter, Closet)
fsOutput.CleseC)
fsRead.GloseO
End Function
'End Class
objCrypt.FileName = "students.txt"
1
Генерируем и сохраняем ключ
ob]Crypt.SaveKeyFile("mykey.dat")
1
Шифруем файл
objCrypt.EncryptFile()
objCrypt.FileName = "students.txt"
Шифрование
С: '.AESiAe5DemoCQn$a!e\bini,Deb«e\
T h e pla i n t e x t i c :
ИЙ 11 22 33 44 $5 66 77 88 9 9 J «a bb CL- dd ее ft
Us i n s я Bitsi92i-key o f :
P0 01 02 83 84 65 Й6 07 88 S9i 6a 0b Йс Set 0e 8f
11 12 13 1-4 15 16 J?
Й / t e t 1 deciphering t h e c i p h e i - t b x t , t l t e i-esult i s :
№ 11 22 33 44 55 66 77 88 9?| aa bb cc del ее f f
00 11 22 33 44 55 66 77 99 аа bb cc dd ее ff
0 1 2 3 4 5 6 7 9 10 11 12 13 14 15
00 01 02 03 04 05 06 07 08 09 Оа ОЬ Ос Od Oe Of 10 11 12 13 14 15 16 17
О 1 2 3 4 5 6 7 6 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
О f
63 7с 77 7Ь и
са 82 с9 7d fa
Ь7 fd 33 26 36
04 с? 23 сЗ 18
09 83 2с 1а 1b
Рис. 2. Sbox
28 Шифрование
0 00 01 62 03
1 04 05 06 07
2 OS 09 Oa Qb
3 fle Od Oe «
4 IS 11 12 13
5 14 15 16 П
6 5ft 46 f2 «I
7 5C 43 14 le
8 54 48 fe n
9 58 47 № lil
10 48 56 e2 «9 0 1 2 3
0 00 44 88 cc
49 la 76 dc 09 1 11 Э9 dd
50 c4 18 c2 7! 2 22 66
51 ез 84 Jd 5d 3 33 7? ЬЬ
Например, если первая строка матрицы State содержит байты { 00, 44, 88, ее },
а первый столбец таблицы ключей имеет вид { 00,04, 08, Ос }, то новым зна-
чением State[0,2] будет 0x80 — результат операции XOR над State[0,2]
(0x88) и w[2,0] (0x08):
10001000
0 0 0 0 1 0 0 0 XOR
10000000
8
Поле GF(2 ) состоит из 256 значений от 0x00 до Oxff, над которыми опре-
Н
делены операции сложения и умножения. Отсюда (2 ) в названии. Поле
GF (Galois Field) названо в честь Галуа, математика, основавшего теорию
полей. Одной из характеристик GF(2*) является то, что результат сложе-
ния или умножения всегда принадлежит множеству {0x00 ... Oxff). Теория
8
полей достаточно сложна, но применительно к сложению в GF(2 ) полу-
H
чается простой конечный результат: сложение в GF(2 ) — это обыкновен-
ная операция XOR.
W
Однако умножение в GF(2 ) — более сложная операция. Как вы в дальней-
шем увидите в реализации на С#, в процедурах шифрования и дешифро-
вания алгоритма AES используется умножение только на семь констант:
0x01, 0x02, 0x03, 0x09, OxOb, OxOd и ОхОе. Поэтому вместо объяснения об-
8
щей теории умножения в GF(2 ) я ограничусь рассмотрением этих семи
частных случаев.
8
Умножение на 0x01 в GF(2 ) занимает особое место; оно соответствует
умножению на 1 в обычной арифметике и выполняется точно так же: при
умножении любого значения на 0x01 получается то же самое значение.
Эту операцию можно выполнить, зная, как умножать на 0x02 и 0x01 и как
складывать. Аналогично умножение произвольного байта на OxOd сводит-
ся к следующим операциям:
8
Подведем итог. Сложение в GF(2 ) — это операция XOR. Умножение в
8
GF(2 ) сводится к операциям сложения и умножения на 0x02, а умноже-
ние на 0x02 — это сдвиг на 1 бит влево, выполняемый в зависимости от
8
условия. Дополнительную информацию об операциях в GF(2 ) см. в спе-
цификации AES.
Расширение ключа
В алгоритме шифрования и дешифрования AES используется таблица
ключей, генерируемая по массиву байтов исходного ключа. В специфика-
ции AES это называется процедурой KeyExpansion. Генерация фактически
нескольких ключей по начальному ключу обеспечивает лучшее перемеши-
вание битов по сравнению с использованием одного ключа. Нельзя ска-
зать, что разобраться в KeyExpansion так уж трудно, но тем не менее это
одна из самых сложных частей алгоритма AES. На высокоуровневом псев-
докоде процедура KeyExpansion выглядит так:
2-138
34 Шифрование
if (row % Nk == 0)
temp = SubWord(RotWord(temp)) xor Rcon[row/Nk]
else if (Nk == В and row % Nk == 4)
temp = SubWord(temp)
Если пока отвлечься от операторов if, то видно, что каждая строка таблицы
ключей vv[] — результат XOR предыдущей строки со строкой, находящейся на
Nk (4, б или 8 в зависимости от размера ключа) строк выше. Первое условие
if означает, что к каждой четвертой, шестой или восьмой строке (в зависимо-
сти от размера ключа — 128,192 или 256 битов) применяются подпрограммы
SubWbrd, Rot Word, а затем — операция XOR с итеративной константой. Вто-
рое условие означает, что в случае 256-битного ключа изменяются строки 12,
20, 28 и так далее через восемь строк. Это делается для того, чтобы в таблице
ключей содержались более разнообразные значения.
00 01 02 03 04 05 06 07 08 09 Оа ОЬ Ос Od Oe Of 10 11 12 13 14 15 16 17
Конструктор AES-класса на С#
Итак, мы рассмотрели все компоненты алгоритма шифрования AES, и те-
перь реализуем этот алгоритм на С#. Официальная спецификация алго-
ритма AES содержится в документе Federal Information Processing Stan-
dards Publication 197. Я решил, что моя реализация должна соответство-
вать ей максимально точно, но вскоре обнаружил, что спецификация -
скорее теоретический документ, чем руководство по реализации. Для
удобства я предпочел использовать те же имена переменных, что и в опуб-
ликованном стандарте (даже такие загадочные, как «Nr> и «w»).
BuildSboxO;
BuildlnvSboxO;
BuildRconO;
KeyExpansion();
tftls.Nb « 4;
if (keySize « KeySize.flits128>
thls.Nk = 4;
this.Nr * 10;
this.Mk » 6;
this.Nr - 12;
}
else if (keySize == KeySize.81ts256)
i
this.Mk * 8;
tfcis.Nr « H;
t If SetHbNkHrO
Я посчитал, что лучше всего объявить таблицу ключей w[], таблицу ите-
ративных констант Rcon[] и таблицу State[] членами класса и присваивать
значения таблицам Rcon[] и w[] закрытыми вспомогательными методами.
Но это в основном вопрос стиля. Код заполнения таблицы итеративных
констант Rcon показан на рис. 7.
38 Шифрование
} // BuildSbOxO
this.w[row,0] = this.key[4*row];
this.w[row,1] = this.key[4*row+1];
this.w[row,2] = this.key[4«row+2];
this.w[row,3] = this.key[4*row+3];
if (row X Nk == 0)
{
* SubWorcJ(flotWordCteiap));
} II конец цикла
} // KeyExpanslonO
В этом коде часто встречается операция XOR над парами байтов. Так как
в языке С# не определен оператор А (XOR) для типа byte, приходится при-
водить byte к int, а результат — обратно к byte. Например, приходится ис-
пользовать:
вместо:
int х = word[0] » 4;
int у = word[0] & OxOf;
byte substitute = this.Sbox[x,y];
result[0] = substitute;
AES-метод Cipher на С#
Код метода Cipher показан на рис. 11. Он очень прост, поскольку за него ра-
ботают закрытые методы AddRoundKey, SubBytes, ShiftRows и MixColumns.
AddfloundKey(O);
SubBytee(>;
ShlftfloweO;
AddfioutidKey(Nr);
// output = state
for (int 1 = 0 ; i < (4 * Nb}; ++i)
{
outputtl] « this. Stated X 4, i / 4];
} // ClpherO
42 Шифрование
} // AddRoundKeyC)
tenptr.c] = this.Statetr.c];
}
// ShiftRtftfflO
Как я уже говорил, любое умножение в поле GF(28) можно свести к умно-
жению на константу 0x02 и сложению. Я назвал метод, умножающий на
0x02, gfmultby02, отступив от принципа использовать те же имена методов,
что и в спецификации, где эта подпрограмма называлась xtime.
AES-метод InvCipher на С#
Основной принцип алгоритма дешифрования AES несложен. Чтобы рас-
шифровать зашифрованный блок, нужно просто выполнить в обратном
порядке операции, противоположные соответствующим операциям шиф-
рования. Таков общий принцип, но имеются и некоторые частности.
Использование AES-класса
Одно из преимуществ реализации AES на языке С# — простота. Рассмот-
рим код на рис. 15, который формирует вывод, показанный на рис. 1. Сна-
чала объявляются «зашитые» в код значения 16-байтного входного текста
и 24-байтного (192-битного) исходного ключа, затем инициализируется
AES-объект, далее метод Cipher формирует по входному тексту зашифро-
ванный текст, а метод InvCipher дешифрует зашифрованный текст. Все
очень просто и понятно.
bytetJ keyBytes = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
a.Cipher(plainText, cipherText);
a.IflvCipher(cipherText, deciptiaredText);
Console,WriteLine("\nDone");
Console, ReadlineO;
} // NainO
192 bits
Как и любой алгоритм, с которым мне доводилось работать, AES можно реа-
лизовать разными способами. Почему это важно? AES рассчитан на приме-
нение в широком спектре систем -- от смарт-карт с крохотной памятью до
громадных многопроцессорных мэйнфреймов. Во многих случаях критиче-
ски важна производительность, иногда приходится сталкиваться с ограни-
ченностью памяти или других ресурсов обработки данных. Почти каждую
подпрограмму AES можно изменить, оптимизировав производительность за
Защита данных с помощью Advanced Encryption Standard 49
Заключение
Новый алгоритм AES явно станет стандартом де-факто на шифрование
всех видов электронной информации и заменит DES. Данные, зашифро-
ванные по алгоритму AES, нельзя взломать в том смысле, что не известно
ни одной атаки криптографического анализа, которая позволила бы рас-
шифровать AES-шифр без применения метода грубой силы, т. е. без пере-
бора всех возможных 256-битных ключей.
Безопасный код
Хэширование
паролей,атрибут
Allow PartiallyTrustedCallers
<users>
<user name*'Alice' password='7Sy2si(Vldx'/>
<user name='Bob' password='mary'/>
<user name-'Fred' password='marv'/ >
</users>
<users>
<user name='Alice' password»'D16E9B18FA038_'/>
<user name= - Bob' password='5665331B9B819...T/>
<user name='Fred' password='5665331B9B819.-V>
</users>
<users>
<user name='Alice' salt='Tu72*&' password='6DB80AE7...'/>
<user name='8ob" salt='N5sbiX' Dassword='096B1085...'/>
<user name='Fred' salt='q-V3bi' password='9118812E...'/>
</users>
Незашифрованные пароли
namespace DevelopKeFitor.Se<;Utils i
using System;
using System.Security.Cryptography;
бого недоверяемого кода. Вот почему даже не у всех базовых сборок самой
.NET есть этот атрибут. Например, частично доверяемому коду не разре-
шается использовать System.Runtime.Remoting.dll или System.Manage-
ment, dll. И причина в том, что Microsoft сама не уверена, что эти библио-
теки точно не позволят частично доверяемому коду повысить уровень сво-
их привилегий. ASP.NET лишь совсем недавно прошла соответствующие
тесты, и ее System. Web.dll присвоен атрибут Allow Partially TrustedC alters в
версии 1.1 инфраструктуры Microsoft .NET Framework.
.NET Remoting
Поддержка HTTPS
2C4t>2Df>ublicKeyrokert<M>3Dniifr
xmins -"http://sc:hemas.xmlsoap. org / 1 v s d I / *
xm in s : tns ="http: / /sche ma 5 .xml sen p.o rg / wsdl / "
xmlns:xsd="httpV /www.w3.org/3Oai/XMLSchema*
xrn Ins : xsi=' http: / / www. w3 .org / 2 OO 1 / XM L Sch*! ma - i n sta и се °
xmlns : suds="http:/ /www. w3.org / 2OOG ' wsdl/ suds'
к m In s : w 5 dl ="http : / /sc h e m a s .xmlsoa p .org / wstl 1 / "
xmins : soa pe n с ="hltp:// schemes -xmtsoap.org/ soap/ encoding/"
xmlns:ns2=nti tip:/ /schemas.microsaft.com/clt/nsa55em/MsdnMag.Remotii
2C<W)2OPubticKeyroken443Dnuil"
РИС. 1. WSDL
HTTP/1.1 200 OK
Content-Type: text/xml
Server; MS ,NET Remoting, MS .NET CLR 1.0.3705.288
Content-Length: 8663
Connection: Close
Объект на lepnejje
Пользовательские
.
P'jdlPiuiiy
ip ft рм атВД» щий об ъ в кт
L
Приемник
. йоякаошвяммв :
лринмнихи каналов
ПользаваияЬйнй
3-138
66 Шифрование
Разработка протокола
// IClientCnannelSlnk.ProcessHessage
public void ProcessMessage(IMessage msg,
ITransportHeaders reqwestHeaders, Stream requestStrea»,
out ITransportHeaders responseHeaders, out Strean responseStream)
f
// Шифруем поток
requestStream = CryptoHelper.Encrypt(requestStreain, .provider);
// Пересыпаем запрос
ServerProcessing result = _next.PropessMessage(
slnkStaek, requestMsg, requestHeaders, requestStrean,
out responseHsg, out responseHeaders, out responseStream);
return result;
68 Шифрование
Создание
пары Открытый Создание
ключей ключ
RSA
{ii шифрование
его открытым
Зашифрованный . ключом)
ключ
Сервер
// Шифруем сообщение
Quid Id;
loek( _t ra^saction Lock)
id = EnsuretDAndProviderCmsg, requestHeatfers);
requestStгеав =
SetupEneryptedMessaQe(requestHeacters, requestSt ream);
I
// Расшифронываем ответ
loek(_t raRsactionLoc k )
i
responseStream =
Dec ryptResponse(responseSt ream, responseBeaders):
if (responseStream =» (ищ SA
Id.EqualsLtransactiB» ClearSharediCeyO;
// Возвращаем результат
return respoflseStreara 1= null;
processingResult = ProcessEncryptedHassageC
transaetlD, sini^tack, requestHsg,
rgquestHeaders, requestStream,
out responseMsg, out responseHeaders,
out responaeStream);
9lse
см. след. стр.
Шифрование
// Ara...
default;
throw new SecureRemotin()Exception("Invalid request."};
Отпрыгни ключ
Общий ключ
Зашифрованное сообщение
L Зач-ифрованныЙ о г ват
Сеptap
case SecureTransaction.Uninitialized:
if (!RequireSecurlty(clientAddress))
{
processingResult = _next.ProcessMessage(
sinkStack, requestMsg, requestHeaders, requestStream,
out responseMsg, out responseNeaders, out responseStream);
}
else throw new SecureRemotingException("Security required.");
break;
Асинхронная обработка
В .NET Framework версии 1.0 нет поддержки асинхронной обработки для
пользовательских приемников канала на сервере (несмотря на наличие ме-
тода с броским именем AsyncProcessResponse в интерфейсе IServerChan-
nelSink). Все запросы к вашему серверному приемнику будут синхронны-
ми, даже если клиент выдаст асинхронный запрос; поэтому в серверный
приемник не нужно добавлять функциональность для асинхронной обра-
ботки.
// Шифруй* поток
encryptedStrean = S9tupEncryptedHessaae(fteacfers, stream);
Очистка сервера
Сервер должен хранить информацию о соединениях для всех подключен-
ных клиентов, иначе он не сможет расшифровать отправляемые клиентом
данные из-за отсутствия общего ключа, нужного для расшифровки. Если
к серверу подключено много клиентов (которые могут быть активны дли-
тельное время), в таблице соединений может оказаться устаревшая инфор-
мация. Поэтому сервер должен периодически очищать эту таблицу. В сво-
ей реализации я решил вместе с ключом записывать время последнего
обращения клиента и определять, прошло ли с момента последнего обра-
щения время, большее заданного значения. На рис. 9 показан код, перио-
дически перебирающий все клиентские соединения и, если они устарели,
удаляющий их из таблицы. Если клиент, информация о котором удалена,
попытается отправить зашифрованное сообщение, сервер сообщит, что
клиент не опознан. Тогда клиент и сервер проведут новое согласование и
начнут весь процесс сначала.
Создание приемников
Теперь, когда приемники написаны, нужно помочь инфраструктуре соз-
дать их экземпляры. Инфраструктура .NET Remoting не создает приемни-
ки напрямую. Вместо этого создаются «провайдеры приемников» (sink
providers), которые и отвечают за создание самих приемников. Провайде-
ры и приемники почти всегда связываются по принципу «один к одному»,
т. е. один провайдер служит для создания только одного приемника, одна-
ко ничто не мешает провайдеру создать несколько приемников.
public IServerChannelSink
CreateSink(IChannelReceiver channel)
I
IServerChannelSink nextSink = null;
if (_next != null)
{
if <(nextSink= _next.CreateSink(channel))
== null) return null;
}
return new SecureServerChannelSink(nextSink, ... );
I
Запрос
на создание
приемника
Ссылка Ссылка
на приемник Провайдер! на приемник Провайдер 2
Конфигурирование
HTTP-канал можно настроить через конфигурационный файл:
<channels>
<channel ref="http" port="8124" />
</channels>
78 Шифрование
<serverProviders>
<provider type=
"MsdnMag.Remoting.SecureserverChannelSinkProvider,SecureChannel" />
<formatter ref="blnary" />
</serverProviders>
Заключение
Канал, описанный в этой статье, не является идеальным решением. При-
емники не используют серьезные механизмы защиты потоков. Нет аутен-
тификации и подписи сообщений. Нет защиты от атак посредника (man-
in~ the-mid die attacks) или атак типа «отказ в обслуживании» (denial of
service attacks). Но надеюсь, суть решения понятна. Моя статья дает пред-
ставление о типах решений, возможных в .NET Remoting. От них могут
выиграть многие защищенные каналы, но возможности для творчества не
ограничены: транспортные приемники для поддержки именованных кана-
лов или MSMQ, IMessageSinks для кэширования возвращаемых значений,
каналы со сжатием (compression channels), ведением журналов (logging
channels), уведомлениями (notification channels) — на этом список не кон-
чается. По-моему, очень скоро появятся самые разнообразные расширения
от Microsoft и сторонних разработчиков, которые заполнят многие пробе-
лы, но это, безусловно, не должно помешать вам сегодня же начать работу
над приемником вашей мечты.
Защита в .NET
Сервисы признаков,
политик, разрешений
и применения политик
в инфраструктуре CLR
Компоненты и защита
Признаки
Защита по правам доступа кода начинается с признака (evidence). При-
знак служит доказательством происхождения данного куска кода и фор-
мируется загрузчиком на основе того, откуда загружается данный код, а
также на основе метаданных самой сборки.
Загрузчик сборок в конечном счете имеет дело с URL кодовых баз, и не-
которые из этих URL могут быть основаны на файлах. URL кодовой базы
(codebase URL) используется для определения трех из четырех типов при-
знаков, основанных на адресах (location-based evidence types): Url, Zone и
Site. Понять, что такое признак Url, легче всего, поскольку это не более
чем URL кодовой базы в исходной форме. Site и Zone производны от URL
кодовой базы на основе ее содержимого.
Zone — в том смысле, что тоже делит URL кодовых баз на категории.
ApplicationDirectory, обычно используемый в сочетании с типом призна-
ка Url, выдает специальные разрешения DLL, загружаемым из каталога
APPEASE приложения.
class App {
static void Malfl(string[] argv) {
// Принять URL кодовой базы как аргумент командной строки
string codebase = argv[03;
Сборкам, в имена которых входят открытые ключи (public keys), тип при-
знака StrongName присваивается при загрузке. Три свойства StrongName
соответствуют трем из четырех свойств имени сборки. Свойства Name,
Version и PublicKey инициализируются загрузчиком на основе метаданных
загружаемой сборки. Как и в случае с Site, UrI и Zone, вы можете сконст-
руировать объект-признак StrongName программным способом (рис. 2).
Но вы должны понимать, что признак StrongName разрешается создавать
только для сборок с открытыми ключами. Кроме того, обратите внимание,
что в коде на рис. 2 мне понадобился объект-обол очка типа System.Secu-
rity.Permissions.StrongNamePublicKeyBlob для байтового массива, в кото-
ром содержится открытый ключ. Этот объект принимает либо открытые
ключи, либо маркеры открытых ключей (public key tokens).
class App {
static StrongName CreateFromAssefflbly<Assembly assm) {
// Получить имя и открытый ключ
Assembly Name name = assm.GetNameO;
bytftO Pk = naiae.GetPublicKeyO;
// Сконструировать новый объект-признак StrongName s
StrongNamePublieKeyBlob blob =
new StrorigSamePublicKeyBloHjilO;
return new StrongHame(blou, name.Майе, паве.Version);
I
static void Hain(stri,ngt] argv) {
// Принять имя сборки как аргумент командной строки
string name - argv[Q];
class App {
static void KaiR(stringl3 argv) {
// Принять «к» файла сертификата как аргумент командной строки
string паде = argv[0];
Console. WriteLine(value.SeteertHasfcStringO);
Console.WriteLineCvalue.GetSe ri alNumberSt ri ng(});
Console. Writetine(valoe.6etPtibUcKeyString());
CoRsole.Wri teUne(value.6etKeyAloorith»(»;
<System.Security.Policy.Url version="1">
<Url>http://www. microsoft.com/foo.dlK/Url>
</System. Security,, Policy. Url>
<System.Security.Policy.Zone version="1">
<Zone>Internet</Zone>
</System. Security,, Policy. Zone>
<System.Security.Policy.Site version="1">
<Name>www.microsoft.com</Name>
</System. Security,, Policy. Slte>
class App {
static void Main(stringn argv) \
// Принять URL кодовой базы как аргумент командной строки
string codebase = argvEO];
Политика безопасности
Признак сам по себе в общем-то бесполезен. Он должен быть передан на
вход политики безопасности, с помощью которой CLR определяет, какие
разрешения могут быть назначены данной сборке на основе ее признака,
Политику безопасности CLR конфигурируют системные администраторы
и/или пользователи. Она также расширяема: в существующую инфра-
структуру можно включать пользовательские алгоритмы политики.
Политика безопасности может быть задана на четырех уровнях, пред-
ставленных значениями System. Security.PolicyLevelType перечислимого
типа:
Enterprise:
C:\WINNT\Hicrosoft.NET\Framework\v1.0.3512\config\enterprisesec.config
Machine:
C:\HINNT\Hicroeoft.HET\Freiework\v1.0.3512\config\securlty.conflg
User: C:\Documents and Settings\dbox\Application Data\
Hicrosoft\CLR Security Config\v1.0.3512\security.config
Заметьте, что политика, специфичная для AppDomain, отсутствует.
class App {
static void Maln{> {
lEnuraerator i » SecyrityHanager.^licy^ierarehyO;
while (i.Hovetiexto) {
PolicyLsvel level - (Policy-level)!.Current;
OQflsole,mteUneC4Q,1Q}: {1}",
level.Label,
level.Storelocation);
96 Защита кода и данных
namespace System.Security.Policy {
public interface IMembershipCondition {
Сервисы признаков, политик, разрешений и применения политик
кода
CodeGroup group = level.RootCodeGroup;
IMembershipCondition cond = group.MembershipCondition;
// Проверить на возможность членства
return cond.Check(evidence);
I
Чтобы к одной сборке можно было применить более одного набора разре-
шений, группы кода имеют иерархическую структуру и могут содержать до-
черние группы. Последние доступны через свойство CodeGroup.Children.
Большинство групп кода в политике безопасности являются экземплярами
типа System.Security.Policy.UnionCodeGroup. Если условие членства выпол-
няется, UnionCodeGroup перечисляет все дочерние группы кода и принима-
ет объединение (union) наборов разрешений каждой дочерней группы,
4-138
98 Защита кода и данных
ЧП4Ш
Рис. 8. Иерархия
class App {
static void DwpGroup(CodeGroup group, string prefix) {
Console. WriteLine<"{OHlH'{2}']:<3r,
prefix, group. GetType(), Name,
group. Kame, group. PermissionSetName);
fo reach (CodeGroup child in group. Children)
DumpSroop( child, prefix + " ");
Примечание 1:
FileCodeGroup выдает
каталогу, содержащему
сборку, разрешение
FilelOPermission с доступом
только для чтения
Примечание 2:
NetCodeGroup выдает
сайту - источнику сборки
разрешение WebPermission
class App {
static void Main(string[3 argv) {
string codebase - argv(0];
// Сконструировать признак
Evidence evidence - new EvideneeQ;
evidence.AddHost(new Uri(codebase));
evidence.AddHost(Zone.С reateFroiMJ rl(codebase});
try { evidence.AddHost(Site.CreateFromUrKcodebase)}; }
catch (ArguaentException) { /* ignore «/ }
class App {
static void Hain{string[] argv) {
string codebase = argv[0];
// Сконструировать признак
Evidence ev = new Evidence^);
evidence. AddHost (new UrKcodebase));
evidence, AdttHqst (Zone. CreateFrofflUrlXcodebase));
try { evidence. AddHost(Site,Creat«FrfflnUrl{codebase)};
catch EArgutnentException) { /* igrore */ 3-
Разрешения
Набор разрешений — это фактически не более чем группа отдельных раз-
решений, которая может быть пустой. Такие наборы доступны программ-
но через пространство имен Systeift. Security. Permission Set. Поскольку
PermissionSet реализует интерфейс System.Collections.I Collection, вы мо-
жете интерпретировать набор разрешений как стандартный набор объек-
тов (collection). Элементы набора гарантированно реализуют хотя бы ин-
терфейс System.Security.IPermission.
namespace System.Security {
public interface IPermission {
IPermission Union(IPermission rhs);
IPermission Intersect(IPermission rhs);
bool IsSubsetOf(IPermission rhs};
IPermission Copy();
void DemandO;
Операция Результат
A.l6SubsetOf(B) jFalse
[False s
ITrue
A Jnterse cl(B} , IsStibsetOf { В i I True
// Суммировать разрешения р1 и р2
IPerisission p3 * p1.Union(p2);
Debug.Assert(И.IsSubsetQf(рЗ));
Debug.Assert(pl.IsSubsetGf(p3));
lUnrestrictecfPermisslon perm
= new T(PermissionState. Unrestricted);
Debug. Assert (pe rm.lsUnrestrictedO);
PennissionSet ps
- new PermissionSet(PerBilsslonState.None);
ps.AddPerjBissiorKne* SecwrityPeriBission(fl));
ps.AddPemitssion(new SecurityPermission(f2));
ps.AddPermisslon<new FileIOPermissii3R(all, &"C:
\
SecarityPermfsslon UIPei|raiss!on
A, Union (В)
Чтобы вызвать метод Demand, вам нужно сначала получить объект разре-
шения или набора разрешений, указывающий, какие права следует требо-
вать от вызывающих. Взгляните на Си-метод Dns.GetHostByName:
using System.Net;
DnsPermission perm
= new DnsPennission(PennissionState. Unrestricted);
perfn.DemandO;
// Если мы попали сюда, политика разрешила просмотр DNS,
// поэтому занимаемся своей работой
using System.Security,Permissions;
namespace System.Net {
114 Защита кода и данных
DnsPermission(SecurityAction.PermitOnly,
Unrestricted=true)
f
В любом из этих примеров, потребуй метод Dns Get Host ByName какое-ни-
будь разрешение, выходящее за рамки DnsPermission, его запрос был бы
отклонен — даже если бы политика безопасности выдавала такое разреше-
ние методу LookupHost (и всем, кто его вызывает). Если в LookupHost
нужно запретить использование лишь какого-то одного разрешения, дос-
таточно следующего кода:
using System. Net;
using System. Security. Permissions;
Важно отметить, что в одном фрейме стека может быть только один набор
разрешений, использующий Deny или PermitOnly. Возьмем для примера
следующий метод:
using System.Net;
using System.Security.Permissions;
После того как метод добавляет некое разрешение, при любом запросе это-
го разрешения проход по стеку останавливается на фрейме данного мето-
да. Таким образом, добавляя какое-либо разрешение, вы указываете, что
все разрешения вызывающего следует игнорировать. Но вот ведь ирония:
добавление разрешения — тоже защищенная операция, которая требует от
метода, выполняющего это действие, разрешения SecurityPermission-
Flag.Assertion. Методы, добавляющие разрешение, обычно делают это в
связи с запросом меньшего уровня прав, чем тот, который скорее всего
имеется у вызывающих. Например, метод Dns.GetHostByName мог бы не-
сти такие атрибуты защиты:
\
using System.Security.Permissions;
namespace System,Net {
public sealed class Dns {
[
DnsPermission(SecurityAction.Demand,
Unrestricted=true), .
SecurityPermission(SecurityAction.Assert,
Flags=SecurityPermissionFlag.UnmanagedCode)
]
public static IPHostEntry GetHostByName(string host) {
// Если мы попали сюда, запрос (demand)
// и добавление (assertion) прошли успешно!
Защита кода и данных
[assembly;
DnsPer»ission(SecurityAcce38.ReqiiestMlfliau8i,
Un rest ri ctecP=t rue ),
Unrestricted-true),
FileIOPermisslon(SecurityAccees.RequestOptional,
Unrest riot edet rue)
FileIQPerfflission(SecurityAGcess. Bequest Re fuse,
Write=*3"e;\autoexee. bat")
1
[ UIPermissionCSecurityAction.InheritanceDemand,
Unrestricted=true) ]
public abstract class MyWindow {
public abstract void Show(4e();
I
У любых типов, производных от MyWindow, должно быть разрешение
UlPermission. Это требование будет удовлетворено неявно, в процессе за-
грузки производного типа.
Вычислить MaxGrantполитики
ReqMin
подмножество нет
MaxGrant?
Да
I
Granted = jMaxGrarit/'MReqMinwReqOpt)) - ReqRefuse
Вызван Вызван
H
Perm it Only «? Den*
(assembly; AssefnblyKeyFlle("pubpriv.snk") 3
StrongNameIdentityPeri4i3sion(
SecyrltyAction. InheritanceOemand, РиЬИсКеу=
"OQ2400000480000094000000060200000024000"
"052534131Q00400000100G100cb3eec5fQac3e5"
"30b73fe823ce6B84be13Sdf SI 19fdc(Jd4f f 3a65"
"68Qda9Qf2819al0ef6a1dbGeb5c5e6ea3822456"
"92a1505f88ad8f6716d366fb2d9d553eOf680b3"
"09f7e78dca447a23ec892d13f150e7c7b7997e8"
"5QdC6427386Qe752c1ffb75ed244522d293b46f"
"74d511e17f76b2874ee80cb82babea3t>624b745"
"Baca48b7")
1
public abstract class Personlmpl {
// Остальные члены опущены
Заключение
CLR поддерживает компонентно-центрическую модель защиты, извест-
ную под названием «защита по правам доступа кода». Эта модель предпо-
лагает, что каждая сборка может предоставить информацию о своем про-
исхождении (признак): кто писал этот код и откуда он скачан. Защита по
правам доступа кода использует конфигурируемую политику безопасно-
сти, которая выдает разрешения коду на основе признаков.
* Secure Coding Guidelines for the .NET Framework//MSDK Library. Microsoft Corporation.
2002. January. — Прим. изд.
Принципы безопасного кодирования для .NET Framework 123
Характеристика Описание
Важно заметить, что вся эта защита основана на указании операций, разре-
шенных коду, а авторизация пользователей — на информации, введенной
при входе в систему, и является совершенно независимым механизмом ни-
жележащей операционной системы. Рассматривайте эти две системы как
многоуровневую защиту. Например, для доступа к файлу авторизацию
должны пройти и код, и пользователь. Авторизация пользователей также
играет важную роль во многих приложениях, которые полагаются на реги-
страционную информацию или другие удостоверения защиты (credentials)
и используют эти данные для контроля за тем, что могут и чего не могут де-
лать определенные пользователи. Однако этот тип защиты в данном доку-
менте не рассматривается.
Например:
[assemblyiFilelOPermissionAttribute
(SecurityAction.RequestMinimum, Wrlte="C:\\test.t<np")]
[assembly:РеrmissionSet
(SecurityAction.RequestOptional. Unrestricted=false)]
... SecurityAction.RequestRefused ...
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using System.Collections;
class bug {
// Допустим, у вас есть API-элемент, предоставляющий доступ к полю
// через свойство, имеющее только аксессор get
public object m_Property;
public Object Property {
get { return m_Property;}
set {m_Property = value;} // (если нужно)
I
// Значение этого свойства можно изменить, вызвав метод, который
// передает параметр по ссылке и имеет следующую сигнатуру.
public static void m1( ref int j ) {
j = Int32.HaxValue;
I
public static void m2( ref ArrayList j )
(
j = new ArrayList();
i
public static void Hain(String[] args)
(
Console.WriteLine( "////// doing this with value type" );
<
bug b = new bug();
b.m_Property = 4;
Object[] objArr = new Object[]{b.Property};
Console,WriteLine( b.m_Property );
typeof(bug).GetMethod( "ml" ).Invoke( null, objArr );
// Обратите внимание, что свойство изменилось
Console.WriteLine( b.m_Property );
Console.WriteLine( objArr[0] );
}
Console.WriteLineC "////// doing this with a normal type" );
<
bug b = new bug();
ArrayList al = new ArrayListO;
al.AddO'elem");
b.m_Property = al;
5-138
130 Защита кода и данных
[StrongNameldentityPermissionAttribute
( Secu rltyAction . LinkDemand ,
PublicKey="...hex...",Name="App1",
Version="0. 0.0.0")]
public class Classl
Demand и LinkDemand
Учтите одну тонкость, если вы хотите, чтобы к вашему коду нельзя было
обращаться из других сборок. Метод, объявленный как virtual и internal,
может переопределять запись в таблице виртуальных методов (vtable) ба-
зового класса и доступен только в пределах своей сборки, так как являет-
ся внутренним. Однако ключевое слово virtual делает метод доступным
для переопределения, и он может быть переопределен из другой сборки,
если ее код имеет доступ к самому классу. Чтобы исключить возможность
переопределения, используйте декларативную защиту или удалите ключе-
вое слово virtual, если в нем нет острой необходимости.
Код оболочки
Применение оболочки может обнажить уникальный набор слабостей в
системе защиты — особенно в том случае, когда оболочка имеет более вы-
сокий уровень доверия, чем использующий ее код. Если в интересах вы-
зывающего кода выполняются какие-либо действия и при проверке защи-
ты не учитываются его ограниченные разрешения, возникает потенциаль-
ное слабое место, которым может воспользоваться злоумышленник.
Делегаты
Обработка исключений
void Main{) {
try {
Sub();
} except (FilterO) { ,
Console.WriteLinef"catch");
\
}
bool Filter C) {
Console.WriteLine("filter");
return true;
}
void Sub() {
try {
Принципы безопасного кодирования для .NET Framework 139
Throw
Filter
Finally
Catch
try {
Alter_Security_State();
// Здесь возможны любые изменения (изменение
// переменных состояния, переключение в
// неуправляемый контекст, олицетворение и т. д.).
// Этим может воспользоваться злонамеренный код,
// выполняемый до восстановления состояния.
Do_some_work();
} finally {
Resto re_Secu rity_State( ) ;
// Здесь просто восстанавливается ранее
// измененное состояние
г, -
В этом псевдокоде фильтр, находящийся выше в стеке, может выполнять
произвольный код. Есть и другие примеры операций, в которых достига-
ется аналогичный эффект: временная работа под другой идентификацией,
установка внутреннего флага, отменяющего некоторые проверки защиты,
смена культуры, связанной с потоком, и т. д.
End Class
try {
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
// Выполняется действие, приводящее к генерации исключения.
I
catch { throw; }
finally {
Thread.CurrentThread.CurrentUICulture = saveCulture;
}
!
Принципы безопасного кодирования для .NET Framework
Но в следующем коде эта проблема устранена, так как оператор finally га-
рантированно выполняется до проверки исключения блоками фильтрации
исключений вызывающего.
YourObject.YourMethodO
'.
Culturelnfo saveCulture = Thread.CurrentThread.CurrentUICulture;
try {
try {
Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE"};
// Выполняется действие, приводящее к генерации исключения
1
finally {
Thread.CurrentThread.CurrentUICulture = saveCulture;
catch { throw; }
>
Неуправляемый код
Иногда библиотечный код должен вызывать неуправляемый код (напри-
мер встроенные функции такого API, как Win32), Поскольку это означает
выход за периметр защиты управляемого кода, соблюдайте осторожность.
Если ваш код нейтрален к защите (см. раздел «Код, нейтральный к защи-
те»), то и ваш код, и код, который его вызывает, должны иметь разреше-
ния на выполнение неуправляемого кода ( Security Permission.Unmanaged-
Code).
Использование SuppressllnmanagedCodeSecurity
Пользовательский ввод
Пользовательские данные, каким бы образом они ни передавались (через
Web-запрос или URL, ввод в элементы управления Microsoft Windows
Forms и т. д.), могут неблагоприятно повлиять на код, так как эти данные
часто напрямую используются в качестве параметров при вызове другого
кода. Эта ситуация аналогична той, где злонамеренный код вызывает ваш
код, передавая недопустимые параметры, так что она требует принятия тех
же мер предосторожности. На практике сделать пользовательский ввод
безопасным гораздо труднее, так как в этом случае нет стека, где можно
было бы проверить наличие потенциально недоверяемых данных.
• Unicode-последовательностей (%nnn);
Удаленное взаимодействие
Удаленное взаимодействие (remoting) позволяет реализовать прозрачные
вызовы между доменами приложений (application domains, AppDomains),
процессами или компьютерами. Однако защита по правам доступа кода
146 Защита кода и данных
Защищенные объекты
Некоторые объекты содержат в себе информацию о состоянии защиты.
Эти объекты не следует передавать недоверяемому коду, иначе он может
получить полномочия, выходящие за рамки его разрешений.
Рассмотрим, например, создание объекта FileStream. Во время создания
запрашивается разрешение FilelOPermission и, если оно получено, возвра-
щается файловый объект. Однако, если ссылка на этот объект передается
объекту, не имеющему файловых разрешений, то последний получает воз-
можность выполнять чтение/запись в данный файл.
Самая простая защита таких объектов — запрашивать то же разрешение
FilelOPermission для любого кода, пытающегося получить ссылку на объ-
ект через открытый API-элемент.
Сериализация
Из-за сериализзции другой код может увидеть или изменить данные эк-
земпляра объекта, недоступные иными способами. По сути, коду, выпол-
няющему сериализацию, следует выдавать специальное разрешение:
SecurityPermission.SerializationFormatter. При политике по умолчанию
это разрешение не выдается коду, загружаемому из Интернета или интра-
сети, но предоставляется любому коду, выполняемому с локального ком-
пьютера.
Принципы безопасного кодирования для .NET Framework 147
Выдача разрешений
Защита на основе признаков основана на предположении, что высокий
уровень доверия (с широкими полномочиями) присваивается лишь коду,
заслуживающему доверия, а злонамеренный код является мало доверяе-
мым или вообще не имеет разрешений. В политике по умолчанию в .NET
Framework разрешения выдаются на основе зон (так, как они определены
в Microsoft Internet Explorer). Ниже приведено упрощенное описание этой
политики по умолчанию.
• Зона локального компьютера (например, c:\app.exe) является полно-
стью доверяемой. Предполагается, что пользователи помещают на свой
Принципы безопасного кодирования для .NET Framework 149
Опасные разрешения
Защита и конкуренция
void Dispose() {
if( _myObj != null ) {
Cleanup(_rnyQbj);
_myObj = null;
}
!
Конкуренция в конструкторах
void SomeSecureFunctionf) {
if(SomeDemandPasses(}) {
_fCallersOk = true;
DoQtherWorkO;
_fCallersOk = false;
}
I
void DoOtherWorkO {
if( _fCallersOK ) {
DoSomethingTrustedO;
152 Защита кода и данных
else {
DemandSomethingO;
DoSomethingTrustedO;
:
Если к DoOtherWork ведут другие пути, которые позволяют вызывать
этот метод из другого потока с тем же объектом, то недоверяемый вызы-
вающий код получает возможность обойти требования разрешений, предъ-
являемые системой защиты.
лы, а это, вероятно, нарушит работу сборки (хотя во многих случаях это не
создает уязвимости в защите).
Рекомендуется генерировать код с помощью Reflection.Emit, что позволя-
ет избежать многих описанных выше проблем.
Продумайте, не может ли злонамеренная программа изменить код при его
компиляции. Посмотрите, не возникает ли небольшой промежуток време-
ни, в течение которого злонамеренный код способен изменить исходный
код на диске перед чтением компилятором или загрузкой DLL вашим ко-
дом? Если да, защищайте каталог с этими файлами, используя в зависи-
мости от ситуации защиту по правам доступа кода или список управления
доступом (Access Control List, ACL) файловой системы.
Если вызывающий может воздействовать на генерируемый код, вызывая
ошибки компиляции, это тоже может угрожать безопасности.
Выполняйте сгенерированный код с наименьшими возможными разреше-
ниями (используя PermitOnly или Deny).
Управление секретами
Шифрование и подписи
Случайные числа
Проблемы установки
Проверьте следующее.
1. Имеется ли код, выполняемый как служба или обычно запускаемый
пользователями с правами администратора и доступный для записи
кому угодно?
2. Если код устанавливался на терминальный сервер, работающий в ре-
жиме сервера приложений, могут ли одни пользователи записывать
двоичные файлы, а другие — их запускать?
3. Есть ли файлы в системном каталоге или его подкаталогах, доступные
для записи пользователям, отличным от администраторов?
Кроме того, если программа взаимодействует с Web, учтите, что при рабо-
те с некоторыми Web-серверами пользователям разрешается запускать ко-
манды, часто выполняемые в контексте учетной записи IUSR_MACHINE.
Убедитесь в отсутствии файлов и элементов конфигурации, доступных для
записи кому угодно, так как этим могут воспользоваться приложения, вы-
полняемые под гостевой учетной записью.
Кит Браун
Безопасный код
Обзор расширений
S4U Kerberos в Windows
Server 2003*
В этой статье я исхожу из того, что у вас есть базовое представление о КегЬе-
ros. Такое представление можно получить из статьи «Exploring Kerberos,
the Protocol for Distributed Security in Windows 2000», опубликованной в но-
мере «Microsoft Systems Journal» за август 1999 г. (http://www.microsoft.com/
msj/0899/Kerberos/Kerberos.htrn). Более детальную информацию см. в книге
«Programming Windows Security» (Addison-Wesley, 2000). Спецификацию по
Kerberos см. в RFC 1510 на сайте IETF (http://www.ietf.org/rfc/rfcl5iO.txt).
Распознавание информации,
необходимой для авторизации
Первое расширение, о котором я расскажу, помогает серверу определить
группы, к которым относится пользователь в домене. Инфраструктура ав-
торизации Windows так усложнилась, что разработчику серверного ПО
стало практически невозможно определять эти группы вручную, Глобаль-
ные группы (global groups) задаются в основном домене (home domain)
пользователя, универсальные (universal groups) могут определяться в лю-
бом домене из основного леса (home forest) пользователя и хранятся в гло-
бальном каталоге, а локальные группы домена хранятся в домене сервера.
И все эти группы могут быть вложенными. Поскольку локальные группы
хранятся на сервере, с ними работать проще всего. Функция SIDHistory в
Windows 2000 приводит к тому, что для некоторых пользователей прихо-
дится неоднократно выполнять операцию раскрытия групп (group expan-
sion). А из-за другой функции, называемой карантином в домене (domain
quarantine), некоторые группы могут быть удалены. Короче, самостоятель-
ное определение членства доменного пользователя в группах — просто
кошмар для разработчика, и этого следует избегать.
S4U2Self
Решение, предлагаемое S4U, заключается в том, что сервер проходит че-
рез процедуру аутентификации Kerberos и регистрирует клиент, не пре-
доставляя его удостоверений. То есть на самом деле аутентификация кли-
ента не производится — сервер лишь получает идентификаторы защиты
(SID) для групп, в которых состоит клиент. Чтобы это было возможным,
контроллеры домена под управлением Windows Server 2003 теперь прини-
мают новый тип запросов Kerberos, в которых сервис запрашивает себе би-
лет (ticket) клиента, применяя для этого собственные удостоверения вме-
сто удостоверений клиента. Это расширение называется Service-for-User-
to-Self(S4U2Self).
Низкоуровневые детали всего этого весьма сложны, но, чтобы сделать пер-
вый шаг, разработчику сервиса достаточно вызвать всего одну функцию:
LsaLogonUser. По своему духу это похоже на показанный мною вызов
LogonUser, однако указывать пароль клиента здесь не требуется. В резуль-
тате возвращается маркер, который сервис может использовать с такими
функциями, как AccessCheck и CheckTokenMembership, а также с новым
семейством функций авторизации AuthZ. Это позволяет сервису прове-
рять права доступа по дескрипторам защиты (security descriptors) управ-
ляемых им объектов.
ULONG authnPkg;
_cnecknterr(L"LsaLookupAuthenticatlonfackage",
LsaLookupAuthenticatioriPackageCnlsa,
&pkgName, &authnPkg));
SquotaLiitiits,
&sitb8tatus));
// Очистка
f ree(s4uLoflon);
LsaFree8eturaBuff6r( prof lie);
LsaClose(hlsa);
return htok;
void mairtO i
HANDLE htok s _84uLogon(L"aliceeesec,com");
Проблема делегирования
Еще один кошмар разработчиков — делегирование. Даже когда клиент
способен использовать Kerberos для аутентификации сервисом, контекст
зашиты клиента, предоставлемый сервису, обычно не содержит его сетевые
удостоверения. Представьте, что произошло бы без такой меры предосто-
рожности: сервис, не являющийся доверяемым в своем домене, мог бы ис-
пользовать клиентские удостоверения из другого домена для доступа к ре-
сурсам, к которым сам по себе он обычно не получает доступа. Ни один
клиент не стал 5ы использовать такой сервис, если только тот не относит-
ся к числу полностью доверяемых.
любой точке сети сутки напролет. Однако такой механизм используют очень
немногие. Тому две причины: во-первых, компрометация сервиса, доверяемо-
го для делегирования, влечет за собой компрометацию всех делегированных
удостоверений, превращая этот сервис в приманку для хакеров. А во-вторых,
вы должны полностью доверять локальному администратору этого сервиса,
поскольку он может повысить уровень собственных привилегий, неправиль-
но используя в сети удостоверения, делегированные клиентом. Очевидно, что
этот механизм применим лишь в очень редких случаях.
AppServer Properties
wn ] :: Member Of
Delegation Managed By -' Diet-in
Cancel
6-138
162 Защита кода и данных
LA-KEITH Properties
1|JL
Заключение
Тесная связь авторизации и аутентификации — и благо, и проклятье. Пре-
имущества очевидны. Когда клиент получает билет Kerberos, контролле-
ры домена записывают в них SID-идентификаторы групп, что исключает
лишние сетевые запросы при авторизации. Упрощается и администриро-
вание. Недостаток в том, что получить данные авторизации можно только
через аутентификацию Kerberos, и расширения вроде только что рассмот-
ренных ничуть не облегчают взаимодействие с другими реализациями
Kerberos. Еще один ограничивающий фактор — двусторонние доверитель-
ные отношения между лесами, необходимые для того, чтобы эти механиз-
мы могли действовать через границы леса.
В IIS 6.0 и новых средствах для IIS 5.0 особое внимание уделяется защите
Web-сервера от атак. Об аутентификации рассказывал Джеф Просиз (Jeff
Precise) в своей статье «ASP.NET: An Introductory Guide to Building and
Deploying More Secure Sites with ASP.NET and IIS», состоявшей из двух
частей (см. номера «MSDN Magazine» за апрель и май 2002 г.). В этой ста-
тье рассматриваются предотвращение проникновений, URLScan, IIS Lock-
Down для IIS 5.0, новые средства IIS 6.0, связанные с защитой, а также
функциональность Web-сервера, запланированного к выпуску вместе с
Windows Server 2003.
Предотвращение проникновений
Искусство и наука предотвращения проникновений состоят в том, чтобы
разрешить людям осуществлять доступ, выполнять и контролировать
только определенные части Web-сайта. Раньше информационное наполне-
ние (контент) Web-серверов было статическим, и администраторам прихо-
дилось следить лишь за тем, чтобы к клиентам не попадали не предназна-
ченные им файлы. Теперь, когда на серверах могут выполняться сценарии,
администраторам нужно предотвращать запуск нежелательного кода. По-
скольку атаки на Web-сервер производятся как извне, так и изнутри ком-
пании, в которой установлен этот сервер, для его надежной защиты Web-
администраторы должны блокировать атаки с обеих сторон брандмауэра.
Вот что однажды произошло со мной. Один мой приятель должен был пе-
редать мне файл по FTP. Я запустил FTP-сервер, установленный вместе с
IIS 5.0, и разрешил привилегии записи для анонимного пользователя. Во-
обще-то я знал, что тем самым я прямо-таки напрашиваюсь на неприятно-
сти, но приятель сказал, что он немедленно закачает файл. И сделал это —
только через три дня, а за это время два типа закачали на мой сервер пол-
нометражные фильмы и бесплатно использовали мой канал связи и место
на сервере. Хотя на моем жестком диске достаточно места для хранения
этих фильмов, хакер вполне мог бы чем-нибудь заполнить весь диск и по-
ставить сервер на колени. (Не говоря уже о том, что я стал распространи-
телем незаконной продукции.)
Kent:
..:
i У I , '
Усовершенствования в SSL
IIS 6.0 предоставляет более совершенную реализацию SSL. Помимо рас-
ширенной настройки производительности, IIS 6.0 предлагает администра-
торам удаленно управляемый сертификационный объект и выбор провай-
дера криптографического сервиса.
ТСР/1Р-фильтрация
Другое средство защиты — TCP/IP-фильтрация портов в рамках сетевой
конфигурации операционной системы. Данный термин в определенной
мере неправилен, так как это средство фильтрует TCP, IP и UDP. Однако
TCP/IP-фильтрация действительно повышает безопасность Web-сервера.
Рис. 3. ТСР/1Р-фильтрация
Здесь вы можете соблазниться выбрать Permit Only и задать порт 80, огра-
ничив трафик исключительно Web-запросами. Но тогда вы не сможете пе-
ресылать файлы на этот компьютер, отправлять и принимать электронную
почту, запускать FTP-сервер и т. д. Прежде чем закрывать все порты, сто-
ит провести небольшое исследование. К призеру, если вы используете SSL
и FTP-сервер, вы должны открыть порты 443 и 20*. Так как вам нужен
доступ к данному компьютеру по TCP/IP, эти порты следует добавить не
только в столбец TCP, но и в столбец UDP Если вы хотите получать с
ASP-страницы имя базы данных SQL Server по имени компьютера, на ко-
тором она находится, например:
<Х
Set оСопп = Server. CreateObject("AOODB. Connection")
oConn.Open "Trusted_Connect ion-yes; drive r=SQL
Server; serve r=SQLMACHINE001;database=NyData; "
то откройте порты WINS: 137, 138, 139 (UDP). А чтобы WebTrends могла
выполнять обратную DNS-трансляцию применительно к файлам журнала,
откройте стандартные порты DNS: 42 (UDP) я 53 (TCP/UDP). Независи-
мо от того, сколько времени займет определение нуждающихся в защите
портов, лучше всего выбрать Permit Only и найти эти порты автоматиче-
ски. Список стандартных портов приведен в табл. 1.
Порт Протокол
21 FTP
23 Telnet
25 SMTP
53 DNS
68 DHCP
70 Gopher
80 HTTP
110 POP3
119 NNTP
135 RPC, DNS, DHCP
139 Входящие SMB-сеансы
143 ШАР
389 LDAP
443 HTTP (SSL)
445 Исходящие SMB-сеансы
1433 Microsoft SQL Server
3389 , Microsoft Terminal Services
8080 HTTP Alternate
Подводя итоги
IIS 6.0 устанавливается в режиме полной блокировки (lockdown mode) и
не обслуживает никакие страницы за исключением тех, которые вы указы-
ваете явно. Для статических файлов и динамических расширений эта
функциональность реализуется по-разному. Статическим файлам не нуж-
но выполнять код в ответ на запрос. К ним относятся графические файлы,
HTML-страницы и каскадные таблицы стилей. А динамические файлы
(страницы ASP и Cold Fusion), напротив, требуют выполнения.
Заключение
В новом IIS 6.0 ответственность за защиту перекладывается с поставщика
программного обеспечения на плечи администраторов. Теперь именно они
решают, какие службы включать, а какие — отключать. Усилия, приложен-
ные к обеспечению безопасности IIS 6.0, делают его более защищенным, а
инструменты вроде IIS LockDown пред ос таил я ют администраторам пока
не обновленных Web-серверов некоторые преимущества IIS 6.O.
Авторизация
Authorization Manager
ReadCataloo,
Groups PlaceHold
Corporate Library Application
CheckOutBook
Gil Groups
ChecUnBook
-j (Tyj Definitions
Ad dBookTolnventory
RemoveBookFromlnventory Qpsration
Task Definitions
ШШ=йЙЙйНйй*
ИРРИИДИЯ!
Ш-Щ Rote Assignments
Хранилище
А сейчас вообразите себя администратором, развертывающим приложе-
ние. Переключитесь в режим администрирования через Action | Options и
184 Защита кода и данных
Groups
Q Corporate Library Appkatlon
Groups
Definitions
T** Definitions
[*] Ш Opefatlon Definitions
lAzClientContext ctx =
арр.InitializedlentContextFromToken(htoken, null);
Где же взять маркер клиента? Ну, это зависит от типа создаваемого при-
ложения. Вот, например, фрагмент С#-кода из ASP.NET-страницы, полу-
чающий маркер клиента. Б этом примере в файле web.coring указан режим
аутентификации «Windows*, a IIS настроен на использование аутентифи-
кации средствами Windows:
Windowsldentity id = (WindowsIdentity)User,Identity;
IntPtr htoken = id.Token;
Если вам известно только имя клиента и нет доступа к его маркеру, поду-
майте, нельзя ли все же как-нибудь раздобыть маркер, потому что мар-
кер — самый надежный способ получить группы, в которые входит клиент.
Кроме того, как я уже упоминал, это самый быстрый способ. Если вы уве-
рены, что до маркера вам никак не добраться, используйте альтернативный
способ инициализации контекста по имени учетной записи в форме «до-
мен\пользователь». Такой вызов может потребовать обращений к контрол-
лерам домена для определения доменных групп, так что будьте готовы к
тому, что его выполнение займет некоторое время:
lAzClientContext ctx =
арр.InitializeCHentContextFromName(name, null);
// flanee в коле. ..
Qbjectn operations = { opAddSookTotnventory H
objectH scopes = { "" };
и
objeetn results («bject[])
ct>^AceessCheck(name0f8GOk,
scopes, operations,
null, null, null, null, null);
int result = (int)resultEG];
if <NG_£RRGR == result) {
// Доступ разрешен
e
*lse {
// Доступ заменен, результат содержит код ошибки
В этом случае области удобны, так как они позволяют совместно использо-
вать низкоуровневые операции и даже некоторые задачи, роли и группы при-
ложения. Увы, области с тем же успехом могут вас напрочь запутать и при-
вести к плачевным результатам. Например, при вызове AccessCheck второй
параметр определяет проверяемую область. Если пользователь предоставил
имя области, например в URL запроса, то прежде чем передавать его в Access-
Check, следует убедиться, что у этого имени канонический формат, иначе
догадливые пользователи могут обхитрить вас и заставить задействовать
190 Защита кода и данных
Группы приложения
В AzMan существует замечательная функция — Application Groups.
В больших организациях добавление новых групп для вашего приложе-
ния в службу каталогов может оказаться весьма трудоемким. По сути,
если определение новой группы требуется только вашему приложению,
вы можете оказаться в неприятной ситуации, когда утомленный адми-
нистратор домена откажется добавить еще один элемент в уже и так
плохо управляемый список групп. В этом случае вас спасет функция
Application Groups. На уровне хранилища, приложения или области
можно определить группы пользователей и присвоить им логические
имена, а потом задействовать эти группы при назначении ролей.
Authorization Manager
-Д my*cr*.xrrtl
p'1 Groups
3 Я corporate Library Application
Сценарии
Когда статических полномочий недостаточно, приложение может предо-
ставлять дополнительный контекст в виде переменных и ссылок на объек-
ты, передаваемых AccessCheck. Это позволяет автору сценария добавить
бизнес-логику на языках JScript или VBScript без перекомпиляции прило-
жения. Например, ранее определенной задаче «получить историю опера-
ций читателя» можно предоставить дополнительный контекст, содержа-
щий, скажем, набор ролей, которые есть у данного пользователя, и булево
значение, указывающее, обращается ли клиент к своей истории или к чу-
жой. Это позволит написать сценарий, разрешающий менеджерам про-
сматривать историю операций любого читателя, но запрещающий обыч-
ным пользователям читать любую историю, кроме своей. Вариант сцена-
рия, решающего это задачу, приведен на рис. 7.
7-133
194 Защита кода и данных
Аудит
Аудит проверок доступа в исполняющей среде — очень важная функция,
доступная только при размещении хранилища Authorization Manager в
Active Directory. Если вы хотите включить эту функцию, щелкните имя
приложения правой кнопкой мыши, выберите Properties и откройте вклад-
ку Auditing. В период выполнения важна учетная запись, под которой ра-
ботает серверный процесс: ей необходимо выдать привилегию Generate
Audits. Встроенные учетные записи Local Service, Network Service и SYS-
TEM по умолчанию обладают такой привилегией. Наконец, обратите вни-
мание на то, чтобы результаты аудита сохранялись в журнале событий
безопасности; для этого на сервере нужно разрешить аудит доступа к объ-
ектам.
Заключение
Authorization Manager — важное средство создания защищенных систем в
Windows. Он расширяет концепцию ролевой защиты, появившейся в MTS
и СОМ+, но применим в любом серверном приложении, а не только в
СОМ-серверах. Authorization Manager помогает централизовать логику за-
щиты в виде четкой политики безопасности, которую можно хранить в
Active Director}' и предоставляет простой API для проверки прав доступа.
Безопасность
Защита SOAP-пакетов
на основе WS-Security
и приемников каналов
Remoting
Прокси Сервер
FormatterSmk FormatterSink
ICIientChannciSink IServerChannelSink
void AsyncProcessResponseCIClientResponseGhanRelSiftkStack
sinkStack, object state, ITransportHeatiers headers,
Stream stream);
void AsyncF'rocessResponsedServerResponseChannelSiRkStack
sirtkStack, abject state, message iasg, ITransportHeadars
headers, Stream stream);
void ProcessMessagedSeFverResponseChafinelSinkStack
IMessage requestMsg, ITransportNeaders requestJ-teaders,
Stream requestStreai», out IHessage respofrse^sfl, out
ITransportHeaders responseHeacters, out Stream
responseStream);
WSE-классы
Теперь рассмотрим WS-Security и использование маркеров имени пользо-
вателя для подписи Remoting-сообщений. Начнем со знакомства с WSE-
классами. Вот эти классы и их описания.
200 Защита кода и данных
<channels>
ref=-"http"
<clientPrQvlders>
«formatter ref="soap" />
<provider type="SecuritySink.SecurityChannelSinkProvltier,
SeouritySlnk"
TokenHeIper="SecyritySink.TokenHelperObJ,SecuritySiRk'"/>
</GltentProvitlers>
<channels>
<ehannel ref="http" port="99Sr>
<serverpfavidet"s>
<provtber s
aw. след. стр.
202 Защита кода и данных
<ofiannel8>
<charvnel re?="tep" port="9999">
<se rve r Provide rs>
«provider
type= "SeeurttySink. SecurityServerCbannelSinkProvider,
SecurityStnk" />
<formatter ref="soap" />
</serverprovlders>
ProcessMessage и SignMessage
Функция ProcessMessage обрабатывает сообщение перед тем, как передать
его следующему приемнику. При этом предварительная обработка поруча-
ется закрытому методу SignMessage. Последующая обработка ответа не
выполняется.
// Подпись
'// Подписываем
// Сохраняем
else
. Save{ in Stream);
XffllftodeUst nodelist;
IHmiaerator rtodellstSnuis;
nodelist = req£nv.Header.GetHeBtentsByTagNaiBe<e"Secarity
@"http r //sctramas . xslsoao. о rg/ws/29S2/Q7/saeext " ) ;
nodelistEfluB = nodellst.EetEnunnsratorO;
ArrayList nodestodelete = new ArrayListO;
try
{
wMle(nodelistEnuifi.MoveNextO)
{
XmlElement elea = nodelistEnum.Currertt as
XmlElefflent)FiodestodeleteEnum. Current);
}
MemoryStreaffl stnr - new KemoryStreanK);
req£nv, SaveCstrfi);
stra. Position^;
processing * „nextSink.ProeesEiMessaflefsinkStack, rtull,
cequestHeaders, sitrnt, oot respoflseHsg,
out responseHeaders, out responaeStrea»);
Расширение реализации
Одно из возможных расширений этого приемника — реализация эквива-
лента олицетворения (impersonation), или подмены. Когда подпись прове-
ряется на сервере, на этой стороне имеется допустимый объект защиты, из
которого можно получить маркер UserName:
SecurityTokenCollBction col = reqCtx.Security.Tokens;
lEnumerator e = col.GetEnumerator();
System.Threading.Thread.CurrentPrincipal = p;
Заключение
Благодаря новым WSE-классам, совместимым с .NET Framework, реали-
зовать клиентский и серверный приемники удаленного взаимодействия
очень легко. Эти классы упрощают подписание и шифрование SOAP-co-
общений, а архитектура цепочки приемников очень удобна для расшире-
ния обработки сообщений.
Полезные советы
по выявлению
уязвимостей в вашем коде
Как мне представляется, есть три способа оценки кода: глубокий анализ,
беглый анализ и смешанный подход. Я обычно пользуюсь третьим, так как
он позволяет быстро оценивать большие объемы кода. Если мне встреча-
ется место, требующее на мой взгляд более глубокого анализа, я помечаю
его для более глубокого анализа, возможно, с привлечением других экс-
пертов в данной области. Но сейчас я хотел бы обсудить беглый первона-
чальный анализ кода — «Огляди и отметь», как я называю этот способ бы-
строй оценки кода с выделением областей, нуждающихся в более деталь-
ном анализе.
ные способны вызвать сбой в этом коде?». Это очень тщательный метод,
требующий много времени. Другой прием состоит в поиске известных и
потенциально опасных конструкций, а затем отслеживания данных обрат-
но до входной точки. Например, рассмотрим следующий код:
void fuction(char *p) {
char buff[163;
strcpy(buff ,
while (*s != P \ V )
*d++ = *s++;
DRIVER={SQL Server};SERVEH=hrserver;UID=sa;PWD=$esame
«select», «insert», «exec» и все известные мне имена таблиц и баз данных.
В этом мне помогает следующая команда:
Hello,
<Х Response.WriteOtequest.QueryStringC'Name")} X>
[HKEY_CLASSES_ROOT\CLSID\<GUID>\Implemented
Categories\{7QD95801-9882-11CF-9FA9-OOAA006C42C4}]
[HKEY_CLASSES_HOOACLSID\<GUlD>\Implemented
Categories\{7DD95802-9882-11CF-9FA9-OOAA006C42C4}]
Заключение
Вы получили приблизительное представление о первом проходе в процес-
се оценки кода. Многие из ошибок просты, и можно возразить, что разра-
ботчики просто не должны их допускать. Но, увы, допускают. Однако зна-
ние того, что ваш код будет проанализирован на защищенность, обычно
приводит к тому, что код изначально получается более защищенным.
Затемнение кода
Пресечение попыток
обратного проектирования
вашего кода Visual Basic
.NET или С#
Дизассемблирование
.NET Framework SDK поставляется с дизассемблером ILDASM, который
позволяет декомпилировать сборки .NET Framework в операторы IL-ac-
семблера. Для запуска ILDASM убедитесь, что .NET Framework SDK уста-
новлен, и в командной строке наберите ILDASM, указав далее имя про-
граммы, которую вы хотите дизассемблировать. В данном случае мы набе-
рем «ILDASM vexed.net.exe». Запустится пользовательский интерфейс
ILDASM, через который можно просматривать структуру любого прило-
жения .NET Framework. На рис. 1 показан дизассемблированный метод
Undo.
QnPaiHivndl]
Refresh • voidlclass |Si4lem DiawmglSjistern.Draw«ig.6re
Tolmage. class [System DfawingJSystem Dialing Burriapl
ToShng
ToStimg
draw VHd[i
.itefiftedi public fiidebysig instance «old undoO cil »a
Декомпиляция
Если вы сейчас думаете, что ваш исходный код сможет увидеть и понять
лишь узкий круг знающих IL-ассемблер, вспомните, что декомпиляция на
этом не заканчивается. С помощью декомпилятора можно воссоздать под-
линный исходный код. Утилиты такого рода способны декомпилировать
.NET-сборку непосредственно в исходный код на высокоуровневом языке
вроде С#, Visual Basic .NET или C++. Посмотрим на метод Undo, рекон-
струированный декомпилятором Anakrino:
Углубляемся в затемнение
Затемнение выполняется с применением ряда смежных технологий. Его
цель — скрыть характер программы, не меняя ее поведение в период вы-
полнения. Это не шифрование, но в контексте .NET-кода это даже к луч-
шему. Дело в том, что вы могли бы зашифровать .NET-сборки и сделать их
полностью нечитабельными. Но такой способ создает классическую ди-
лемму: поскольку исполняющая среда способна выполнять лишь неза-
шифрованный код, вместе с зашифрованной программой должен хранить-
ся ключ для расшифровки. А раз так, то нетрудно создать утилиту для из-
влечения ключа, расшифровки кода и записи IL на диск в его исходном
виде. После этого программа будет абсолютно беззащитна перед декомпи-
ляцией.
if (this.г.Length >= 2)
this.г = this.r.Substring(0, this.r.Length - 2);
this.a(this.q[this.p - this.p / 50 * 50]);
this.a(this.e);
Как видите, и без других способов затемнения понять этот метод уже на-
много труднее.
Дополнительные технологии
С помощью описанных выше технологий Dotfuscator Community Edition
обеспечивает хорошее затемнение, но вы должны знать и о дополнительных
технологиях, которые предоставляют еще большую защиту и способны во-
обще предотвратить обратное проектирование. Dotfuscator Professional
Edition реализует множество дополнительных технологий, включая затем-
нение потока управления (control flow obfuscation), шифрование строк
(string encryption), инкрементное затемнение (incremental obfuscation) и
уменьшение размера (size reduction).
изменения логики. Что важнее, она удаляет ключи, которые ищет деком-
пилятор для правильного восстановления высокоуровневых операторов
исходного кода, таких как if-t hen-else и циклы. Фактически эта техноло-
гия нацелена на нарушение работы декомпиляторов.
[) vexed.net
ii 18 slBls/PackDele
41 *rj slats
raadME
*i{ PixslData
*J frmMain
8! *» prelerences
ilH -*f about
*ij board
h
% .dor: voidt^Bxed.nelfrwWain. siring. System.Drawing.Point int32)
dor: void(System Drawing.Graphics, string.
ctor: void(Syste(n Drawing.Graphics, string, int3?. System Drawing.Point]
S If* mil. voidlSyalem.Crowing.Graphics, string, in(32. System.Dtewing.Point)
Классон 20 20 100
Методой 164 144 88 39
Подводные камни
Затемнение — особенно переименование — может быть затруднено в
сложных приложениях и весьма чувствительно к правильности конфи-
гурации. Если не соблюдать осторожность, затемнитель может повредить
ваше приложение. В этом разделе мы расскажем о некоторых наиболее
распространенных проблемах, возникающих при использовании затем-
нителей.
Заключение
Не давайте хакерам применять удобную утилиту ILDASM к вашему при-
ложению с сомнительными целями. Защитить ваш код поможет хороший
затемнитель. Затемнение препятствует обратному проектированию. Dot-
fuscator Community Edition, поставляемый с коробочной версией Visual
Studio .NET 2003, обеспечивает хорошее затемнение кода всего нескольки-
ми щелчками кнопки мыши.
Защита
Закрытие доступа
к строкам подключения
баз данных и другим
секретным параметрам
в коде*
Скрытие данных
Скрытие данных (data hiding) иногда называют зашитой через затумани-
вание (security through obscurity). Полагаясь на этот способ, вы считаете,
что только вам известно, где хранится секретная информация, и надеетесь,
что никто другой не сможет это выяснить. Подвох в том, что приложение
тоже должно знать, как получить доступ к данным, поэтому возможность
сохранения секретов во многом зависит от способности приложения защи-
щать это знание.
Process
iexplore.exe SelValue HKOJ\Softi«ate\Mic-№soft\lnternelExplQreAMdn\FulScreeri SUCCESS
iexplore.exe: SetValue HKCU\Soltwaie\Microsoft^nternelExploFer\Main\Window_.. SUCCESS 2COO s
iexpbie.exe: SefValue HKCUXSo/lrtareSMic ra SoftWindows \S hellN oRoamVB agN! R . .
SUCCESS 02 02 l!
ienplore exe: SelValue HKCU\Software\.Mic rosofftWindoi'MSfieilNoR oam\B agMR . .
SUCCESS HOOf
iexplore.exe. DeleteVal. HKCUVSoftW3ie\Miaosoft\Whdow\ShellNoRaam\BagMR .. NOTFOU...
iexpiore.exe SetValue HKCUVS oftwaieSM ic rasoft\Windows\S hefN oRoanAB agMR SUCCESS
iexplore.exe: DeleteVal НКШ \Sofl i*are\MicrosoftVWind№vs\She!INoR oarnVBagMP. .SUCCESS
iexptue exe: DeleleKeji H*CCU\SoHwate\.MJciosoltVWJndows\S hellNoR oamVB agM R . .
SUCCESS Kev. Q
iexplore.exe: SetValue H KCU \S oftware\M icroso/t\WindowE4ShelfNoRoam\BagMR. ..
SUCCESS 0300!
iexDlore.exe: SetValue HKCU\SoltwaJe\Micro3oH\Wmdows\ShellNoR oam\BagM R . . . SUCCESS 02021,
iexpbie.exe SetValue HKCU VS oltwaieXM ic-osof t\Windows\S heIN ofi oam\8 agMR.
SUCCESS Ox8E
iexptare еке: SetValue HKCU\Software\Mbosof[VWindows\ShellNoRoarn^agMR. SUCCESS FFFFI
(explore exe: SetValue SUCCESS OxFFFF
(explore exe: SetValue HKCUVSoftwaieSMiciosollWindcjwisVSheDNciFloamSBags1.!.. SUCCESS OxFFFf •
S «Value HKCUXSo»ware\Miciosoft Wind ows\SheflNoRoam \Bags\i. SUCCESS
т
Рис. 1. Regmon
Закрытие доступа к строкам подключения баз данных 235
*• Anakrino
Back
i•
щ Co isoleApplicationl
jpnvate static void Main(stnng[] args) {
Щ Г"Ц ConsoteApplicatnnl exe string localG;
И- {) ConsoteApphcationl string local!;
Я *i* Class! SglConnection loca!2;
. ьф .ctor(). void local 0 = ";
: ,§Ф Connect!oSqlSeivei locall = "ЭЕВШЕШ1'.
--*• DoSomething(Si^Con Iocal2 = null;
loca.12 = Classl.ConnectToSqlServer(localO,
Classl.DoSomethingClctcalZ);
е
-За ТуР Reference locaT2.Closei;j;
Reteiences
Рис. 2. Декомпиляция
Управленце доступом
может базироваться на том, что.
Шифрование данных
При использовании шифрования ни скрытие, ни управление доступом к
данным не являются основными целями. Поскольку информация зашиф-
рована, знание ее местонахождения и способность получить к ней доступ
не гарантируют ее полезности взломщику, пока тот не обнаружит ключ для
расшифровки.
[cledb]
; Everything after
this line is an OLE DB
initstring
provider=MSDASQL.l;
user io=sa;
Password-Hi
Persist security
=True;
Data source=localhost;
initial catalog-master
Оценка вариантов
По мнению многих экспертов по безопасности, лучший способ защиты
секретов — вовсе не использовать их. Например, если вам нужно защитить
строки подключения к базе данных, содержащие SQL-удостоверения, по-
думайте об отказе от SQL-аутентификации. Если ваше приложение спо-
собно для подключения к серверу баз данных применять Windows-аутен-
тификацию вместо SQL-аутентификации, вам вообще не нужно будет бес-
покоиться о защите SQL-удостоверений.
Алгоритмы хэширования
Самые популярные алгоритмы хэширования — MD5 и SHA-1. Длина хэ-
шей SHA-1 равна 160 битам, а длина хэшей MD5 — 128, Алгоритм
SHA-1 чуть медленнее, но обеспечивает более высокую защиту, чем MD5.
В дополнение к MD5 и SHA-1 NET Framework предлагает поддержку 256-,
384- и 512-битных версий алгоритма SHA, что еще надежнее, но, вероят-
но, и медленнее.
using System.Web.Security;
...
string base64Hasn\'alue =
FormsAuthentlcatlon.HashPasswordForStoringlnConfigFileC'mypassword",
"shaT);
Шифровальные ключи
Если вашему приложению необходимо знать текстовые значения секрет-
ных данных, вы не сможете применить хэширование. В таком случае ис-
пользуйте обратимое шифрование с симметричным ключом или с парой
из открытого и закрытого ключей. Если вы не уверены, какой тип клю-
чей выбрать, используйте симметричные ключи. Основной недостаток
шифрования с открытым ключом — низкая производительность, которая
может быть в 1000 раз меньше, чем при шифровании с симметричным
ключом. Шифрование с открытым ключом также накладывает некоторые
ограничения на размер текстовых данных, которые могут быть зашифро-
ваны.
Необратимое
(кэширование)
Шифрование данных
Алгоритм Rijndae! 126, 192, 256 (AES)
Симметричные
Triple DES- 112, 168
ключи
Берегитесь LSA
Во времена расцвета Windows NT 4.0 функции LSA Policy LsaStore Private-
Data и LsaRetrieve Private Data предоставляли достаточно надежный спо-
соб защиты секретов приложения. Хотя функции LSA Policy доступны в
Windows 2000 и выше (и по-прежнему используются для защиты таких
данных, как пароли для служб Windows), Microsoft не рекомендует приме-
нять их, поэтому я упомянул эти функции лишь для полноты картины,
чтобы объяснить, почему их следует избегать.
Проблема с функциями LSA Policy в том, что они не только управляют
ключами и шифруют их, но и работают с хранилищами данных, используя
защищенную область реестра Windows. Может показаться, что это хорошо,
но это не так, потому что объем доступного места для функций LSA Policy
ограничен 4096 слотами, половина из которых уже занята системой. Если
приложения будут использовать LSA Policy для хранения секретных дан-
ных, им просто не хватит места. Далее, поскольку лишь в высшей степени
привилегированные пользователи могут вызывать функции LSA Policy,
они не сработают для приложений, выполняемых под непривилегирован-
ными учетными записями, такими как ASP.NET. Хуже того, существуют
инструменты вроде LSADUMP2 (http://razor.bindview.com/tools/desc/
Isadump2_readme.html), способные раскрыть секреты LSA. Вывод: не при-
меняйте функции LSA Policy для защиты данных.
Использование DPAPI
Как альтернативу функциям LSA Policy компания Microsoft рекомендует
применять подмножество Crypto API, которое называется DPAPI. DPAPI
включает две функции, пригодные для защиты данных: CryptProtectData
и CryptUnprotectData. Эти функции реализованы в crypt32.dll и могут вы-
зываться из приложений .NET Framework через P/Invoke. DPAPI являет-
ся частью операционной системы и доступен в Windows 2000 и выше.
DPAPI — в отличие от функций LSA — не работает с хранилищами дан-
ных, но способен создавать индивидуальные для машины или пользовате-
ля ключи для шифрования и расшифровки данных. Чтобы различать два
типа ключей, в документации DPAPI их называют хранилищем машины
(machine store) и хранилищем пользователя (user store).
*• Andkitno
ConsoleAp()ication1
Iprivate static void i(string[] )
ComoleApplcalionl .exe string localQj
В i*S> Type References string local!;
SqlConnection local 2;
.ctoi[); void
localO = l.lC"3L"lL.
local! = 1.1 (||~
£* niSqComection); void local 2 i nul ,
string, siring]: SqIConneclion
Ioca12 > i-iClocalO, locall);
loca!2.Close();
References
*r!
Рис. 7. Декомпиляция затемненных сборок
«на лету». Еще можно предложить рассматривать сборку так же, как храни-
лище данных, т. е. применять соответствующие ACL. И прибегайте к этому
варианту лишь в качестве крайней меры, когда никакая другая технология
защиты данных неприменима и единственной альтернативой остается хра-
нение секретных данных в незашифрованном виде.
Изолированное хранилище
Иногда изолированное хранилище упоминается как метод защиты данных.
Оно позволяет ограничить доступ к данным сборки приложения. Хотя та-
кой вариант может быть полезен, изолированное хранилище не рекоменду-
ется для защиты секретных данных, поскольку в нем не используется шиф-
рование; оно лучше подходит для хранения индивидуальных пользователь-
ских параметров приложения. Для хранения секретных пользовательских
данных в приложении используйте DPAPI совместно с изолированным хра-
нилищем.
Заключение
Когда речь идет о защите секретных данных в приложении, идеальных ре-
шений нет. Ни одна из существующих программных технологий не гаран-
тирует абсолютной защиты. Задача в том, чтобы выбрать лучший, или
«наименее плохой*, вариант, приемлемый для вашего приложения и соот-
ветствующий вашим требованиям к защите. Понимание способов защиты
данных различными способами и технологиями поможет вам оценить уяз-
вимости и не позволит стать жертвой чувства ложной защищенности.
Решив купить готовое или создать собственное решение для защиты дан-
ных, убедитесь, что оно опирается на стойкое шифрование, обеспечивает
удовлетворительную защиту кршпгографических ключей и ограничивает
доступ к зашифрованным данным. Хотя ни одно программное решение не
сделает данные вашего приложения абсолютно защищенными, верный
подход поможет устранить наиболее распространенные бреши в защите.
Знание типичных
механизмов вирусных
атак поможет лучше
защитить приложения*
Готовимся к бою
Как в принципе работают вирусы? Ну, во-первых, его создателю нужно
написать исполняемый код для активизации вируса. Чего хочет автор от
своего вируса? Должен ли он форматировать ваш винчестер? Удалять
JPG-файлы? Отправлять по почте свои копии вашим друзьям и колле-
гам? Для всего этого потребуется некий исполняемый код. А чтобы за-
пустить этот код, нужно активизировать вирус. Обычно исполняемый
код вируса запускается напрямую: некий беспечный пользователь полу-
чает по электронной почте письмо с вложенным файлом типа «Дважды
щелкни здесь и будет тебе счастье.ехе» или с чем-то столь же притяга-
тельным. Он запускает программу, и вирус срывается с цепи.
Так что любые другие типы файлов, для которых операция open содержит
параметр %1, могут представлять угрозу. Таких типов уйма, и все они по-
тенциально опасны. Создателю вируса известно, что многие не станут два-
жды щелкать файлы с расширением .ехе и скорее всего не будут запускать
ВАТ-файлы, но не запустят ли они CMD-файл? А как насчет расширений
.com, .pif или .vbs? Операция open для всех этих типов файлов содержит
параметр %1. Создатель вируса может просто заменить расширение фай-
ла с исполняемым кодом вируса с «.ехе» на, скажем, «.com», и тем самым
254 Защита кода и данных
rundll32.exe
shell32.dll,OpenAs_RunDLL
c:\winnt\win.ini
Функция OpenAs_RunDLL из SHELL32.DLL принимает один параметр —
имя файла. При вызове она отображает диалог Open With (рис. 1). Выбрав
в нем имя файла и щелкнув кнопку ОК, можно открыть этот файл в соот-
ветствующем приложении, которому имя файла передается в виде пара-
метра командной строки. И примеров таких вызовов в системном реест-
ре — масса. Возможно, вы захотите взглянуть на некоторые из них, чтобы
лучше понять их работу и предоставляемые ими системные функции. Для
этого просто выполните в реестре поиск по RUNDLL32.
win.lnj - War dP ad
Fia fflit View Jnsert Fori
JEW!
"iegiyaed m types.
;-..-, | i Щ i n , .
McrasofUetQLEDDAO
JPEG Image
~^'E/ ;
«fjPEG JPEG Image
JPEG Image
JSc<ip^cnp|fte
[1]JSE JScipl Sciipt Fie .1
41
ISbSKie ;- l^j°'|3Script5criptFile
R ЕС-файлы
Как вы, наверное, знаете, файлы с расширением .reg — это системные ре-
гистрационные файлы (system registration files) с информацией, которая
9-138
25S Защита кода и данных
в •
Узел ЕХЕ — лишь одно из многих мест в системном реестре, где можно
найти опасные изменения. Два других — разделы HKLM\SOFTWARE\
Microsoft\Windows\CurrentVersion\Run и RunOnce. REG-файл или ис-
полняемый файл вируса могут добавить в любой из этих разделов пара-
метры, содержащие путь и имя файла любого приложения, которое долж-
но быть запущено при загрузке системы. Эти параметры не отражаются в
группе Startup меню Start, и, если вы не знакомы с данным разделом рее-
стра, обнаружить их трудно. Разделы Run и RunOnce есть и в кусте реест-
ра HKEY_CURRENT_USER. Борясь с вирусом, проверьте их оба.
Уязвимость PATH
Еще одна опасность таится в переменной окружения PATH. Как вы знае-
те, все самые длинные и часто используемые пути можно перечислить в
переменной PATH, чтобы не набирать их каждый раз. Например, если вы
внесете в переменную PATH путь d:\Program Files\Microsoft Visual Stu-
dio\vb98\, то для запуска Visual Basic 6.0 из командной строки достаточ-
но набрать «vb6». В системном реестре есть масса ссылок на исполняемые
файлы, которые тоже пользуются этим преимуществом. Проблема в том,
что применение этой на первый взгляд безобидной возможности весьма
рискованно. Рассмотрим следующий сценарий.
Так что причиной отсутствия пути в этом параметре реестра может быть
только лень. Вновь оторвитесь от чтения и проверьте реестр: если путь не
указан, немедленно исправьте это, как показано на рис. 3. (Учтите, что
такое изменение может нарушить работу некоторых программ установ-
ки, некорректно обращающихся с данным параметром.) Кроме того, на-
чинайте избавляться от привычки слишком сильно полагаться на пере-
менную PATH. Убедитесь также, что вирус не добавил к ней другие ка-
талоги, которым там нечего делать. Вирусы нередко делают именно так,
но при должной бдительности этого легко избежать. Помните, что любой
компьютер в вашей сети может быть заражен (любыми традиционными
способами, из которых самым распространенным является запуск инфи-
Знание типичных механизмов вирусных атак 261
В куче фрагментов
Последнее, о чем я расскажу, — об объекте фрагмента документа (scrap
object). Существует два типа соответствующих файлов (рис. 4). Оба типа
очень опасны, поскольку могут инкапсулировать исполняемый код в
составном документе OLE (compound OLE document). Чтобы понять ме-
ханизм их работы, в свободное время изучите параметры реестра, управ-
ляющие операциями open для этих файлов. Создать исполняемый код для
таких фрагментов несложно (см, статьи на смежную тематику, перечислен-
ные в аннотации).
IGS 'SHB'
Мало того, что эти файлы могут содержать исполняемый код, есть еще две
причины, делающие их очень опасными. Во-первых, они часто пропуска-
ются антивирусным ПО. Даже если один из типов включается в список ис-
полняемых файлов, второй часто игнорируется. Убедитесь, что ваши анти-
вирусные программы проверяют файлы обоих типов.
262 Защита кода н данных
Module Verify&ce
Return SB.ToString
End Function
Bis Я As Registry
Dim RegKey As RegistryKey - R.LocalMachine.OpenSubKey< _
RegPath, True)
If RegKey Is Nothing Then
' flp» первом запуске программы этого раздела нет,
1
так что придется создать его
йедКеу *= R.LoealHaehine.CreateSubKeyCRegPatn)
End If
Else
' Если 8 командной строке не переданы никакие параметры,
' сообщаем об ошибке к выходим. Или же можно использовать
' этот путь для установки корректных параметров
' в Shell\Gpen\Command!
Ms9Box("This application requires that the filename " & _
"and path to an" & vbCrLf & _
"executable program be passed " & _
"as a eoffiBand-line argument", _
HsgBoxStyle.ExclaBatiott Or MsgSoxStyLe.OKOnly, w
"Argument Required")
End If
End Sub
End Module
Ш SOFTWARE
Ш 23 АТ7 Те.
DesFipton
G«s
LSH
35 В! 05*1 Ь5 as 13 as -43 d7 ck e? ^ сЗ et S7
5* 2i * 03 И 65 Ж 3S 7s rf Л Оз Оста dc df
. » 58 7rf td 0* c5 5f Й fc 55 72 fO d7 5с и Й
_J £• ^gram Groups . 10 Sf =b 9c *s e8 ji 1 i» ей Те ft eS Id 8112 C3
V _J WVstiK? 3 1
'. . ,ertf|€<e
Рис. 6. MDS-хэш
Я знаю, о чем вы сейчас думаете. А если вирус учтет такой способ контроля
и удалит из реестра необходимые параметры до инфицирования приложе-
ния? Тогда при следующем запуске приложение сможет выполняться и рас-
пространять вирус. Или же вирус просто удалит сам файл VerifyExe.exe?
Все это возможно, но горькая правда в том, что здесь ничего не поделаешь.
Что бы вы ни делали, вирус всегда может обойти вашу оборону. Конечно, вы
можете изменить исходный код утилиты и размещать хэш в другом разделе
реестра, INI-файле или любом другом месте. Вероятно, тогда вирусам будет
труднее избежать обнаружения, однако любое эффективное решение рано
или поздно само станет мишенью для вирусов. Именно поэтому, как я уже
Знание типичных механизмов вирусных атак 267
Заключение
Чтобы обезвреживать вирусы, надо знать, как они работают. По мере
усложнения вирусы становятся все более агрессивными по отношению к
антивирусному ПО. Если с вами такого еще не случалось, будьте уверены,
рано или поздно вам придется бороться с вирусом самостоятельно. Пом-
ните, что лучшая оборона — нападение. Из этой статьи вы узнали, как кон-
тролировать содержимое исполняемых файлов в своей системе, так что
сможете всегда быть готовы к атаке вирусов. Сочетание подобных мер со
свежими антивирусными программами и знанием соответствующих разде-
лов реестра не позволит создателям вирусов перехитрить вас.
Шаблоны
Архитектура
автономного приложения
Защищенные шлюзы
В какой-то мере приложение, ориентированное на сервисы, безопасно про-
сто по своей природе: единственный способ заставить его выполнить one-
Архитектура автономного приложения 271
Архитектурный шаблон
Очевидно, что автономия — это архитектурный шаблон (architecture pat-
tern). Как и в случае других шаблонов, вашим коллегам должно быть по-
нятно, о чем речь, если вы, будучи архитектором ПО, скажете им: «по-мо-
ему, следует проектировать это приложение как автономию». В этом и со-
стоит одно из преимуществ шаблонов: они помогают обсуждать вопросы,
связанные с архитектурой и проектированием, на более высоком уровне
абстракции, не вдаваясь в ненужные на данном этапе детали.
Эмиссары
Ряд автономий поддерживает UI для предоставляемых ими сервисов.
В таких автономиях может применяться один из шаблонов эмиссаров
(emissary patterns) — эмиссар на основе либо Web Forms, либо Win-
dows Forms. Эмиссар действует подобно торговому агенту или торговцу
недвижимостью и предоставляет пользователю образец данных, позво-
ляя выбрать один из вариантов. Эмиссар также в курсе большинства
принятых в автономии бизнес-правил и может помочь пользователю со-
ставить запрос так, что он с большей вероятностью будет выполнен ав-
тономией.
Эмиссары также способны сохранять состояние пользовательского сеанса.
Типичный пример — Web-форма ASP.NET, которая сохраняет содержимое
корзины покупателя между запросами и тем самым позволяет добавлять
в корзину новые товары и хранить уже добавленные, пока не придет вре-
мя оформления заказа.
Однако автономия не доверяет эмиссару, даже если формально он являет-
ся ее частью. Любой запрос, поступающий через него, проверяется на
предмет безопасности, полноты и корректности заполнения не менее тща-
тельно, чем запросы, поступающие по другим каналам. В этом случае ав-
тономия ведет себя подобно страховой компании, которая проверяет заяв-
ление на выплату страховки, даже если оно подано через агента, оформив-
шего эту страховку. Это разумно, так как эмиссар действует скорее в
интересах клиента, чем автономии.
Как же распределяются обязанности между автономией и ее эмиссарами?
Автономия имеет дело с разделяемыми (общими) данными (shared data).
Это означает, что операции записи должны быть упорядоченными, чтобы
не нарушить целостность данных. Эмиссары, напротив, работают с локаль-
ными копиями эталонных данных только для чтения (образцами данных),
а также с информацией, индивидуальной для каждого пользователя. То
есть эмиссары могут игнорировать проблему параллельного доступа к дан-
ным. Как правило, эмиссары поочередно обслуживают клиентов в демили-
таризованной зоне, тогда как автономия обычно размещается в защищен-
ной интрасети и должна быть всегда доступна клиентам.
Web-фермы обеспечивают едва ли не безграничное масштабирование эмис-
саров. Масштабировать автономию много сложнее, так как ей приходится
обрабатывать разделяемые данные, которые должны быть доступны всем.
Поэтому, переложив больше работы на эмиссаров и тем самым разгрузив
автономию, вы заметно повысите масштабируемость приложения. Вспом-
ним Amazon.com. Навигация по сайту, добавление книг и других товаров
Архитектура автономного приложения 273
Y
ЯасеОауТаЫе
RaceDayld:lnteger
Date: Date
Rac6TrackName:String
City Name: String
Country Name; String
Cityjd City id
TrackName CilyName
CountryCode CountryCode
CountryName
Классы сущностей
Теперь посмотрим, как разработчики, желающие скрыть от клиента струк-
туру базы данных, проектировали бы свои объекты. Все шансы за то, что
они прибегнут к одному из популярных шаблонов для проектирования
объектов с поддержкой состояний. Он построен на моделировании про-
блемной области (domain model). Естественно, эта модель представляет
объекты реального мира. В нашем случае это лошади, тренеры, жокеи и
скачки.
RacingPrograms RaceTracks
RacingProgram RaceTrack
i 1
Date TrackName CWyKame CountryName
XML-наборы данных
никогда не подключаются к базам данных
Возможно, не все еще знают, что XML-набор данных (Dataset) никогда не
подключается к базе данных — он просто не может этого. Для передачи
данных между XML-набором данных и базой данных нужен какой-нибудь
прокси, сопоставляющий таблицы набора данных с реляционными табли-
цами. Такой объект предоставляет ADO.NET, причем в нескольких верси-
ях, ориентированных на разные СУБД. Называется он адаптером данных
(data adapter) и применяется только для обмена информацией между ис-
точниками и наборами данных. Сам Dataset не имеет ни малейшего пред-
ставления ни о базе данных, ни об операторах SQL, заполняющих его или
передающих данные в источник.
Заключение
Принимаясь за новый проект, подумайте о том, чтобы спроектировать
приложение как автономию. Если у него будет UI, как и у большинства
других приложений, попробуйте реализовать его в виде набора эмисса-
ров, переложив на них как можно больше работы. Эмиссары должны об-
ращаться к автономии только при крайней необходимости. Например,
они должны самостоятельно кэшировать эталонные данные (образцы
данных) и поддерживать состояние сеансов. Такие приложения масшта-
бируются лучше, чем приложения, постоянно работающие с серверными
ресурсами, например с разделяемыми данными.
Защищенный вход
Средства безопасной
аутентификации через
Microsoft .NET Passport
Поддержка Security Key введена в .NET Passport версии 2.0 для сайтов,
требования которых к безопасности выше, чем уровень защиты, обеспечи-
ваемый существующими способами входа через безопасные каналы. Secu-
rity Key включает всю функциональность Secure Channel и ряд дополни-
тельных средств.
284 Защита кода и данных
Словарь терминов
Здесь поясняется часть терминов, встречающихся в этой статье; тол-
кование остальных терминов можно найти в справочном файле
Passport SDK,
Доменные центр (domain authority) — юридическое лицо, которому
принадлежат домены, используемые для выдачи и обслуживания
учетных записей .NET Passport (например, Hotmail).
Сайт-участник (participatiog site) — любой Web-сайт, на котором
реализован единый вход .NET Passport. Заметьте, что для работы с
большинством функций .NET Passport и для доступа к базовым про-
филям пользователей сайт-участник должен быть зарегистрирован.
Для регистрации необходимо предоставить URL сайта, контактную
информацию, политику конфиденциальности и т. д. Это также озна-
чает, что Microsoft будет периодически проводить аудит вашего сай-
та на соответствие стандартам Passport.
PUID (Passport Unique Identifier) — комбинация двух атрибутов
.NET Passport: MemberlDHigh и MemberlDLow. Результирующее
64-разрядное значение образует PUID, который узлы-участники
должны использовать для индексирования своих баз данных и уни-
кальной идентификации пользователей,
Защищенный вход (secure sign-in) — функциональность .NET Pass-
port версии 2.0 (и выше). Расширяет возможности стандартного
входа и за счет дополнительных средств заметно уменьшает вероят-
ность входа хакеров по учетной записи, взломанной атакой с повто-
рением пакетов или по словарю. Существует два уровня защищен-
ного входа: Secure Channel и Security Key.
Вход (sign-in) — процесс входа в .NET Passport с предоставлением
регистрационного имени и пароля при обращении через браузер на
сервер входа,
bValue = PassportManager.IsAuthenticated(
[TimeWindow], [ForceLogin], [SecureLevel])
sValue = PassportManager.AuthURL2([returnURL],
[TimeWindow], [ForceLogin], [coBrandArgs],
[lang_id], [NameSpace], [KPP], [SecureLevel])
sValue = PassportManager;LogoTag2([returnURL],
[TimeWindow], [ForceLogin], [coBrandArgs],
[lang_id], [bSecure], [NameSpace], [KPP], [SecureLevel])
Значение Допустимый
Имя Тип данных по умолчанию интервал Описание
Значение Допустимый
Имя Тип данных по умолчанию интервал Описание
10-138
290 Защита иода и данных
Значение Описание
Разработка на ASP
Теперь сравним простейшие ASP-страницы, реализующие стандартный и
защищенный вход. Все, что они делают, — показывают кнопку Sign-in; по-
сле аутентификации пользователя через Passport эта кнопка меняется на
Sign-out.
1
Я перенаправляю пользователя обратно на эту страницу,
' а вы можете перенаправлять его на любу» другую
redirectURL * Server.URLEneo3e("http:/7" & _
Request.ServerVarlabIes("SSlVER_HAKE") i _
Request.SefverVariables("SCRIPT_HAHE"))
strtogoTag * passportManager.togoTatj2(redirectURt)
Sesponse.W rite(st rLogoTag)
Dl» passportManager
Diffi strLogoTag ' a этой строк» будет храниться HTHt-код
' кнопки Sign-in, сгенерированный Passport
Dim redirectURL ' URL, на который перенаправляет сервер входа
Bim TieeMlindow ' интв^яал, в течение которого действителен
* последний вход пользователя
см. след. стр.
292 Защита кода и данных
TimeWindow - 10000
ForceLogin = false
bSecure = True ' передача изображения по HTTPS
SecureLevel = TOO ' защищенный вход G вводом PIN
Разработка на ASP.NET
А теперь посмотрите, как реализовать защищенный вход в ASP.NET на
основе .NET Framework. Код на рис. 3 почти не отличается от такового для
защищенного входа с применением объекта Passport Manager. К немногим
отличиям относятся директива для импорта пространства имен Sys-
tem. Web.Security и модифицированное объявление переменной passport-
Manager: вместо инициализации passportManager вызовом CreateObject,
теперь вызывается New Passportldentity. Наконец, вы должны указать
Средства безопасной аутентификации через Microsoft .NET Passport 293
параметры для функции входа, чтобы .NET мог корректно определить, ка-
кую из перегруженных функций следует использовать.
TieeWindow * 1QOOO
ForceLogln ~ False
bSecure = True ' передача изображения по HTTPS
SecureLevel = 100 " защищенный вход с вводов РШ