WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 10 |

«Michael Howard David LeBlank WRITING SECURE CODE Second Edition Press Майкл Ховард Дэвид Лебланк ЗАЩИЩЕННЫЙ код 2-е издание, исправленное Москва 2004 УДК 004.45 ББК 32.973.26-018.2 Х68 ...»

-- [ Страница 4 ] --

Опасность здесь в что обработчик заданий IPP реализован в виде Pi расширения (Internet Server Application Programming Interface), работающего под учетной записью системы (SYSTEM). этой бреши в фрагменте выпущенного Microsoft бюллетеня по безопасности soft.com/technet/security/bulletin/MSO 180 Часть II Методы безопасного кодирования в защите возникает из-за того, что со неконтролируемый буфер в коде обработки входных параметров. Это позволяет атаковать удаленно, вызывая переполнение буфера, и на сервере ный код, который выполняется в контексте безопасности темы. Таким образом, злоумышленник получает полный над сервером, Если бы протокол 1РР в Windows 2000 не работал под учетной записью SYSTEM, изуродованных было бы меньше. Ведь системная учетная запись доставляет полный доступ к компьютеру, в том числе полномочия по созданию Web-страниц.

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

Запомните эту рекомендацию! Прежде чем рассказать как снизить при вилегии, необходимые мы познакомим вас с управлением доступом и привилегиями в Windows.

Краткий экскурс в управление доступом Защита ресурсов от неавторизованных пользователей в Microsoft Windows NT/2000/ ХР и Windows Server 2003 организована с помощью разграничения доступа:

для этого применяются избирательные таблицы управления доступом (Discre tionary Control List, (обычно название сокращается до ACL ) состоят из записей управления доступом (Access Control Entry, АСЕ). Каждая АСЕ содержит идентификатор безопасности (Security ID, SID) участника безо пасности (principal), которым может быть пользователь, группа или компьютер, информацию о нем и которые он может выполнять с объектом. На пример, одним участникам безопасности можно предоставить доступ на а другим — полный доступ к объекту, защищенному с помощью Более об ACL рассказано в главе 6.

Коротко о привилегиях Учетные записи пользователей Windows обладают привилегиями, иначе — вами, которые позволяют или запрещают выполнять определенные (привилеги рованные) действия над всей системой, а не над объектами, напри мер правом на вход в систему, отладку программ других пользователей, измене He совсем верно. Списки управления доступом (ACL) к объектам Windows NT/2000/ ХР состоят из избирательной и системной (SACL) таблиц управления досту пом. Первая используется для доступа к а вторая — для управления аудитом. — ГЛАВА 7 Принцип минимальных привилегий ние системного времени и т. п. Некоторые исключительно привилегии (те, что позволяют выполнять важные и небезопасные перечислены в табл.

Таблица 7-1. Наиболее важные привилегии Windows Системное название Название константы Отображаемое название значение) (Winnt.h) Backup Files And (16) (Архивирование файлов и каталогов) Restore And Directories (17) (Восстановление и Act As Part Of The Operating (6) System (Работа в режиме системы) Debug Programs (Отладка программ) Replace A Process Token (Замена Privilege (2) NAME уровня процесса) Load And Unload Device (9) SE LOAD DRIVER Drivers (Загрузка и выгрузка драйверов устройств) Take Ownership Of Files Or (8) Other файлами или иными объектами) Имейте в что область действия этих привилегий ограничена локальной системой, но ее можно расширить на весь домен, назначив соответствующие груп повые политики. Привилегии одного пользователя на двух разных компьютерах иногда сильно отличаются. Настройка локальной политики позволяет вить привилегии только на данном компьютере, но никак не на других компью терах в сети.

Познакомимся детально с каждой из перечисленных привилегий.

Привилегия Учетной записи с привилегией Backup files and directories доступно чтение лов, прямого доступа к которым у нее нет. Так, если пользователю Blake нужно сделать резервную копию файла, он сможет считать файл, несмотря на то, что файла явно запрещает ему доступ обычными средствами. Программа резервного копирования читает файлы, вызывая функцию с флагом В этом легко убедиться, выполнив следующие операции, 1. Войдите в систему под учетной записью с привилегией, разрешающей вирование файлов и каталогов, например под учетной записью локального администратора или оператора архива, 2. Создайте небольшой текстовый файл Test.txt с произвольным содержимым.

Часть II Методы безопасного кодирования 3. Средством редактирования ACL добавьте в файл запись АСЕ, явно запрещаю щую вам доступ. К примеру, если имя учетной записи Blake, добавьте такую АСЕ:

Blake (Deny All).

4. Скомпилируйте и запустите на исполнение указанный ниже код. Подробнее о связанных с безопасностью, вы найдете в библиотеке MSDN или в ресурсах Platform SDK Л */ int { HANDLE = 0;

if { с ошибкой -> -1;

if (NULL, { завершилась с ошибкой CloseHandle return -1;

I = SE_PRIVILEGE_ENABLED;

= 1;

if FALSE,,' 0, NULL, { завершилась с ошибкой GetLastErrorO);

(hToken);

return -1;

if (GetLastErrorO == ERROR_NOT_ALL_ASSIGNED) выполнена успешно, но не все привилегии заданы CloseHandle (hToken);

return 0;

ГЛАВА 7 Принцип минимальных привилегий void DWORD считать Xs с флагами OxXx \ HANDLE = GENERIC_READ, FILE_SHARE_READ, NULL, dwFlags, NULL);

if (hFile == { завершилась с ошибкой -> Xd return;

DWORD cbBuff = sizeof buff;

sizeof buff);

if (ReadFile(hFile, buff, cbBuff, { считано Xd байт\п\пТекст:

cbRead, buff);

else { завершилась с ошибкой - > GetLastErrorO);

I CloseHandle(hFile);

void argc, { if < 2) { Xs return;

// Сперва привилегию файлов и каталогов.

If == -1) return;

// Пытаемся установленного флага архивирования - доступ отсутсвует, // Пытаемся установить флаг - должно | Этот пример кода вы найдете среди других примеров в папке При работе программа должна вывести в отладочном окне следующее:

Часть II Методы безопасного кодирования Пытаемся считать с флагами 0x80.

Функция завершилась с ошибкой -> Пытаемся считать Test.txt с флагами 0x2000080 flags Успех, считано 15 байт.

Текст: Hello, Как первый вызов завершился с ошибкой запрета доступа (ошибка с номером 5), а второй так как мы добавили привилегию, разре шающую архивирование, и установили флаг При работе с я использовал дополнительный код. Однако, если у пользователя уже есть привилегии и допол нительно ничего делать не придется. Воспользовавшись он сможет прочитать любой файл, для этого следует сделать резервную копию в обход ACL, а затем восстановить файл в месте, где у него прав больше.

Предоставление привилегии SeBackupPrivilege ставит под удар Ведь никак не удастся проверить, с какой целью пользователь копирует делает резервную копию или просто ворует их;

поэтому наделяйте этой приви легией только пользователей, которым доверяете.

Привилегия SeRestorePrivilege Несложно догадаться, что она противоположна привилегии резервного копиро вания. Она позволяет переписывать файлы, в том числе DLL-библиотеки и ЕХЕ к которым обычного доступа у злоумышленника нет! Кроме того, она предоставляет право поменять владельца объекта, а владелец обладает безгранич ным доступом к объекту, Привилегия SeDebugPrivilege У учетной записи с привилегией Debug Programs есть право подсоединяться к любому процессу, а также просматривать и изменять содержимое принадлежащей ему памяти. Обладая этой привилегией и достаточными знаниями, любой пользо ватель сможет подключить к процессу отладчика и получить доступ к секретным данным программы. Опасность этой привилегии отлично описана в главе В частности, злоумышленник с такой привилегией запросто получит закрытый ключ сеанса «перелопатив» память процесса специальными инструментальными средствами, предоставляемыми компанией Кроме того, функции пользователю с привилегией Debug Programs удастся завершить любой процесс в системе. Иначе такой, обычный в других отношениях, может запросто «уронить* один из ключевых системных процессов, например Lsass.exe, диспет чер локальной безопасности (Local Security Authority, LSA).

И это только цветочки!

Самая пакостная заключается в том, что функция позволяет злоумышленнику с привилегий отладки программ запускать на исполнение код в существующих процессах. Именно так работает хакерский ин струмент LSADUMP2 уполномоченный пользова тель получает возможность просматривать секретные данные LSA. Для этого в ГЛАВА 7 Принцип минимальных привилегий процесс Lsass.exe внедряется новый поток с кодом, который считывает закрытые данные, уже заботливо расшифрованные диспетчером локальной безопасности, Подробно о секретах LSA рассказано в главе Отличный источник информации о внедрении кода в потоки программ — книга Джеффри Рихтера (Jeffrey Richter) Applications for Microsoft (Microsoft Press) (Рихтер Windows для профессионалов: Создание ных с учетом специфики 64-разрядной версии Windows. СПб.:

М.: 2001).

Примечание Вопреки сложившемуся мнению, учетная запись нуждается в при вилегии Debug Programs только для отладки процессов, принадлежащих другим учетным записям. Для отладки собственных процессов таких прав не нужно. Так, пользователю Blake не нужна привилегия для отладки лю бого из своих приложений, но она понадобится для отладки процессов, принадлежащих Cheryl.

Привилегия Учетную запись с привилегией Act as part of the operating system [ее также часто Trusted Computing Base (ТСВ)] можно рассматривать как высоконадеж ный системный компонент. Она предоставляет максимум полномочий и поэтому считается самой опасной в Windows. Вот почему по умолчанию эта привилегия предоставляется только учетной записи SYSTEM.

Внимание! Не следует предоставлять привилегию ТСВ, если нет очень серь езных на то оснований. прочитав эту главу, вы поймете, что обойтись без нее, Примечание Чаще всего необходимость предоставления привилегии ТСВ обус ловлена необходимостью вызова функций типа которые без нее не работают. Но, начиная с Windows XP, при вызове LogonUser из приложения для входа под пользовательской учетной записью Windows эта привилегия больше не требуется. Тем не менее она нужна при входе под учетной записью Passport или когда параметр не равен NULL, Привилегии и Учетная запись с привилегиями Replace A Process Level Token и Increase Quot позволяет получить доступ к маркеру процесса другого пользователя и создать от его имени новый процесс — так называемые атаки с подменой источника (spoofing) или с целью повышения полномочий.

Привилегия Исполняемый код ядра считается очень надежным и пользуется практически не ограниченным доверием, поэтому ему доступны любые операции. Для загрузки 1 86 Часть II Методы безопасного кода в ядро обязательна привилегия так как загруженный код может выполнять множество потенциально опасных действий. Предоставлять эту привилегию рядовому пользователю поэтому по умолчанию ею облада ют только администраторы.

Замечу, что для загрузки драйверов самонастройки (Plug and Play) эта приви легия не нужна — их загружает системная служба Plug and Play.

Привилегия Ее действие очевидно — она позволяет удаленно завершать работу компьютера, Заметьте: как и в остальных случаях, пользователь должен обладать привилегией на целевом компьютере. А теперь представьте себе, сколько радости вы достави те злоумышленнику, предоставив эту привилегию группе Everyone (Все) на всех компьютерах сети! Никакая распределенная DoS-атака (Denial of Service) не сможет создать такой кавардак!

Привилегия В Windows существует понятие владелец объекта (owner). Это лицо (или объект), пользующееся полной и нераздельной властью над всеми объекта которыми владеет. Обладателю этой привилегии ничего не стоит объект у «законного» владельца, таким образом получив неограниченный доступ к любому объекту системы.

Примечание Примечательно, что до Windows XP владельцем объекта, создан ного администратором системы, назначалась группа локальных нистраторов. В Windows XP и более поздних версиях, включая Windows Server 2003, это не обязательно — владельцем может быть как ло кальная группа Administrators так и сам создатель объекта, Примечание Bypass Traverse Checking (Обход перекрестной проверки), или — единственная привилегия, необходимая всем учетным записям пользователей. Она требуется для получения инфор мации об изменениях файлов и каталогов. Впрочем, главное преимуще ство этой привилегии по умолчанию в том, что она позволяет избежать процедуры проверки на пути к определенному объекту в любой файловой системе Windows или реестре. Привилегия применяется при оптимизации файловой системы NTFS, Несколько слов о маркерах После входа в систему Windows NT/2000/XP и успешной аутентификации пользо вателю назначается специально созданная структура маркер (token), который прикрепляется ко всем запускаемым пользователем процессам и пото кам. Кроме прочего маркер содержит SID пользователя, всех групп, членом которых является пользователь, и список его привилегий. В дей ГЛАВА 7 Принцип минимальных привилегий именно маркер определяет, какие операции на компьютере до ступны пользователю. Как при входе с консоли, так и при удаленном входе в си стему маркер создается только после успешной аутентификации. Любая тировка параметров учетной записи (например, изменение членства в группах или смена привилегий) вступает в силу только после следующего входа в систему.

Начиная с Windows 2000, маркер может содержать информацию обо всех ленных или отключенных SID и привилегиях. Такой маркер называется маркером (restricted token). Как они применяются в приложениях, я рас скажу чуть попозже.

Как взаимодействуют маркеры, SID, ACL и процессы Все процессы Windows NT/2000/XP выполняются в определенном кон тексте безопасности, иначе говоря, маркер закреплен за процессом. Выполняемый процесс обычно отождествляется с запустившим его Однако ватель с достаточными привилегиями вправе запускать приложения от других пользователей, вызвав функцию Как процесс.

обращающийся к CreateProcessAsUser, должен обладать привилегиями и Впрочем, если маркер, функции в качестве первого аргумента, — ограниченная версия основного кера пользователя, то привилегия не нужна.

Процесс другого типа — служба — работает в контексте деляемом в диспетчере служебных программ (Service Control Manager, SCM). Боль шинство служб по умолчанию исполняются как Local System, но можно строить службу на работу под другой учетной указав имя и пароль в (рис. 7-1).

• Enabled Рис. 7-1. службы работы под заданной учетной Примечание Пароли для запуска служб хранятся как секреты LSA. Подробнее с секретными данными LSA мы познакомим вас в главе 9.

Часть II Методы безопасного кодирования За процессом закрепляется маркер учетной записи, который обладает инфор мацией обо всех свойствах и привилегиях пользователя, поэтому процесс иног да можно считать представителем» учетной записи — все, что раз решено учетной записи, разрешено и процессу. Это справедливо только при усло вии, что полномочия маркера не урезаются применением ограничивающего мар кера, который представляет собой версию исходного маркера.

Идентификаторы SID и управление доступом, а также привилегии и их проверка Маркер содержит SID и привилегии. Первые служат для управления доступом к ресурсам на основе а вторые — для выполнения общесистемных операций.

Часто на мой вопрос о том, зачем процессу требуются высокие привилегии, его разработчики отвечают, что программе нужно считывать и изменять записи рее стра. Лишь часть из них в полной мере понимает, что при этом выполняется про верка доступа, а не привилегий. Зачем же давать приложению все эти опасные привилегии? Иногда я слышу такие доводы: «Для работы нашей программы архи нужны административные Но для архивирования фай лов требуется привилегия, а не SID члена группы администраторов.

Если вы не до конца уяснили смысл сказанного, прочитайте раздел еще раз.

Чрезвычайно важно, чтобы вы разобрались в том, как связаны и чем отличаются SID и привилегии.

Три аргумента в пользу назначения приложению высоких привилегий В последние годы мне пришлось потратить массу времени, чтобы выяснить, на что приложениям, не являющимся инструментами администрирования, могут понадобиться административные Думаю, я разобрался, в чем и полагаю, есть три аргумента в пользу высоких привилегий:

• возникающие из-за ACL;

• проблемы, возникающие из-за привилегий;

• использование секретов LSA.

Я познакомлю вас поближе с каждой из них, а затем расскажу о способах ре шения этих проблем.

Проблемы с ACL Пусть в разделе NTFS есть папка со следующими • SYSTEM — разрешение Full Control (Полный доступ);

• Administrators (Администраторы) — разрешение Full Control (Полный доступ);

• Everyone (Все) — разрешение Read (Чтение).

Если у вас нет учетной записи, такой, как у администра тора или системного процесса, вы сможете только читать файлы этой папки — запись, удаление и другие действия вам недоступны (при попытке выполнить та кую операцию файлового ввода/вывода вы получите ошибку отказа в доступе). За отказ в доступе — это ошибка под номером 5!

ГЛАВА 7 Принцип привилегий 1 Есть одна очень распространенная проблема: приложения, записывающие данные в защищенные области файловой системы, нормально работают, только получив права администратора. Сколько известных вам игр записывают таблицу результатов в каталог Files? Я отвечу за вас: масса. И это действительно создает проблемы, так как играющий должен обладать полномочиями Во многих играх есть режим работы через а ведь при этом открываются Вот где широчайшее поле деятельности для хакеров мастей! Злоумышленнику достаточно воспользоваться переполнением буфера или другим слабым местом обработчика сокетов, чтобы запустить на компьютере иг рока свой код с правами И все! Game Over!

Открытие ресурсов в режиме доступа ALL Есть и менее очевидная проблема, связанная с ACL, — предоставление доступа к ресурсам с большими, чем требуется, разрешениями. Пусть вышеупомянутый файлу и программа открывает файл в режиме доступа Под какими учетными записями программа будет работать корректно?

администратора или SYSTEM. Режим доступа аналогичен Full Contr Я (Полный доступ). Другими этот режим позволяет открывать файл и со вершать над ним любые действия. Но что, если вашей программе требуется вы полнять только чтение файла. Нужен ли вам режим Конечно, Достаточно открыть файл в режиме и файл станет доступным любому пользователю приложения, так как в ACJ, есть запись разрешение (Чтение) для группы Everyone (Все). Такое решение сочетает практичность и зопасность: так как приложение работает и выполняет свои в режиме «только для и надежно, потому что файл нию (благодаря наличию соответствующей записи АСЕ) в режиме только для чтения и более.

Запомните: в Windows NT/2000/XP приложению либо предоставляются запр разрешения, либо же возвращается ошибка отказа в доступе. Если ложение запрашивает полный доступ, a ACL ресурса разрешает только программа не получит даже права на чтение — система возвратит ошибку в доступе.

Можно пытаться открывать объекты с максимально допустимыми правами, редавая в параметре значение однако действий поэтому без обработки ошибок здесь не обойтис ь, Проблемы с привилегиями Понятно, что учетной записи для выполнения задач типа архивирования нужны соответствующие привилегии. Но будьте осторожны: администратору не рекомендуется предоставлять учетным записям слишком много опасных приви легий, а разработчику — требовать наличия у пользователей программы множе ства ненужных привилегий. Почему — я уже объяснил выше.

Использование секретов LSA может хранить секретные данные других приложений. Для управления сек ретами LSA применяются API-функции и Часть II Методы безопасного кодирования А суть проблемы в том, что секреты LSA могут только члены группы локальных администраторов. Вот что говорится Platform SDK по поводу «Перед записью шифруются, a DACL ключа позволяет считы вать данные только создателю и По сути, эти функции LSA доступны только администраторам, и здесь-то и кроется затруднение, если нуж но создать приложение с соблюдением принципа минимальных привилегий и при этом предусмотреть сохранения секретных данных пользователя.

Решение проблем, возникающих из-за предоставления высоких привилегий Рассмотрим возможные способы разрешения ситуаций (они описаны выше), когда вроде бы необходимо запускать приложение под учетной записью с высокими привилегиями.

Решение проблемы ACL Есть три основных способа затруднительные ситуации с • открывать ресурсы в подходящем режиме доступа;

• сохранять пользовательские данные в местах, доступных пользователю для записи;

• делать ACL более «толерантными».

Во-первых, ресурсам следует назначать только те разрешения, которые действи тельно необходимы. Если необходимо прочитать раздел в реестре, требуйте до ступ только для чтения. При этом выполняются простейшие поэтому вероятность регрессионной ошибки невелика, способ: не записывайте пользовательские данные в защищенные системные папки ОС, к которым ветвь реестра каталоги Files (или другой каталог, на который указывает переменная окружения и Храните пользователь скую информацию в ветви а файлы пользователей — в каталоге профиля. Для определения каталога профиля пользователя вставьте сле дующий фрагмент кода:

ttinclude if CSIDL_PERSONAL NULL, 0, { HANDLE =..,);

I Если в текущей версии приложения пользовательские данные хранятся в мес те, доступном только а в новой версии надо поменять их мес тоположение, чтобы полномочия администратора не требовались для записи информации, позаботьтесь о переносе данных из старых версий в новую. В про тивном случае возникнет обратная несовместимость: пользователям не удастся получить доступ к записанным в предыдущей версии данным.

ГЛАВА 7 Принцип минимальных привилегий 1 Ну и наконец, вы можете немного ослабить «непримиримость» записей управ ления доступом (ACL) — это менее рискованно, чем предоставлять полномочия администратора. Понятно, что делать это нужно предельно ведь небезопасная ACL делает систему более уязвимой. Никогда не решайте > блем с привилегиями за счет создания проблем с авторизацией.

Решение проблем с привилегиями Как уже говорилось, если для выполнения задачи действительно требуется вилегия, тогда деваться некуда, ведь без нее проблему не решить. Но это вовсе не означает, что нужно раздавать привилегии направо и налево просто для того, чтобы все работало! Честно говоря, нет универсального и легкого способа избежать проблем, связанных с привилегиями.

Решение проблем с LSA В Windows 2000/ХР API защиты данных (Data Protection API, DPAP ), Его использование желательно по многим причинам, но для нас наиболее важно то, что в этом случае пользователю не требуются полномочия администратора для доступа к секретным данным, а сами данные защищены закрепленным за > вателем ключом.

Примечание Подробно сведения о использовании DPAPI — в главе 9 Определение оптимального набора привилегий Как говорилось в главе в ACL вы должны быть готовым поручиться за АСЕ. Это также касается SID и привилегий в маркере. Если приложение выполнять от имени администратора, вы должны быть уверены в каждом SID и привилегии в маркере администратора. Б противном случае лучше убрать тельные разрешительные записи.

Чтобы решить (исходя из требований конкретного приложения), включать ли те или иные SID и привилегии в маркер, рекомендуется следующая процедура.

1. Выясните, какие ресурсы нужны приложению, Создайте перечень всех системных API-функций, в 3. Выясните, какая учетная запись требуется для работы приложения.

4. Выясните, какие SID и привилегии есть в маркере доступа.

5. Решите, какие SID и привилегии необходимы для работы приложения.

6. Скорректируйте маркер в соответствии с результатами предыдущего этапа.

Этап выясните, какие ресурсы нужны приложению Прежде всего следует инвентаризовать ресурсы, необходимые для работы > жения: файлы, разделы реестра, данные Active Directory, именованные каналы и т. п., а также определить, какой уровень доступа требуется для того или иного ресурса. Например, в рассматриваемом далее иллюстративном Windows приложении ресурсы, необходимые процедурам определения привилегий, числены в табл. 7-2.

Часть II Методы безопасного кодирования Таблица 7-2. Ресурсы, используемые в приложении-примере Ресурс Требуемые права доступа Файлы с параметрами Для настройки приложения администраторам конфигурации требуется полный доступ к данным Остальным пользователям достаточно только считывать данные поступающие Каналы предоставляются всем для чтения и записи по каналам данных Каталог для хранения файлов Каждому разрешается создавать файлы и выполнять приложения любые действия со своими данными. Любому пользо вателю доступны для чтения файлы остальных пользователей Установочный каталог Всем предоставляется доступ для чтения и право программы запускать приложение. Администраторы могут обновления Этап 2: выясните, какими системными API-функциями пользуется приложение Создайте список всех функций, для работы которых необходимы привилегии (табл. 7-3).

Таблица 7-3. Функции Windows и необходимые для их работы привилегии Необходимые привилегии Название функции или членство в группе () с флагом открытие файла для архивации ~ вход в систему (в Windows XP и Windows Server 2003 больше не требуется) — модификация SeTcbPrivilege информации маркера — закрытие окна — открытие журнала безопасности — рассылка SeTcbPrivilege системного сообщения во все окна в системе и — пересылка SeTcbPrivilege сообщения на другой компьютер завершение SeShutdownPrivilege или работы ОС — приостановка работы ОС — получение информации о безопасности файла ГЛАВА 7 Принцип минимальных привилегий Таблица Необходимые привилегии Название функции или членство в группе Функции отладки том числе и — запуск процесса и обычно от имени другого пользователя — создание самодостаточного дескриптора безопасности — настройка системного времени и — закрепление памяти за процессом Функции управления сетевыми В большинстве случаев пользователь пользователями и группами, должен входить определенные группы, такие как и например или Account Operators (Операторы учета) — присоединение к домену Примечание что приложение способно Windows-фун кции через функции-оболочки (wrappers) и В нашем нет функций, которым требуются привилегии, как, и в большинстве Windows-приложений.

Этап 3: какая требуется учетная запись Опишите учетную необходимую для нормальной работы приложения.

Например, нужны ли полномочия или программа будет работать как служба под учетной записью локальной системы, нашего приложения-примера поленились и что ме нужны права администратора. Нерадивые тестировщики также работу программы только под учетной записью администратора. Да и проекта достойны осуждения: они пошли на поводу у разработчиков и щиков!

Этап 4: исследуйте содержимое маркера Теперь выясните, какие SID и привилегии содержатся в маркере учетной определенной на предыдущем этапе. Для этого или войдите в систему под учетной записью, или используйте команду для запуска нового командного процессора. для выполнения приложения от имени тора введите в командной строке:

Часть Методы кодирования При этом (если вы знаете пароль администратора) запустится новый экземп ляр командного процессора от имени администратора, и все приложения, запус каемые в нем, будут работать под администраторской учетной записью.

Если вы, будучи администратором, хотите запустить экземпляр командного процессора от имени SYSTEM, рекомендуем для запуска задачи задействовать планировщик задач — просто назначьте запуск в течение следующей минуты.

если текущее время 17:01, следующая команда запустит командный чуть меньше, чем через минуту:

At 17:02 /INTERACTIVE Созданный экземпляр командного процессора выполняется в контексте Local System.

Теперь, попав в контекст, который следует исследовать, запустите программу тестирования Она предоставляет массу ценной информации о мар кере доступа пользователя, Л // Эта определяет размер требуемой памяти // и выделяет ее. Память должна освобождаться вызывающей программой.

LPVOID HANDLE InfoClass, DWORD { InfoClass, NULL, return new ;

• // Определяем void { enf[] = {NameDisplay, for (int i=0;

i < sizeof(enf) / DWORD = if ГЛАВА 7 Принцип минимальных привилегий (format // Отображаем и ограничивающих SID.

void tic) { DWORD = 0;

*pSIDInfO = tic, if return;

if tic, pSIDInfo, dwSize, Error if (DWORD i=0;

i < i++) { DWORD = DWORD = MAX_NAME;

DWORD 0;

if NULL, { if (GetLastErrorO == ERROR_NONE_MAPPED) else Error GetLastErrorO);

} else dwAttr = IpDomain, IpName, (dwAttr ? " : " ");

delete [] (LPBYTE) pSIDInfo;

} // Отображаем сведения о привилегиях, Часть II Методы безопасного кодирования void GetPrivs(HANDLE DWORD = 0;

= if return;

BOOL bRes = TokenPrivileges, pPrivileges, if (FALSE с for i < pPrivileges char szPrivilegeName[1283;

DWORD if szPrivilegeName, szPrivilegeName, else завершилась с ошибкой delete [] (LPBYTE) pPrivileges;

int ) { if { Error GetLastErrorO);

return -1;

HANDLE hToken NULL;

if { Error GetLastErrorO);

return -1;

ГЛАВА 7 Принцип минимальных привилегий return 0;

!

Исходный текст файла в папке примерами. Программа открывает маркер потока и извлекает из него цию об имени пользователя, обычных SID и привилегиях Основную работу выполняют функции и Существует два варианта для извлечения стандартных и ограничивающих SID.

следние (их наличие не обязательно) добавляются в маркер для снижения уров ня доступа процесса или потока по отношению к доступу пользователя. Об огра ниченных маркерах я расскажу далее в этой же главе, впрочем, как и о SID с про веркой только на запрет (они отмечаются строкой Примечание Перед открытием маркера доступа потока для детального иссле дования придется позаимствовать права пользователя, но это не обяза тельно, если вызывать функцию Если вы не хотите сами разрабатывать программу анализа содержимого мар кера, используйте приложение Token Master — оно описано в книге Джеффри Рих тера и Кларка (Jason Clark) «Programming Server-Side for Microsoft Windows 2000» (Microsoft Press, 2000) (Рихтер Дж, Кларк Д, серверных приложений для Microsoft Windows 2000. СПб.:

М.: редакция», 2001) и содержится на прилагаемом к ней ком пакт-диске. Token Master позволяет вам войти в систему под выбранной учетной записью и исследовать созданный при этом операционной системой а также получить доступ к работающему процессу и просмотреть содержимое его маркера (рис. 7-2).

Поле Token Information содержит список всех SID и привилегий маркера, а также SID пользователя. Пример-приложение следует запускать от имени администра тора. Анализируя стандартный маркер администратора, MyToken.cpp выявляет следующую информацию:

Часть II Методы безопасного кодирования NT NT Users None Privileges (3) SeSecurityPrlvilege (0) (0) (0) (0) (0) (0) (0) (0) (0) (0) (0) (2) SeCreatePagefilePrivilege (0) (0) (0) Name Этап Name Logon and of computer Рис. 7-2. Результаты анализа маркера экземпляра выполняемого от имени SYSTEM ГЛАВА 7 Принцип минимальных привилегий Обратите внимание на цифры рядом с названиями привилегий — это вые маски из значений, указанных в табл. 7-4.

Атрибуты привилегий Значение Описание S1. 0x80000000 Привилегия использовалась для получения к объекту 0x00000001 Привилегия предоставлена по умолчанию ч ENABLED 0x00000002 Привилегия предоставлена Этап 5: выясните необходимость всех привилегий и Этот этап намного веселее: совместно с представителями групп проектирования, разработки и тестирования проанализируйте каждый SID и привилегию, пытаясь выяснить, без каких вы обойдетесь. Просто сравните список используемых >в и полученный на этапах 1 и 2, с на этапе 4 информацией о маркере. Если маркер содержит SID иди привилегии, в которых сти, серьезно подумайте об их удалении.

Примечание Наличие некоторых SID, таких как идентификаторы групп Users (Пользователи) и Everyone (Все), вполне обосновано. Не стоит удалять их из маркера.

Наше приложение получает доступ только на основании таблицы ACL, а однако содержит целый неиспользуемых привилегий! Если в приложении есть ошибка, позволяющая запускать на исполнение код, он получит все эти привилегии. Из перечисленных наибольшую опасность представляет привилегия отладки программ.

Этап 6: внесите изменения в маркер Последняя операция — ограничение возможностей маркера. На то есть три спо соба:

• разрешить выполнение приложения под другими, менее привилегированны учетными записями;

• использовать ограниченные маркеры (restricted tokens);

• удалить ненужные привилегии.

А теперь поговорим о каждом поподробнее, Разрешите выполнение приложения под непривилегированными учетными записями Такая операция вполне допустима, но при этом придется отключить некоторые функции программы. пользователю доступны 95% возможностей пр< > граммы, исключение составит архивирование файлов.

200 Часть II Методы безопасного кодирования Примечание Для того чтобы проверить во время выполнения программы, об ладает ли учетная запись привилегией, применяется Windows функция Если программа выполняет привилегированную операцию, например архивирование вы вправе запретить ее для непривилегированного пользователя.

Внимание! С приложением, для работы которого требуются высокие приви легии, могут возникнуть проблемы при внедрении крупных компани ях. В больших организациях очень не любят предоставлять пользовате лям какие-либо дополнительные права, помимо базовых. Это делается из соображений безопасности и снижения совокупной стоимости вла дения. Получив привилегии, пользователь может изменить части систе мы и вывести ее из а на восстановление придется затратить уси лия службы поддержки. Вывод ясен: из-за необходимости высокие привилегии в некоторых случаях клиент может отказаться от вашего приложения.

Иногда при применении принципа минимальных привилегий возможны труд ности. Если приложение плохо спроектировано и без особой необходимости тре бует высоких привилегий, то подчас единственный выход из такой ситуации — полная переделка программы.

Как-то мне попалось Web-приложение, работающее только как SYSTEM, так как — по заявлению разработчиков — один компонент программы позволял ад министратору добавлять новые учетные записи. Приложение было монолитным, поэтому не только администраторская часть, но и весь процесс приходилось за пускать от имени SYSTEM. Как выяснилось, учетные записи добавлялись доволь но редко, и после долгих дебатов разработчики решили внести изменения в сле дующую версию продукта:

• запускать приложение под специальной непривилегированной учетной записью;

• заставить приложение требовать от администраторов прохождения Windows аутентификации;

• заставить приложение олицетворять пользователя и работать с базой данных учетных записей. В этом случае при отказе в доступе выяснится, что у пользо вателя нет прав на администрирование!

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

С точки зрения безопасности, запуску приложения с минимальными приви легиями альтернативы нет. Если процесс работает как SYSTEM или под другой учет ной записью с высокими привилегиями, а созданный поток олицетворяет пользо вателя и поэтому имеет меньшие возможности, все равно запо лучит права SYSTEM. Внедрив свой код (к примеру, через переполнение буфера) и вызвав функцию он сможет отменить олицетворение и получить права то есть SYSTEM. Если же приложение всегда работает под не привилегированной учетной вызов RevertToSelf будет иметь ГЛАВА 7 Принцип привилегий фических последствий. Возьмем, к примеру, IIS 5. Web-приложения всегда запускать в процессе, отдельном от основного, [что высоко му (High) и среднему (Medium) уровням изоляции]. В этом случае приложение полняется под учетной записью Не стоит исполнять приложение с правами основного процесса IIS [соответствует низкому (Low) ню изоляции], так как последний обладает привилегиями SYSTEM. В первом слу чае возможный ущерб от переполнения буфера незначителен, так как процесс полняется под гостевой учетной записью, для которой круг доступных операций значительно ограничен. Замечу также, что в вообще нет пользовательского работающего как SYSTEM, поэтому приложение, рассчитанное на привиле гии SYSTEM потока Web-сервера, работать не сможет.

Используйте ограниченные маркеры Одна из новинок Windows 2000/XP — ограничение возможностей маркера. Огра (restricted) называется исходный маркер или маркер олицетворения, измененный с помощью функции Процесс или поток с огра ниченным маркером понижается в правах на доступ к защищаемым объектам и на выполнение привилегированных операций, кроме того, потоку доступны только локальные ресурсы. Функция позволяет выполнить одну из операций ограничения маркера:

• удалить привилегии из маркера;

• ограничивающие SID (restricting SID);

• установить в атрибут проверки на запрет attribute).

Удаление привилегий Процедура проста и прямолинейна: из маркера безвозвратно удаляются ненужные привилегии. Для их восстановления поток придется уничтожить и создать Добавление ограничивающих SID Добавляя ограничивающие идентификаторы безопасности в маркер доступа, «от ключают» ненужные SID. Когда ограниченный процесс или поток пытается полу чить доступ к защищаемому система проводит проверку обоих наборов SID — обычных и ограничивающих — и разрешает доступ, только если обе > верки завершились успешно.

А теперь пример использования ограниченных SID. Пусть ACL файла т группе Everyone (Все) чтение а группе Administrators (Администраторы) чтение, запись и удаление. Приложению удалять файлы не нужно. Возможность удаления предоставляется только специальным инструментам t которые поставляются в комплекте с приложением. Административные пол номочия предоставлены Brian, менеджеру по сбыту. Его маркер содержит тификаторы следующих групп:

• Everyone (Все);

• Authenticated Users (Прошедшие проверку);

• Administrators (Администраторы);

• Marketing.

Часть II Методы безопасного кодирования Приложение не предназначено для администрирования, поэтому необходимо добавить ограничивающий (блокирующий) идентификатор с одной записью для группы Everyone. При запуске приложения от имени рядового пользователя со здается ограниченный маркер. Когда Brian пытается удалить файл с помощью инструмента система проверяет, имеет ли он право на уда ление, просматривая первый набор SID. Ответ положительный (он входит в группу Administrators, у которой такая привилегия есть), но это еще не все. ОС просмат ривает список ограничивающих SID, находит там только SID группы Everyone и отказывает в удалении файла, так как для Everyone разрешен доступ только для чтения, Примечание Проще всего понять действие ограничивающих SID, если пред ставить, что сначала выполняется логическое умножение (AND) двух списков SID, а полученный результат служит для проверки доступа. Или же что проверка доступа осуществляется на основе пересечения двух списков SID.

Установка в SID атрибута проверки только на запрет идентификаторы безопасности (deny-only SID) применяются толь ко для запрещения доступа к защищаемому объекту. Их невозможно применить для предоставления доступа. Если в ACL ресурса Marketing имеется АСЕ-запись Deny:

Full (Запретить: Полный доступ), а в маркере содержится SID группы Marketing, то пользователь доступа не получит. Но если у другого ресурса есть АСЕ запись Marketing Allow: Read (Разрешить: Чтение), а в маркере пользователя SID группы Marketing является запрещающим, запрет распространяется только на чтение объекта.

Подозреваю, что это выглядит слишком сложно, но надеюсь, что табл. 7-5 по может вам разобраться в этом вопросе.

Таблица 7-5. Взаимодействие запрещающих SID и ACL ACL объекта ACL объекта содержит содержит объекта запись запись не содержит — «Marketing — Allow: Read» Deny: Full Control» для Маркер пользователя Доступ Доступ запрещен Доступ содержит SID группы от других АСЕ Marketing объекта Маркер пользователя Доступ запрещен Доступ запрещен Доступ содержит от других АСЕ SID Marketing объекта Заметьте: простое удаление SID из маркера — и проблема с безопасностью как именно поэтому предусмотрена возможность установки в SID атрибута проверки только на запрет. Вот вам пример. Пусть ACL ресурса запрещает доступ к ресурсу группе Marketing. Если программа удаляет SID группы Marketing из мар кера пользователя, пользователь, казалось бы, загадочным, но довольно очевид ГЛАВА 7 Принцип минимальных привилегий образом получает доступ к ресурсу! Поэтому не стоит удалять SID — превратить его в запрещающий.

Используйте маркеры Принимая решение о необходимости применения ограниченных маркеров, тывают ряд обстоятельств.

• Если программе заведомо не понадобится определенный уровень доступа, можно изменить соответствующие SID так, чтобы они работали только на Например, экранной заставке администраторский доступ вообще не нужен, так что администраторские SID стоит переделать в запрещающие. «Родные» ные заставки Windows 2000/XP работают именно так.

• Если вы точно знаете, какому минимальному набору пользователей и групп необходим доступ к ресурсу, применяйте ограниченные SID. Так, если для до ступа к рассматриваемому достаточно членства в группе Users, назначьте ограниченный SID группы Authenticated Users. Это помешает недружелюбным программам, перехватившим ограниченный маркер, получить доступ к личным данным пользователей криптографическим ключам), • Если приложение во время работы запускает на выполнение произвольный код, надежность которого заранее неизвестна, стоит использовать ограниченный маркер. Примеры таких приложений: почтовые программы (точнее, вложения) и программы обмена сообщениями (из-за возможности передачи файлов). Если приложение вызывает функции или для произволь ных файлов, настоятельно рекомендуем применять ограниченный маркер, Программа-пример, демонстрирующая возможности ограниченных маркеро Передав ограниченный маркер функцию можно процесс с ограниченными правами и привилегиями. Это же в вызова или с той разницей, что в контексте в систему пользователя поток, Вот программа, демонстрирующая, как на основе маркера текущего создавать новый ограниченный маркер: удаляются все привилегии, кроме (она нужна всем записям). этого устанавливается фл по для топкого выборочного отключения привилегий придется создать собственный список, не говоря уже о превращении тификатора локального администратора в запрещающий.

/* •/ // Создаем SID для группы BYTE = = If 2, 204 Часть II Методы безопасного кодирования О, О, О, О, О, О, ) { Error );

return -1;

// Превращаем SID локального администратора в запрещающий SID.

= = 0;

// Получаем маркер текущего процесса.

HANDLE = NULL;

if | | | с ошибкой );

return -1;

// Создаем на основе полученного маркера процесса ограниченный маркер.

HANDLE = NULL;

1, SidToDisable, 0, NULL, завершилась с ошибкой }:

return -1;

I if (pAdminSID) // код создает новый процесс // с ограниченным маркером.

pi;

si;

sizeof(STARTUPINFO) );

= = NULL;

// Задаем путь к чтобы быть уверенным, // что не выполняем "троянскую" версию Cmd.exe, Char if { if == ГЛАВА 7 Принцип минимальных привилегий == == { NULL, FALSE, NULL, NULL, завершилась с ошибкой );

return 0;

Невозможна сетевая аутентификация маркера с ограниченными D в качестве пользователя. Функция позволит выяснить, ограничен ли маркер, Внимание! Не меняйте в Restrict.cpp значение (в про грамме — на В противном случае при работе с сервером терминалов (Terminal Server) приложение будет выполняться в физической консоли пользователя, а не в сессии Terminal Server, из которой его запустили.

Полный листинг программы вы найдете в папке Программа создает новый экземпляр программы командного процессора — в нем выполнять другие приложения для изучения их поведения в урезанном контек сте безопасности.

Если после выполнения демонстрационного приложения вы взглянете на со держимое маркера процесса (применив программу то получите показанный далее результат. Как вы видите, SID группы Administrators стал щающим (deny-only), а все кроме удалены.

User Users [DENY] BUILTIN\Users NT Users SIDS None 206 Часть II Методы безопасного кодирования Privileges (3) Следующий код создает новый процесс, применяя ограниченный маркер. Ана логично создают отдельные потоки. Здесь демонстрируется использование огра ниченного маркера в многопоточном приложении. Для создания потока вызыва ется функция она удаляет из маркера потока все привилегии, кроме Bypass Traverse а затем вызывает функцию DoThreadWork.

DWORD { DWORD 0;

try { if throw HANDLE = NULL;

HANDLE = if TOKEN_ASSIGN_PRIMARY | | | TRUE, throw HANDLE hNewToken = NULL;

if 0, NULL, 0, NULL, 0, NULL, throw if throw // DoThreadWork действует в "урезанном" контексте.

DoTh } d) { dwErr = d;

!

if (dwErr == 0) return dwErr;

ГЛАВА 7 Принцип минимальных привилегий void HANDLE = 0, NULL, if I Применяйте политику ограниченного использования программ и Windows XP В XP добавлена новая возможность под названием Software Policies (Политики ограниченного использования программ), или SAFER, ная для упрощения работы с ограниченными маркерами в приложениях. Мы говорим о вопросах программирования для SAFER, а не администрирования. По дробнее об администрировании SAFER вы узнаете во встроенной справочной стеме Windows XP, выполнив поиск по фразе Software Restriction Policies (в ской версии — ограниченного использования SAFER содержит ряд функций (они объявлены в которые упроща ют работу с маркерами с низкими привилегиями. Одна из них — Получая маркер в качестве аргумента, она модифицирует его, права до заранее определенного уровня.

Показанный далее код демонстрирует создание нового процесса для выпол нения от имени учетной записи, не входящей ни в группу Administrators (Администраторы), ни в Power Users (Опытные пользователи). Файл с кодом есть в папке После выполнения программы используйте ken.cpp для просмотра изменений SID и привилегий, Л */ ttinclude void { // Допустимые уровни SAFER:

// (полное доверие) // (обычный) (ограниченный) // // // Создаем уровень обычного if О, { 208 Часть II Методы безопасного кодирования // Создаем ограниченный маркер для дальнейшего использования.

HANDLE = NULL;

if // более безопасного уровня.

NULL, // маркер потока - NULL, // Целевой маркер.

О, // Без флагов.

{ // Зарезервировано, // Определяем путь к быть в // что мы не выполняем "троянскую" версию Cmd.exe if sizeof { sizeof (szPath), szSysDir);

STARTUPINFO si;

sizeof = sizeof(STARTUPINFO);

= NULL;

pi;

if szPath, NULL, NULL, NULL, FALSE, NULL, NULL, с ошибкой );

Примечание Возможности SAFER очень обширны и не ограничиваются упро процедуры создания маркеров и выполнением процессов в более безопасном контексте. Рассказ о потенциале касающемся политик и выходит за рамки нашей книги, созданию защищенных приложений. Даже хорошо напи санное приложение может пасть атаки из-за неграмотного ад министрирования или неправильной установки. Поэтому необходимо, чтобы развертывающие приложение специалисты знали, как надежно и практично устанавливать и использовать технологии, в числе которых SAFER.

ГЛАВА 7 Принцип минимальных привилегий Полностью удаляйте ненужные привилегии В Windows Security Push (когда сотрудники работали не над но выми возможностями, а тестировали и проверяли безопасность старых) мы до к Windows Server 2003 новую функцию — удаление привилегии вы полняемого приложения. Тут есть небольшое отличие от SAFER: подразумевается «чистка» из первичного маркера процесса, а не порожденного пото ка. Преимущество заключается в том, что приложению запрещенные привилегии в принципе недоступны: как в штатном режиме, так и под атакой.

Как правило, код для удаления привилегий вызывается при запуске ния. Приведенный ниже текст программы демонстрирует удаление двух легий из маркера процесса.

// ffifndef (0x00000004) ffendif DWORD DWORD cPrivs) { HANDLE = NULL;

if | return DWORD = sizeof TOKEN_PRIVILEGES + * cPrivs);

char = new = // Удаляем две привилегии.

= cPrivs;

for (DWORD i=0;

i < cPrivs;

{ = // привилегии.

BOOL fRet = FALSE, 0, NULL, NULL);

DWORD = GetLastErrorO;

ffifdef -> 210 Часть II Методы кодирования ttendif if delete [] pbBuff;

return dwErr;

' int main(int argc, CHAR* LPCTSTR = if == 0) { // Круто! Работает!

} Если вы знакомы с то поймете, что единственное измене ние заключается в появлении нового флага — Запомните:

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

Если вы создали службу для работы в Windows Server 2003 и уверены, что никогда не потребуются привилегии, желательно их удалить. Так как подобный код работает только в операционных системах, начиная с Win dows Server 2003, перед его выполнением разумно вызвать функцию GetVer и выяснить версию ОС.

К примеру, в Windows Server 2003 процесс LSA (LSASS.EXE) лишен приви легий, которые не нужны для системных задач:

• • • • • • • • • • • • У службы Smartcard также удалены лишние привилегии:

• • • • • SeUndockPrivilege.

ГЛАВА 7 Принцип минимальных привилегий Доходит даже до того, что у некоторых компонентов убирают все кроме которая необходима для работы с NTFS. Следующий код предназначен именно для этого:

V define (0x00000004) ttendif \ \ == DWORD { DWORD = 0;

VOID* Tokenlnfo = NULL;

try { HANDLE hToken = NULL;

if | throw DWORD if TokenPrivileges, NULL, 0, { dwError = if (dwError != throw dwError;

Tokenlnfo = new if (NULL == Tokenlnfo) throw ERROR_NOT_ENOUGH_MEHORY;

if hToken, TokenPrivileges, Tokenlnfo, dwSize, SdwSize)) throw 212 Часть II Методы безопасного кодирования = // Эту привилегию удалять не нужно.

(DWORD = 0;

dwlndex < if = if FALSE, pTokenPrivs, throw GetLastError();

catch (DWORD { = if (Tokenlnfo) delete [] Tokenlnfo;

return dwError;

Учетные записи непривилегированных служб в Windows XP/.NET Server Службы Windows традиционно разрешается настраивать для работы как в контексте безопасности локальной системы, так и под учетной записью пользователя. Со здание отдельных учетных записей для работы каждой службы — обре менительное занятие, поэтому почти все локальные службы работают под учет ной записью локальной системы. У последней высокие привилегии SID учетной записи SYSTEM и SID группы локальных администра а это очень плохо: взломав службу, злоумышленник легко проникнет систему и получит практически неограниченные права.

Многим службам не нужны столь высокие привилегии, поэтому более безопас ный контекст оказывается как никогда кстати. Для этого в Windows XP введены две новые учетные записи служб:

• локальной службы (NT • сетевой службы (NT ГЛАВА 7 Принцип минимальных привилегий Первая обладает минимальными на компьютере и при к сетевым ресурсам действует как анонимный пользователь. У второй также нимальные привилегии, но при доступе к сетевым ресурсам она действует от учетной записи Приведу пример. Служба, работающая на компьютере BlakeLaptop под учетной записью и обращающаяся к файлу на удаленном компьютере, и выглядит точно так же, как анонимный пользователь (не путайте с гостевой учетной записью). Как правило, доступ без (то есть анонимный) запрещен, поэтому обратиться к сетевому файлу не удастся. Если же служба вы полняется на BlakeLaptop от имени доступ к файлу ся под учетной записью Примечание Запомните: в Windows 2000/XP компьютер в составе домена про ходит стандартные процедуры а его имя состоит из имени компьютера с добавленным в конец знаком 1 Для управления компьютеров к ресурсам используются ACL — точно так же, как для обычных пользователей.

В табл. показано, какие привилегии связаны с учетными записями отдель ных служб Windows Server 2003.

Таблица 7-6. Общеизвестные учетные записи служб и их привилегии по умолчанию Локальная Локальная Сетевая Привилегия система служба служба + + + + + + + + + + + + + + + + + + + + см. след. стр.

214 Часть II Методы безопасного кодирования Таблица 7-6. (окончание) Локальная Локальная Сетевая Привилегия система служба служба + Как видите, Local System прямо-таки «увешана» привилегиями, причем большая их часть обычно не требуется для работы вашей службы. Так зачем же применять именно эту учетную запись? Запомните одно большое различие между двумя но выми учетными записями служб: NetworkService обращается к сетевым ресурсам от имени компьютера, a — как анонимный пользователь, поэтому последняя доступа обычно не получает, ведь в защищенной среде анонимный доступ запрещен.

Внимание! Если ваша служба все еще выполняется как Local проана лизируйте ситуацию, как описано далее в разделе «Процедура ления оптимального набора и постарайтесь перевести ее на непривилегированные учетные записи NetworkService и LocalService.

Привилегия олицетворения в Windows Server Олицетворение (impersonation) хорошо работает в модели доверенной подсис темы, в которой сервер сам контролирует доступ ко всем своим ресурсам. Но в иерархической системе сервер не всегда владеет нужным так как тот иногда принадлежит следующему в иерархии серверу. Здесь сервер с невысоки ми полномочиями может позаимствовать права учетной записи с высокими при вилегиями и работать от ее имени. Чтобы этого не происходило, в Windows Server 2003 добавлена новая привилегия — (табл. 7-7), Таблица 7-7. Привилегия олицетворения Имя Значение По умолчанию ею наделяются процессы со следующими SID в маркере:

• SYSTEM;

• Administrators (Администраторы);

• Service (Служба).

Группе Everyone эта привилегия не выделяется, а записи Service — да, так как службам часто требуется выполнять от имени пользователей.

Права на установку новых служб предоставлены только доверенным лям, например администраторам.

Если приложение поддерживает тестировать его следует осо бо тщательно.

ГЛАВА 7 Принцип минимальных привилегий Заметьте, что эта только при олицетворении и нии (например, и Ее нельзя применять для анонимного доступа и доступа с идентификацией (на пример, и ваш код всегда может пользоваться правами своего процесса, независимо от того, обладает ли учетная запись рассматриваемой привилегией или нет. Иначе гово ря, ничто не может запретить вам олицетворять самого себя.

Отладка ошибок, возникающих из-за ограничения привилегий Вы наверняка удивитесь, к чему разговор об отладке в книге о проектировании и создании защищенных программ, Разработчики и часто даже и не думают проверять работоспособность при урезанных так как найти причину возникающих ошибок в этой ситуации подчас исключи тельно сложно. Сейчас мы расскажем о некоторых проверенных опытом мето дах отладки приложений, отказывающихся работать под непривилегированной учетной например, рядового пользователя, а не Выбор в пользу высоких привилегий делается по двум причинам:

• программа прекрасно работает в Windows но по непонятным чинам отказывается свою задачу в Windows NT/2000/XP, если у пользователя нет административных полномочий;

• проектирование, написание, тестирование и отладка приложений сложны и трудоемки.

Сейчас я расскажу о подоплеке вопроса. Перед выпуском Microsoft Windows XP я помогал группе, отвечающей за совместимость выяснить ны появления ошибок работы приложений, обусловленные отсутствием у вателя полномочий администратора. Как выяснилось, многие приложения спро ектированы без учета ACL и привилегий — особенностей системы безопасности, которые есть в Windows XP, но в принципе отсутствуют в Windows (в этих операционных системах обработка ошибок доступа попросту не Нередко встречаются приложения, странным образом отказывающиеся без полномочий администратора из-за того, что работать с ошибка ми отказа в доступе.

Почему приложения не работают под рядовой учетной записью Многие приложения, спроектированные для работы в Windows не считаны на работу в защищенной среде Windows Как я уже объяс нял, такие приложения не работают из-за недостатка привилегий или в доступе. по частоте отказов в доступе, источник ошибок — файловая система, а за ней следует реестр. Кроме того приложения часто не «при что базовая причина — ошибка защиты, а не те неполадки, о оно сообщает. А корень зла в том, что в самом начале, при тестировании, не по думали о работе программы на защищенной платформе.

Однажды мы тестировали известного текстового редактора. При запуске под рядовой учетной записью программа с ошибкой Unable to load (сбой 216 Часть II Методы безопасного кодирования при загрузке), но при этом безупречно работала, когда ее запускал администра тор. Исследование показало, что ошибка происходит из-за отказа в доступе при попытке записи в реестр. Другой пример: популярная компьютерная прекрасно работала в Windows Me, а в Windows XP при отсутствии полно мочий администратора отказывалась и упорно возвращала ошибку па мяти. Из-за нее мы потратили кучу времени на отладку этой пока не связались с производителем, который сообщил, что если все возможности исчер паны, то проблема действительно в нехватке памяти! Но и это оказалось не так — ошибка крылась в отсутствии доступа на запись в каталог Files. Другие приложения просто возвращали сообщения об ошибках, не имеющих отношения к делу, или ошибках нарушения доступа.

Внимание! Создавая предусмотрите грамотную обработку оши бок защиты с предоставлением внятных сообщений. Пользователи это оценят.

Как выяснить, почему приложение «падает» Найти причины ошибок защиты в приложении вам помогут следующие инстру менты:

• оснастка Event Viewer (Просмотр событий);

• RegMon (с сайта • (с сайта Просмотр событий Windows Оснастка «Просмотр позволяет обнаружить ошибки безопасности, если включить аудит определенных категорий событий безопасности. Рекомендуется проводить аудит удачных и неудачных попыток использования привилегии. Та ким образом удастся выяснить, пыталось ли приложение использовать привиле гию, доступную только высокопривилегированным учетным записям, разумно ожидать от программы архивирования запроса привилегии на архиви рование, которая недоступна большинству пользователей. В Windows 2000/XP аудит работы с привилегиями включается следующим образом.

1. Запустите 2. В диалоговом окне выберите сначала File (Консоль), а затем — Add/Remove Snap-in (Добавить или удалить оснастку), 3. Б диалоговом окне Add/Remove Snap-in (Добавить или удалить оснастку) щел кните кнопку Add (Добавить) — откроется окно Add Standalone Snap-in (Доба вить изолированную оснастку).

4. Выберите оснастку Group Policy (Групповая политика) и щелкните кнопку Add (Добавить).

5. В диалоговом окне Group Policy Object (Объект групповой политики) щелкните кнопку Finish (Готово), В поле Select Group Policy (Объект групповой политики) по умолчанию указано Local Computer (Локальный ком ГЛАВА 7 Принцип минимальных привилегий 6. Закройте окно Add Standalone Snap-in (Добавить изолированную 7. Чтобы закрыть Add/Remove snap-in (Добавить или удалить оснастку), щелкни те ОК.

8. Выберите папку Local Computer tings\Security Settings\Local Policies\Audit Policy (Политика «Локальный компь политики\Политики аудита).

9. Дважды щелкните значок Audit Privilege (Аудит использования чтобы открыть диалоговое окно Audit Privilege Use Properties (Свойства:

использования привилегий), 10. Установите флажки Success (Успех) и Failure и щелкните кнопку ОК.

11. Выйдите из программы. (Учтите, что на активизацию новых правил аудита дит несколько секунд.) Если выполняемое приложение выдаст ошибку, просмотрите раздел ности журнала событий Windows, чтобы отыскать события, которые примерно так:

Event Type: Failure Audit Event Source: Security Event Privilege Use Event ID: Date: 5/21/ Time: 10:15:00 AH Computer: CHERYL-LAP Description:

Privileged object operation:

Object Server: Security Object Handle;

Process ID;

Primary User Name:

Primary Domain:

Primary Logon ID:

Client Name:

Client Domain:

Client Logon ID:

Privileges: SeShutdownPrivilege В этом примере пользователь Blake пытается выполнить задачу, которой нуж на привилегия выключения компьютера. Вполне возможно, что приложение сбо ит именно по этой причине.

Утилиты Regmon и Нередко ошибки в приложениях возникают из-за отказа в доступе к реестру или файловой системе. Такие неполадки выявляются с помощью двух утилит: RegMon и FileMon. Они доступны на сайте Обе программы информируют об ошибке при каждой неправомочной попытке обращения процесса к реестру или файловой например, а 218 Часть II Методы безопасного кодирования рядовой пользователь пытается выполнить запись в раздел реестра, а это разре шается только администраторам.

При наличии на жестком диске файловых систем FAT или FAT32 никаких ошибок защиты при доступе к файлам быть не может. Если приложение сбоит при рабо те на но нормально на то очень вероят но, что причина неполадок кроется в ошибках проверки доступа. FileMon позво лит выяснить, верна ли догадка. Я вы заботитесь о безопасности и не используете FAT? Конечно, функции и успешно выпол няются и па FAT-разделе, но при этом реально ничего не делают. Возможно, в некоторых приложениях стоит предупредить пользователя о возможных послед ствиях, если он устанавливает приложение в FAT-разделе.

Примечание Программы и FileMon позволяют фильтровать результат по имени приложения. Используйте эту возможность, иначе вы потоне те в потоке информации, предоставляемом этими утилитами, Блок-схемы на рис. 7-3, 7-4 и 7-5 (стр. 219-221) показывают, как выявлять при чины ошибок, возникающих при работе программ в непривилегированном кон тексте.

Внимание! С точки зрения безопасности альтернативы работе приложения в контексте с низкими привилегиями просто не существует. Так же важно отказаться от использования учетных записей администратора или SYS TEM при выполнении повседневных задач. Конечно, вы можете пренеб речь этим советом — но стоит ли так рисковать?

Резюме По нашему глубокому убеждению принцип минимальных привилегий — самый метод защиты. Ведь в урезанном безопас ности приложению вряд ли удастся далеко отступить от своих прямых обязанно стей. Помните: безопасное приложение делает только то, для чего оно создано.

Однако создать приложение, удовлетворяющее принципу наименьших привиле гий, иногда довольно сложно, для этого требуется преодолеть многие препятствия.

Мы называем это «Битвой за низкие так как путь к безопас ной программе практически всегда оказывается усеянным терниями.

Ни в коем случае не поддавайтесь искушению запускать службы в контексте SYSTEM или администратора системы. Иначе вы не только подставите под удар пользователей своей программы, но и усложните себе жизнь: в дальнейшем мо дернизировать приложение для работы с пониженными, а значит более безопас ными привилегиями, окажется намного особенно после добавления в программу десятков новых функций и возможностей. Скорее всего при такой операции какая-нибудь старая функция «сломается», а пользователи не смогут нормально выполнять свою работу.

Так что делайте все правильно с самого начала: проектируйте, создавайте и тестируйте приложения с минимальными привилегиями, а также тщательно до кументируйте все потребности приложений в тех или иных привилегиях.

ГЛАВА 7 Принцип минимальных Начало в как и включите аудит привилегий Войдите в систему как рядовой пользователь Запустите создайте на рабочем столе Есть ли запуска О Войдите в аудита журнала как администратор.

о неудачных аудита а админист Добавьте раторском контексте I привилегию, привилегий?

которой Продолжает ли привилегий приложение сбоить?

Перейдите к рис. 7- анализа доступа к Рис. 7-3. Анализ неполадки, предположительно недостатком привилегий 220 Часть II Методы безопасного кодирования Начало Войдите & систему как рядовой на рабочем столе ярлык для - • Запустите - RegMon в админи контексте применяйте для не ACL Остановите в RegMon Отфильтруйте записи в RegMon по процесса разделе Control группы Everyone ли доступ в журнале к какому разделу реестра об отказе вызывает ошибку в т Неполадка обусловлена приложение ошибкой доступа к реестру сбоить?

Перейдите к рис. 7- проверки доступа к файлам) Рис. 7-4. Анализ неполадки, ошибкой при доступе к реестру ГЛАВА 7 Принцип минимальных привилегий ли А что файловая с NTFS?

Да Войдите в как рядовой на столе для запуска - - утилиты - в тести рования, но не ACL по умолчанию ли в записи отказе в доступе? Назначьте для файла или папки Control для группу Определите, доступ к какому пи или папке приложение уверены, что поладка причина неполадки ошибкой к файлам в Рис. Анализ обусловленной недостаточностью прав на доступ к файлам Подводные камни криптографии не раз приходилось слышать фразу: «Мы защищены, поскольку используем Однако специалисты по криптографии не столь оптимистичны:

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

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

Начнем с моей любимой темы: случайные числа в защищенных приложениях.

«Слабые» случайные числа Нередко для создания ключей или случайных маркеров (nonce) прило жению требуется сгенерировать случайную величину. механизм ГЛАВА 8 Подводные камни криптографии 22: генерации случайных чисел — основа любого безопасного приложения. Сейчас я расскажу о простом способе генерации случайных, непредсказуемых Примечание Ключом называется секретное значение, необходимое для чтения, записи, изменения или проверки защищенных данных. Ключ шифрова ния — это то, что используется в алгоритме шифрования для шифрова ния и расшифровки данных.

Проблема с функцией rand Однажды я проверял код на C++, в котором для генерации случайного пароля вызывалась функция rand библиотеки С. Проблема в том, что большинстве ализаций библиотеки С результат этой функции предсказуем. Каждое следующее число rand генерирует на основании предыдущего, поэтому созданный ею пароль легко «вычислить». Код rand есть в файле библиотеки времени ния Visual C++ 7 (С Run-time, а выглядит он вот так (для ясности я убрал многопоточный код):

int rand (void) { = * 214013L 16) & А это версия из классического труда Брайана (Brian Kernighan) и Денниса Ричи (Dennis Ritchie) «The С Programming Language, Second Edition* e unsigned long int next = 1;

int next = - 1103515245 + 12345;

return (unsigned int)(next/65536) % 32768;

Эти функции принадлежат к общему типу и известны под названием согласующихся функций (linear congruential function). Хороший генератор ных чисел характеризуется тремя свойствами: равномерным распределением нерируемых чисел, непредсказуемостью значений и поддержкой полного цикла (то есть он должен уметь генерировать количество различных из определенного подмножества, в конце концов «закрывая» все Линейно согласующиеся функции обладают первым свойством, но никак не вто рым! Иначе говоря, rand выдает равномерно распределенные числа, но каждое последующее стопроцентно предсказуемо! Такие функции бесполезны для защи щенных сред, Одно из лучших описаний линейно согласующихся функций водит Дональд Кнут (Donald в книге Art of Computer Programming.

Volume 2: Algorithms» 1998) (Дональд Е. Кнут Ис кусство программирования. Том 2. Получисленные алгоритмы.

ните на примеры rawd-подобных функций:

Русский неоднократно публиковался различными издательствами — 224 Часть II Методы безопасного Пример на VBScript На моем компьютере всегда выводит 73 22 29 92 19 89 43 29 ' Примечание: Числа могут в разных версиях VBScript.

i = 0 to г = - Rnd) + // Пример на // На моем компьютере всегда выводит 52 4 26 66 26 62 2 76 67 66...

ftlnclude void (int i = 0;

< 10;

i++) { i X 100;

i);

Пример на На моем компьютере всегда выводит 86 39 24 80 85 92 64 27 82...

650903;

(1 10) { $г = int 100;

printf // Пример на С* // На моем компьютере выводит 39 89 31 94 33 94 80 52 64 31 System;

class { static void { Random rnd = new (int i < 10;

i++) < I • Как видите, поведение их предсказуемо. (Числа, сгенерированные каждой функ цией, отличаются для разных ОС или платформ, но в одной среде последователь ность всегда одинакова.) Никогда не используйте линейно согласующиеся функции, такие как CRT-функция там, где критически важна безопасность. Резуль тат этих функций предсказуем, и взломать приложение не составит осо бого труда.

ГЛАВА 8 Подводные камни криптографии Пожалуй, известными из атак, на предсказуемости случай ных чисел, можно считать атаки на ранние версии браузера Netscape Navigator.

двух словах дело обстоит так: случайные числа, на основании которых генериро вались ключи протокола SSL (Secure Sockets оказались легко что сводило на нет эффективность SSL-шифрования. Если хакеру не стоит «вычислить» ключи, то зачем вообще шифровать данные! Описание впервые появилось на BugTraq и доступно по адресу Еще пример. Забавно, но в алгоритме выбора случайного IP-адреса для атаки черве закралась ошибка. Все инфицированные компьютеры одни и те же «случайные» IP-адреса. «Червь» бесславно погиб, так как не смог эффективно размножаться, раз за разом тыкаясь, как слепой котенок, в одни и же системы! Подробности — на Web-странице Еще один показательный пример слабых случайных чисел - атака на приложение для игры в покер Texas Hold Poker фирмы ASF Компания Reliable Software Technologies (теперь Cigital — обнаружила брешь в конце 1999 г. В программе применялась фун кция генерации случайных чисел из библиотеки Borland Delphi — линейно сующаяся, как и rand CRT. Exploit-коду требовалось знать пять карт из а остальные запросто вычислялись! Дополнительную информацию ищите на Web странице Случайные числа криптографического качества в Простое правило для защищенных систем гласит: никогда не вызывайте rand, пользуйтесь более надежными источниками случайных данных в Windows, мер которая обладает двумя свойствами хорошего случайных чисел — непредсказуемостью и равномерным распределением. Эта функция определена в и доступна практически на всех Windows-плат формах, включая Windows 95 с браузером Internet Explorer версии 3.02 и более поздних, Windows 98, Windows Me, Windows CE v3, Windows NT 4/2000/XP и dows Server 2003.

Схема процесса генерации случайных чисел в CryptGenRandom показана на рис.

Примечание Тем, кому интересно, сообщаю, что случайные числа генериру ются, как описано в FIPS 186-2. приложение по алгоритму SHA-1, как Функция CryptGenRandom на случайность [ее также называют (system которая в Windows 2000 и более версиях создается на основе многих источников, в том числе с • идентификатора текущего процесса • идентификатора текущего потока • числа тактов процессора с момента загрузки • текущего времени 226 Часть II Методы безопасного кодирования данные Генератор псевдослучайных использующий — Системная энтропия Рис. 8-1. Высокоуровневое представление процесса генерации случайных чисел в Windows 2000 и более поздних версиях. Прерывистой линией направление движения данных которую обеспечивает вызывающий код • показаний различных высокоточных счетчиков производительности • блока куда входит имя пользовате ля, имя компьютера и путь поиска. — это алгоритм хеширования, созда ющий 128-битный хеш сообщения и применяемый для проверки целостнос ти данных;

• показаний высокоточных внутренних счетчиков процессора, таких как (доступные только в архитектуре — подробная информа ция о них публикуется на HTM);

• низкоуровневой системной информации, показаний счетчиков производитель ности: Idle Process Time, Io Read Transfer Count, I/O Write Transfer Count, I/O Other Transfer Count, I/O Operation Count, I/O Write Operation Count, I/O Other Operation Count, Pages. Committed Pages, Commit Limit, Peak ГЛАВА 8 Подводные камни криптографии Page Fault Count, Copy On Write Count, Transition Count, Cache Transition Count, Demand Zero Count, Page Read Count, Page Read I/O Count, Cache Read Count, Cache I/O Count, Dirty Pages Write Count, Dirty Write I/O Count, Mapped Pages Write Count, Mapped Write I/O Count, Paged Pool Pages, Non Paged Pool Pages, Paged Pool Allocated space, Paged Pool Free Space, Non Paged Poof Allocated Space.

Non Paged Pool Free Space, Free System Page Entry, Resident System Code Page, System Driver Pages, Total System Code Pages, Non Paged Pool Lookaside Hits, Paged Pool Lookaside Hits, Available Paged Pool Pages, Resident System Page, Resident Paged Pool Page. Resident System Driver Page, Cache/Fast Read wit No Wait, Cache/Fast Read with Wait, Cache/Fast Read Resource Missed, Cache/Fast Read Not Possible, Cache/Fast Memory Descriptor List Read with No Wait, Cache/ Fast Memory Descriptor List Read with Wait, Cache/Fast Descriptor List Read Resource Missed, Cache/Fast Memory Descriptor List Read Not Possible, Cache/Map Data with No Wait, Cache/Map Data with Wait, Cache/Map Data with No Wait Cache/Map Data Wait Miss, Cache/Pin-Mapped Data Count, Cache/Pin-Read with No Wait, Cache/Pin Read with Wait, Cache/Pin-Read with No Wait Miss, Read Wait Miss, Cache/Copy-Read with No Wait, Cache/Copy-Read with Wait, Cache/ Copy-Read with No Wait Miss, Cache/Copy-Read with Wait Miss, Cache/Memory Descriptor List Read with No Wait. Cache/Memory Descriptor List Read with Cache/Memory Descriptor List Read with No Wait Miss, Cache/Memory List Read with Wait Miss, Cache/Read Ahead IOs, e Pages, Cache/Data Flushes, Cache/Data Pages, Context Switches, First Translation Buffer Fills, Second Level Translation buffer Fills и System • информации о системных исключениях, в том числе показаний Alignment Fix Up Count, Exception Dispatch Floating Emulation Count и Byte Word Emulation Count;

• информации, хранимой системой, в том числе Current Depth, Maximum Depth, Total Allocate Misses. Total Frees, Free Type, Tag и Size;

• информации о системных прерываниях, в том числе показаний Context Switches, Deferred Procedure Call Count, Deferred Procedure Call Rate, Time Increment, Deferred Procedure Call Bypass Count и Asynchronous Procedure Bypass Count;

• системной информации о процессах, в том числе показаний счетчиков: Ne>.t Entry Offset, Number Of Threads, Time, User Time, Kernel Time, Image Base Unique Process ID, Inherited from Unique Process ID, Handle Count.

Session ID, Page Directory Base, Peak Virtual Size, Virtual Size, Page Fault Peak Working Set Size, Working Set Size, Quota Peak Paged Pool Usage, Quota Paged Pool Usage, Quota Peak Non Paged Pool Usage, Quota Non Paged Pool Usage, Page file Usage, Peak Page file Usage, Private Page Count, Read Operation Count, Write Operation Count, Other Operation Count, Read Transfer Count, Write Transfer Count и Other Transfer Count.

Результирующий поток байт по SHA-1, чтобы получить значение инициирования счетчика (seed value), которое применяется для рации случайных чисел в соответствии со стандартом FIPS приложение 228 Часть Методы безопасного кодирования Разработчик вправе обеспечить большую степень предоставляя буфер данных (подробно о предоставляемых буферах описано в докумен тации к CryptGenRandom в Platform SDK). Итак, если пользователь предоставил дополнительные данные в буфер, они становятся дополнительным ингредиентом «колдовского варева», на основании которого генерируются случайные числа.

Простейшая форма вызова CryptGenRandom выглядит так;

ttinclude ftinclude hProv = NULL;

BOOL = FALSE;

BYTE DWORD = if NULL, NULL, CRYPT if cbGoop, fflet = TRUE;

if (hProv) 0);

Однако показанный далее класс C++ более эффективен, поскольку вызовы (занимает много времени) и ко торые соответственно создают и разрушают ссылки на криптографический про вайдер (Cryptographic Service Provider, CSP), инкапсулированы в конструкторах и деструкторах класса. Поэтому, пока существует объект класса нерация не создаст заметной нагрузки на систему, Л V ttinclude ttinclude ttinclude class CCryptRandom { public;

virtual BOOL DWORD cbGoop);

private:

HCRYPTPROV CCryptRandom: { = NULL;

NULL, NULL, ГЛАВА 8 Подводные камни криптографии if NULL) throw ;

{ if 0);

BOOL { if return FALSE;

return void main{) { try { CCryptRandom r;

10 случайных чисел из диапазона 0-99.

for (int i<10;

i++) { DWORD d;

if sizeof d % } catch { исключений.

Код этого примера есть в папке случайное число, генерируемое CryptGenRandom, практически невозможно — как раз то, что нам надо!

Совет Из соображений производительности избегайте частых вызовов а описатель рекомендуется передавать в место в том числе в другие потоки.

такое FIPS Федеральный стандарт обработки информации FIPS (Federal Infor Standard) применяется для сертификации криптографичес В нем описаны некоторых широко Подробнее о FIPS на Также помните, что если планируется продавать ПО правительству США, необходимо использовать алгоритмы, соответствующие стандарту FIPS догадаться, что входит в их число. Стандартная версия в 2000 и более поздних версиях удовлетворяет требованиям FIPS, 230 Часть II Методы безопасного кодирования числа криптографического качества в управляемом коде Если вам требуется создать безопасные случайные числа криптографического качества в управляемом коде, никогда не делайте как показано далее, здесь вызывается линейно согласующаяся функция, подобная rand библиотеки С:

// Генерация нового ключа шифрования.

byte[] key = new new А как делать надо, показано в этом фрагменте на С#, буфер заполняется надежными с точки зрения криптографии случайными данными;

using try { byte[] b = new new // выводим результат.

for (int i = 0;

i < } catch(CryptographicException { Класс обращается к вызывая функцию которая генерирует случайные данные. Этот же пример на Visual Ba sic выглядит так:

Imports Dim b(32) As Byte Dim i As Short Try Dim r As New r.GetBytes(b) i = 0 To - Next Catch e As Console. Message) End Try Случайные числа криптографического качества на Web-страницах В приложениях очень легко получить качественные случайные числа, просто управляемые классы, о которых говорилось ранее. На Web-сервере можно воспользоваться методом GetRandom объекта Utilities ГЛАВА 8 Подводные камни криптографии из библиотеки Следующий код показывает, как генерировать числа на ASP-странице, созданной с применением (Visual Scrip ting Edition):

a set oCC = strRand = Теперь можно использовать strRand.

strRand содержит 32 байта случайных данных в кодировке Base64, Заметьте: метод появился в CAPICOM версии 2, в версии 1 его не было. Последняя версия CAPICOM доступна по адресу: http://www.microsoft.com/ Создание криптографических ключей на основе пароля Криптографические алгоритмы шифруют и расшифровывают при щи а хорошим считается ключ, который характеризуется трудностью подбора и значительной длиной. Человеку трудно запомнить длинный ь знаков, из которых состоит ключ, поэтому люди пользуются не особо ключами — паролями или идентификационными которые гораздо легче. в вашем приложении применяется алгоритм (Data Encryption Standard), которому нужен 56-битный ключ. Хо роший имеет равную вероятность попадания в любое место диапазона О — (то есть от 0 до 72 057 594 037 927 899). Однако пароли обычно ят из легко запоминающихся ASCII-символов, таких как а также ков пунктуации, вследствие чего диапазон возможных значений ключа сильно су жается.

Если хакер знает, что вы применяете DES и пароли, придуманные лями, ему не обязательно пытаться проверить все значения из диапазона 0 — Достаточно попробовать все возможные пароли, состоящие из легко ющихся групп ASCII-символов, а это намного проще.

Примечание Должен признаться, что я просто обожаю язык В апреле 2001 г, в списке рассылки Perl кто-то спросил, как проще всего получить случайный пароль из восьми символов. В числе самых коротких был следующий пример:

print map 33+rand 93, Вряд ли пароль, который он сгенерирует, можно назвать случайным, но зато как Оценка эффективной длины пароля Один из основоположников информатики — Клод Шеннон (Claude Shannon), в 1948 опубликовал исследование «Математическая теория связи» (A Mathematical 9- 232 Часть II Методы безопасного кодирования Theory of Communication), посвященное особенностям английского языка. Не уг лубляясь в математические дебри, скажу, что число «информативных» бит в слу чайно взятом пароле составляет где и — размер множества допустимых — длина пароля. Следующий пример на демонстрирует, как определить количество полезных бит в пароле:

Function If <= 0 Then = Else EntropyBits = iPwdSize * / End If End Function Вывод пароля 8 символов, содержащего символы ' из множества A-Z, a-z, 0-9 (всего То же самое на C++:

double valid, double { return valid ? size * log(valid) / void { EntropyBits(62, Внимание! Число полезных бит в пароле очень важно при вычислении его но также следует принимать во внимание то, насколько легко его угадать. Например, у меня есть пес по кличке по этому будет сумасшествием с моей стороны выбрать пароль наподобие который без особого напряжения вычислит любой, кто хоть не много знаком со мной. Не стоит недооценивать возможности атак с применением социальной инженерии (social engineering). Один из моих друзей, большой поклонник романа Виктора Гюго не давно обзавелся смарт-картой для своего домашнего компьютера. Сто ит ли удивляться, что я с первого раза угадал PIN-код — тюрем ный номер Жана одного из персонажей.

Позвольте объяснить, почему большинство паролей так плохи. Помните, что DES с 56-битным ключом считается небезопасным для защиты длитель ного хранения. А теперь загляните в табл. где указаны размеры множеств до ступных символов и длина пароля, требующиеся в различных ситуациях для со здания эквивалентных 56- и 128-битных ключей.

ГЛАВА 8 Подводные камни криптографии Таблица Множества доступных символов и длины паролей для ключей разной длины Необходимая Необходимая длина пароля длина пароля Доступные для 56-битного для 128-битного Вариант символы ключа ключа Числовой PIN-код 17 10 (0-9) Буквы учета регистра 26 или !

Буквы с учетом регистра 52 (A-Z и a-z) Буквы с учетом регистра 52 и 0-9) и цифры Буквы с учетом 93 (A-Z, a-z. цифры и знаки пунктуации и знаки Если получаете пароли или ключи от добавить в диалоговое окно информацию, объясняющую, как надежность пароля зависит от его энтропии (рис. 8-2).

a enter a & recommended you a of punctuation Г" IE mediocre;

it is to a Cancel Рис. 8-2. Пример окна ввода пароля с информацией об стойкости введенного пароля Внимание! Если для генерации ключей приходится использовать пароли, по заботьтесь о достаточной их длине и высокой степени случайности, Конечно, человеку тяжело запомнить случайные данные, поэтому при дется пойти на компромисс между случайностью и легкостью Очень поучительный документ о недостатках паролей вы найдете по адресу он называется «The Memorability and Security of Passwords — Some Empirical («Запоминаемость и безопасность паролей — некоторые эмпи рические Примечание В Windows 2003 и более поздних версиях можно про верять соответствие пароля корпоративной политике, функцию Пример па C++ есть в папке Другой великолепный документ, посвященный случайным числам в приложениях, написан Дональдом Истлейком (Donald Джеффри Шиллером Schiller) и Стивом Крокером (Steve Crocker) и называется 234 Часть И Методы безопасного кодирования ness Requirements for («Требования к случайности данных, используемых в целях Это проект новой версии RFC 1750, где обсуждаются тех нические детали генерации случайных чисел. На момент написания данной кни ги документ устарел, но имя последнего варианта документа — randomness2-02. Попытайтесь найти его с помощью любимой поисковой системы.

Управление ключами Обычно это наиболее слабое звено криптографических приложений, так как правильно реализовать управление ключами очень трудно. Использовать крип тографические технологии просто, а вот безопасно хранить, использовать и об мениваться ключами гораздо сложнее. Очень часто плохое управление ключами портит даже исключительно хорошие системы. Например, жестко прописанный в коде ключ становится легкой добычей хакера, даже если тому недоступен ис ходный код.

Взлом защиты DVD: трудный урок тайны наиболее известный с секретных данных в файле, — шифрования DVD в продукте DVD компании Xing В этой ключи DVD были защищены из рук вон и хакеры смогли ее и сделать программу DeCSS, которая Подробности — на Если ключ — это просто текстовая строка наподобие то, что бы определить пароль, можно воспользоваться специальными инструментами (один из них называется Strings), которые извлекают из ЕХЕ- или DLL-файлов все содержащиеся в них строки. Хакер элементарно определит пароль методом проб и ошибок. Поверьте мне: такие строки очень легко вычисляются. Немедленно бейте тревогу, увидев что-то подобное этому:

// Только говорите.

А если пароль состоит из качественного случайного набора данных, как и подобает хорошему ключу? Утилиты типа Strings его не найдут, поскольку он не является ASCII-строкой. Но ведь в этом-то и его слабость! Код и статические данные не случайны. Утилита, выискивающая незакономерные значения в испол няемом быстро ключ.

На самом деле такая утилита уже создана британской компанией www.ncipber.com). Она подключается к работающему процессу и сканирует его память в поисках энтропии. Обнаружив области с высокой степенью случайно сти, она выясняет, являются ли найденные данные ключом, например ключом про токола SSL/TLS, Утилита редко ошибается! Подобные атаки описаны в документе «Playing Hide and Seek with Stored Keys» («Игра в прятки с — nCipher не распространяет утилиту, храня ее для внутреннего использования.

ГЛАВА 8 Подводные камни криптографии Примечание Подробнее о хранении секретной информации в ПО рассказы вается в главе Внимание! Не прописывайте секретные ключи в коде, то же самое относится к файлам ресурсов и конфигурации. Рано или поздно их равно найдут. Если вы думаете, что этим никто не станет заниматься, то жестоко ошибаетесь.

Долгосрочные и краткосрочные ключи Существует два класса ключей: долгосрочные и краткосрочные. Последние также называют или эфемерными (ephemeral), и используют в самых ных сетевых протоколах, например SSL/TLS, и Процесс ления генерацией ключей скрыт от приложения и пользователя.

Долгосрочные ключи применяются для аутентификации, обеспечения целос тности сообщения и невозможности отрицания авторства а также создания временных ключей. Например, в протоколе SSL/TLS сеансовые ключи сервер обычно создает на основе своего закрытого ключа. Вообще-то, все намного сложнее, но основная идея именно такая.

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

А теперь пришла пора рассказать о том, как правильно управлять ключами, Выбор длины ключа для защиты данных Зашифрованные данные необходимо защищать ключом достаточной длины. По нятно, что чем она меньше, тем легче хакеру. Однако ключи различных мов взламывают по-разному. Большинство ключей симметричных таких как DES и RC4, взламывают простым перебором. А вот атакуя RSA (алгоритм асим метричного шифрования), пытаются определить случайные которые применялись для генерации открытого и закрытого ключей. Такой процесс разложением на множители (factoring). Поэтому нельзя утверждать, что менее безопасен, чем 512-битный ведь они взла мываются разными способами. Если уж об этом зашла речь, то последний расклады вается на множители значительно быстрее, чем выполняется полный перебор битного Примечание Посмотрите статью (Проблемы крип тографии) на Web-странице В ней речь идет о взломах полным перебором и RSA — разложени ем на множители.

Таким образом, вы вправе защищать симметричные ключи но только при условии, что у последних достаточная длина. Примерные 236 Часть II Методы безопасного кодирования ния возьмите из табл. 8-2, созданной на основе документа Strengths For Public Keys Used For Exchanging Symmetric Keys» («Определение стойкости от рытых ключей, применяемых для обмена симметричных ключей») Таблица 8-2. Соответствие размеров симметричных и асимметричных ключей Длина симметричного Эквивалентная длина Эквивалентная длина ключа, бит ключа RSA, ключа DSA, 70 1228 i ! 1553 00 1926 [ 4575 8719 Итак, для защиты 80-битового симметричного ключа годится дли ной по крайней мере бит. Если он короче, хакеру проще расшифровать ключ RSA, чем атаковать «в 80-битный симметричный ключ.

Внимание! Бессмысленно защищать 128-битный 512-битным RSA Выбор места хранения ключей При использовании секретной информации, такой как криптографические клю чи и пароли, храните их как можно ближе к месту, где выполняется шифрование и расшифровка данных. Причина проста: секреты недолго остают ся тайной. Как однажды сказал мой друг: «Ценность секрета обратно пропорцио нальна его доступности». Можно перефразировать: «Тайна, известная уже таковой не Это верно не только по отношению к людям, но и к коду, где работают секретные данные. Как я уже в любом коде есть ошибки, и чем больше частей программы имеют доступ к секрету, тем больше шансов, он станет достоянием хакера (рис.

В левой части рис. 8-3 демонстрируется пример передачи пароля от функции к функции, от одного исполняемого файла другому. Функция считывает пароль из хранилища и передает через Encrypt, — в Это очень неудачно спроектированная программа, поскольку брешь в лю бой из функций чревата утечкой пароля.

Справа структура программы получше. Функция получает опи (handle) пароля, который и передает в Последняя функция сама извлекает ключ из хранилища. Компрометация любой из промежуточных ций позволит хакеру получить всего лишь описатель, но не сам пароль.

ГЛАВА 8 Подводные камни криптографии D.EXE = C.EXE Рис. по всему приложению и близко к Внимание! Секретные данные, в том числе пароли, больше подвержены ком прометации, если передаются между компонентами приложения, а не хранятся централизованно и не обрабатываются Функции и В Microsoft CryptoAPI есть функция CryptGenKey, для надежного ключа криптографического качества, однако вам не удастся увидеть сам ключ — вам предоставляется только его описатель. Ключ CryptoAPI, и обращения к нему осуществляются через описатель. Если ключ надо сохранить в постоянном хранилище, таком как гибкий диск или база дан ных, экспортировать ключ вызовом функции и им портировать — функцией Ключ защищается либо открытым клю чом сертификата (а позже расшифровывается парным закрытым ключом), либо симметричным ключом (в Windows 2000 и более поздних версиях). Ключ никог да не передается и не хранится открытым текстом (plaintext), т. е. в незашиф рованном виде. С самым ключом работает только CryptoAPI. что надежную защиту.

Вот код на демонстрирующий, как создается и экспортируется закрытый КЛЮЧ:

238 Часть II Методы безопасного кодирования Л tfinclude using namespace std;

// Получить симметричный сеанса, которым следует ключ, void hProv, HCRYPTKEY { сеанса получаем из внешнего источника.

BYTE if sizeof ЬКеу)) throw if CALG_SHA1, 0, 0, throw if bKey, sizeof bKey, throw GetLastErrorO;

if hHash, throw GetLastErrorO;

I void { HCRYPTPROV hProv = NULL;

HCRYPTKEY = NULL;

HCRYPTKEY = NULL;

= NULL;

try { if NULL, NULL, throw GetLastErrorO;

// Сгенерируем два и пометим их как экспортируемые.

// Заметьте: эти ключи хранятся в CryptoAPI.

if CRYPT_EXPORTABLE, throw GetLastErrorO;

// Получаем ключ, которым будем шифровать большого двоичного объекта DWORD = 0;

if hExchangeKey, ГЛАВА 8 Подводные камни криптографии О, pb Key, throw pbKey = new для хранения зашифрованный большой двоичный объект.

if Key(hKey, 0, throw GetLastErrorO;

cout "Класс, " dwLen зашифрованный ключ // зашифрованный ключ в файл // при необходимости переписываем вызовом вместо // оператора поскольку данные могут содержать ), dwLen);

{ "Ошибка e hex e endl;

// Выполняем очистку, if (hExchangeKey) if (hKey) if (hProv) CryptReleaseContext{hProv, 0);

if (pbKey) delete [] pbKey;

Этот код вы найдете в папке Имейте в виду, что ~ лишь пример, в реальном приложении она должна чать сеансовый ключ из его хранилища или от пользователя. Теперь вы може'! е получать из хранилища ключ в форме и шифровать и ровывать им данные, даже не зная, как он выглядит! Приложение генерирует дна 3DES — это алгоритм в котором данные шифруются тремя различными ключами. Его труднее взломать, чем простой DE:S.

Проблемы обмена ключами ключами — это одна из самых сложных и неблагодарных подзадач задачи управления ключами. Как-никак, если хакеру удастся процесс обмена ключами, он получит доступ к ключам шифрования данных и в итоге сможет приложение. Основная угроза, которую таит в небезопасный или ненадежный механизм обмена ключами, — раскрытие и пор ча информации. И то, и другое дает возможность атаковать сетевых Часть II Методы безопасного объектов если ключ применяется для аутентификации или подписи данных. Помните: подпись служит для подтверждения подлинности и целостнос ти документа, и если ключ подписи то за целостность доку мента поручиться нельзя.

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

• Некоторые ключи никогда должны участвовать в обмене! закрытые ключи подписи (на то они и Так что каждый раз спрашивайте себя:

ли необходимо делать этот ключ Вы сами как часто обмен окажется совершенно ненужным и вас устроит какой-нибудь другой безопасный протокол, где обмен не требуется.

• Как я уже никогда не ключ в коде. Раз и навсегда решить проблему обмена ключами можно, вообще не прибегая к помощи клю если вы все-таки задействовать ключ, а хакер его взлома ет (а при возможности он это сделает, не сомневайтесь), готовьтесь к большой ложке дегтя (об этом — в главе 9).

• Не исключайте возможности «приделать сменным носителям для обме на ключами (то есть чтобы обмен ключами выполнялся с помо щью дисков, лепт и других сменных носителей). Весьма трудно пере хватить ключ, когда для его доставки используются люди, а не связи.

Правда это менее удобно, но в свете проблем с безопасностью вполне терпи мо, а усилия окупаются сторицей. Подобный режим поддерживает утилита администрирования в Windows 2000 и более поздних ОС. На рис. 8- показано диалоговое окно сохранения сертификата, который затем пользова тель доставляет «на своих двоих».

Рис. 8-4. В диалоговом выбора способа предоставляется сертификат вместо сетевого механизма обмена ключами В английском языке подобная в которой перенос данных осуществляется не по линиям связи, а путем сменных носителей с данными, называется от sneaker — и net — «сеть». — Прим. перев.

ГЛАВА 8 Подводные камни криптографии может, стоит установить протокол, который возьмет обмен клю чами на себя. Это применимо лишь для краткосрочных и временных к.

например тех, что передаются по сети. Так, в протоколах SSL/TLS и ред передачей данных выполняется обмен ключами. Подобный метод не го если данные хранятся в реестре или базе данных.

И для обмена ключами выбирайте проверенные механизмы, можно доверять стопроцентно, например согласование ключей Диффи — лмана — или обмен ключами по алгоритму Ни в коем не изобретайте собственный протокол. Скорее всего, вам не удастся это корректно, и ваши ключи станут легкой добычей хакеров.

Создание собственных криптографических функций Меня передергивает, когда я слышу что-то вроде: мы специалисты по криптографии. Мы создали свой супернадежный алгоритм!» или «Мы не ем всем этим алгоритмам, которые известны каждой поэтому разработ ли свой, известный только нам, а это залог Создание хорошего крипто графического алгоритма — очень сложная которая под силу лишь отлич ным специалистам. Вот пример очень плохого, просто отвратительного кода:

void DWORD *szData, { for i < dwDataLen;

i++) { szData[i] "= szKey[i % } Здесь просто выполняется операция XOR над ключом и открытым текстом;

в результате получается «зашифрованный» текст, и я не зря заключил это слово в кавычки. Термин зашифрованный означает, что текст защищен ключом. В нашем же случае ключ слаб — его взломать проще простого. Допустим, вы хакер и у вас нет доступа к коду шифрования. Приложение работает следующим образом:

рет открытый текст, «шифрует» его и сохраняет результат в файле или реестре.

Вам достаточно лишь выполнить операцию XOR над зашифрованным текстом, тым из реестра или файла, и исходными данными — и ключ у вас в кармане!

коллега называет подобное шифрование !

Никогда так не делайте! Нет ничего лучше одного из надежных и проверен ных алгоритмов, содержащихся в библиотеках, в том числе в стандар тной библиотеке Windows. Если при чтении документации по функции, которую предполагается реализовать, вы увидите слова (obfuscate) закодировать, советую вам моментально насторожиться и посмотреть, не подло В оригинале — encraption, что с (шифрование), а корень — crap переводится как «дерьмо». — 242 Часть II Методы безопасного кодирования жил ли проектировщик пытаясь изобрести собственный алгоритм рования, операции XOR Если вы что на самом деле делает прочитайте эту врезку.

рация «исключающее (таково его название) обозначается знаком и обладает интересным свойством:

© А - Вот почему ее применение для шифрования не выдерживает никакой XOR над открытым текстом и вы текст. Применив операцию к тек сту и ключу, получите исходный текст. И если вам зашифрован ный и открытый текст, вы с легкостью определите ключ!

В следующей программе в которой используется библиотека CAPICOM.

демонстрируется, как правильно шифровать и расшифровывать сообщения.

var = 0;

var = 1;

= 2;

var = 3;

oCrypto = new // Зашифруем данные.

strPlaintext = "Жил-был в норе под землей = strPlaintext;

// Получим ключ от пользователя, внешнюю функцию.

= = // Расшифруем данные.

if == strPlaintext) { Примечание Что такое CAPICOM? Это СОМ-компонент, выполняющий крип тографические функции. Его позволяют подписывать дан ные, проверять цифровую подпись, а также шифровать и расшифровы вать данные. Кроме он годится для проверки цифровых сертифи катов. CAPICOM впервые был опубликован в Windows XP Beta SDK. Перед использованием библиотеку необходимо заре ГЛАВА 8 Подводные камни криптографии Свободно распространяемые файлы для этой DLL доступны на Web-странице Внимание! Ни при каких обстоятельствах не создавайте свой собственный алгоритм шифрования. Скорее всего, вы сделаете все неправильно. В используйте в приложениях на языках сценариев (VBScript, JScript или ASP) - А при работе в (в том числе и ASP.NET) пользуйтесь классами из пространства имен Осадите из отдела маркетинга ' Предлагаю развлечься. Посвятите несколько минут изучению маркетинго вой литературы по вашему продукту. Есть в вей фразы типа защита», «уникальные алгоритмы шифрования» или прошедшее военную Чаще все го они так как вырваны из контекста. Например, если криптография, то где и как хранятся ключи?

•. ли от атак? Обнаружив подобные серьезно • те с людьми из маркетинга. Подчас они рисуют красивую, но непол ную как правило, не вполне адекватную безопасности решения, И лучше покончить с словоблудием можно раньше, пока оно подмочило репутацию вашей компаний.

Использование одного ключа потокового шифрования При потоковом шифровании (stream cipher) в каждый момент времени ется только один блок данных, обычно его размер составляет 1 байт. (RC4 — наи более известный и часто применяемый алгоритм потокового шифрования. Кро ме того, это единственный такого рода алгоритм, по в Windows.) Понимание того, как работает поточное шифрование, может уяснить, в чем опасность использования одного ключа для шифрования всего потока. Сначала ключ шифрования предоставляется алгоритму, ко торый вызывает генератор ключевого потока;

последний выдаст длины поток ключевых бит. Этот поток накладывается по методу XOR на откры тый текст, в результате чего получают готовый поток зашифрованных бит.

шифровка данных потребует обратных действий: надо выполнить XOR над клю чевым потоком и зашифрованным текстом, В шифровании один и тот же ключ применяется как для шиф рования, так и расшифровки данных. Этим оно отличается от асимметричного шифрования (например, где для тех же операций требуются два разных, но взаимосвязанных ключа. Примеры симметричных шифров: DES, AES ced Encryption он сменил DES), IDEA [используется в системе Pretty Good 244 Часть II Методы безопасного кодирования Privacy и RC2 все они относятся к алгоритмам блочного шифрования, то есть шифруют и данные блоками и не работают с потоками бит, Стандартный размер блока — 64 или бит, Зачем нужно потоковое шифрование Потоковое шифрование позволяет головной боли, с управ лением памятью. Так, зашифровав байт открытого текста, вы получите байт шифротекста. Но в DES, где шифрование выполняется блоками по 64 бита, байт открытого текста превратятся в 16 байт шифра. Оставшиеся 3 байта просто запол няют пустое место, поскольку DES шифрует только полные 64-битные блоки. Та ким образом, при шифровании байт DES зашифрует первые восемь а за тем добавит к оставшимся 5 байтам еще 3 (как правило, они пустые), чтобы полу чить еще один блок для шифрования. Я не обвиняю разработчиков в лени, но, честно говоря, чем меньше приходится с управлением памя тью, тем лучше!

Потоковое шифрование также популярно из-за своей быстроты. При прочих равных условиях программная реализация RC4 примерно в 10 раз быстрее DES.

Как причины довольно веские. Однако не следует забывать о массе под водных камней.

Подводные камни потокового шифрования Прежде всего алгоритмы потокового шифрования не назовешь большин ство из них очень крепкие и выдержали испытание временем. Но слабость не в них, а в том, как разработчики их применяют.

Обратите внимание, что каждый уникальный ключ потокового шифрования порождает одинаковый ключевой поток. Хотя нам и необходима при генерации ключа, она нам совершенно ни к чему при генерации ключевого по тока. Если бы ключевые потоки были случайными, мы никогда не смогли бы восстановить исходный поток из зашифрованного. Здесь-то и начинаются непри Если ключ используется повторно и хакер может получить зашифрован ный текст на основе известного, то ему ничего не стоит выполнить над ними операцию XOR и получить ключ. После этого любой зашифрованный этим же читается как открытая книга. А это, как вы понимаете, уже не В действительности хакеру не удается получить весь исходный текст второго сообщения: он может получить те же что ему известны из перво го сообщения. Другими если он знает первые 23 байта одного ния, то в состоянии получить первые 23 байта другого сообщения, Чтобы посмотрите на следующий код, где функ ции Л V BYTE BYTE BYTE ГЛАВА 8 Подводные камни криптографии BYTE BYTE BYTE // Исходные параметры - записать в память 2 открытого // текста и шифрования.

void { встречаемся у горы Заверть в 6 MAX_BLOB-1);

захватил меня и держит в плену в // функция.

:

Encrypt шифрует двоичный блок данных по алгоритму RC4.

void bPlaintext, DWORD { HCRYPTPROV HCRYPTKEY HCRYPTHASH Работает это так:

Получаем описатель Создаем пустой объект "хеш".

Хешируем ключ, переданный в Используем полученный на этапе 3 ключ для получения криптографического Этот ключ также содержит название алгоритма шифрования.

Используем полученный на этапе 4 ключ для шифрования открытого текста.

DWORD = bPlaintext, if NULL, NULL, 246 Часть II Методы безопасного кодирования if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, throw;

if ЬКеу, if (!CryptDeriveKey(hProv, hHash, throw;

if 0, TRUE, 0, bCipherText, if if (hHash) if void { // Шифруем два фрагмента текста ключом try { } catch { // Теперь слегка "поколдуем".

// Получить все байты уже известного или открытого текста.

(int i = 0;

i < { BYTE c1 = // Байты первого зашифрованного фрагмента BYTE p1 = // Байты первого открытого фрагмента BYTE k1 = с1 р1;

// Получаем байты потока.

BYTE p2 = k1 // Байты второго открытого фрагмента // Выводим все байты второго сообщения.

p2);

Этот пример есть в папке При запуске такого кода на ис полнение вы увидите открытый текст второго сообщения несмотря на то. что нам содержимое только первого сообщения!

В действительности можно атаковать используемые таким образом поточные даже вообще не видя открытого текста. Если у вас есть два зашифрован ных фрагмента, вы можете выполнить над ними операцию XOR, чтобы получить открытых фрагментов. Далее все просто: статистический анализ ГЛАВА 8 Подводные камни криптографии позволяет расшифровать текст. В любом языке буквы повторяются с вполне оп ределенной частотой. Например, в английском языке наиболее «популярны* Е. Т А. Располагая достаточным хакер сможет получить текст одного (или даже обоих) сообщений. (Впрочем, одного достаточно, чтобы узнать Примечание Будьте аккуратнее и никогда не используйте один и тот же ключ шифрования в любом из симметричных алгоритмов, в том числе блоч ных (DES и 3DES). двух одинаковых фрагментов исход ного текста совпадают. Хакер может не знать открытого текста, но иногда совпадения разных фрагментов (или их частей) достаточно. Часто хоть какой-то фрагмент исходного кода взломщику известен. у файлов многих типов есть стандартные заголовки, место которых в хакер может анализируя частоту и характер зашифрованного текста.

Что делать, когда необходимо использовать лишь один ключ Первое, что приходит в голову: такая ситуация вызвана неудачным проектом ложения, поэтому его придется пересмотреть! То есть, если вы обязаны зовать один ключ во всех операциях потокового шифрования, вам следует ь зовать модификатор и присоединять его к зашифрованным данным. Модифика тор (salt) — это значение, специально выбранное или случайное, которое в виде присоединяется к шифрованному сообщению. Комбиниро вание ключа и модификатора помогает сбить хакера с толку, Модификатор часто используется в UNIX-системах для создания хеша паро лей. В старые добрые времена хеши паролей хранились открытым текстом в об щедоступном файле (в каталоге /etc/passwd). Любой мог посмотреть этот и сравнить хеши своего пароля и других пользователей. Если находились совпада ющие то и пароли совпадали! В Windows модификаторы паролей не применяются, хотя в Windows 2000 и более версиях хеши паролей шифруются перед размещением в постоянном хранилище, что чивает тот же результат. В Windows NT 4.0 с SP 3 при необходимости можно за действовать функцию (настоятельно ее рекомендуем).

Внесем изменения в программу на основе применив модификатор.

if CALG_MD5, 0, 0, throw;

if (!CryptHashData

cbSaltSize, throw;

hHash, CRYPT_E 248 Часть И Методы безопасного кодирования Код просто модификатор вместе с ключом;

ключ остается зашиф а в незашифрованном виде добавляется к сообщению.

Внимание! Биты модификатора состоят из случайных данных. Биты ключа должны оставаться в тайне, в то время как к битам модификатора по добное требование не предъявляется, и они передаются открытым тек стом. Модификатор лучше всего подходит для передачи или хранения большого числа похожих пакетов, зашифрованных одним и тем же клю чом. Обычно два одинаковых пакета после шифрования тоже совпада ют до а это очень сигнал взломщику. Если менять фикатор при отсылке каждого пакета, результирующие будут отличаться, даже если исходные одинаковы. Модификаторы не обязательно должны оставаться секретными и обычно передаются от крытым текстом с каждым зашифрованным пакетом, поэтому гораздо проще с каждым пакетом менять значения модификатора, а не ключ.

Примечание Все алгоритмы шифрования в Framework — блочные. Поэтому у вас меньше шансов совершить подобную тем, что описаны в этом разделе.

Атаки на поточные шифры путем переворота бит Как я уже в алгоритмах потокового шифрования данные, как правило, шифруются и расшифровываются — достаточно применить операцию XOR к открытому тексту и ключевому потоку, сгенерированному поточным шиф ром. Из-за этого поточные шифры восприимчивы к атакам переворота бит (bit flip). При побитовом шифровании хакер может изменить 1 бит зашифрованного текста, и получатель не узнает, что изменились. Это очень опасно, если взломщик не знает содержания сообщения, но знаком с его форматом, Допустим, известно, что формат сообщения таков;

bbbbbbbbbbbbbbbbbbbbbbbbbbbb где — часы в 24-часовом формате, mm — dd — — трех аббревиатура, обозначающая месяц, — год, a — тело сооб щения. (Squirt) решил передать (Major) сообщение. Перед шиф рованием поточным алгоритмом сообщение выглядело так:

16:00 Встречаемся в парке для выгула собак. Сквирт.

Примечание Будем что Сквирт и имеют общий ключ, кото рый используют для шифрования и расшифровки данных.

Как видите, Сквирт хочет встретиться с в парке для выгула собак 3-го сентября 2004 года в 4 пополудни. как хакеру, не известен исходный у вас есть только шифрованное сообщение, и вам известен формат сообщения.

Однако ничего не мешает вам поменять один или несколько зашифрованных байт в полях времени и даты (в общем случае, в любом поле) и переправить ГЛАВА 8 Подводные камни криптографии ние у которого нет инструментов, чтобы обнаружить подмену. В шифрованном сообщении указано совсем другое время (не и встреча не состоится. Это простая и в то же время опасная атака!

Защита от атак переворота бит Подобные атаки предотвращаются путем реализации подписи или хеша с ключом (о нем чуть позже). Оба способа позволяют проверять целостность и выполнять аутентификацию. Можно использовать хеш, однако это не вполне на дежно, поскольку хакер может изменить данные, заново вычислить хеш и гь его к потоку данных. Опять-таки, факт подмены данных обнаружить не удастся.

Если вы решите использовать хеш с ключом или цифровую подпись, по ток зашифрованных данных изменится, как показано на рис. 8-5.

Данные, зашифрованные потоковым к атакам с переворотом бит Хеш, хеш с ключом или цифровая подпись Данные, зашифрованные поточным алгоритмом с проверкой целостности Рис. Потоковое шифрование — зашифрованные данные, с проверкой целостности и без нее Что выбрать: хеш, хеш с ключом или цифровую подпись Как я уже вы вправе вычислить хеш и добавить его в конец ванного сообщения. Но так делать не рекомендуется, поскольку хакер может ко пересчитать хеш после изменения данных. Использование хеша с ключом или цифровой подписи обеспечивает лучшую защиту от модификации данных, Создание хеша с ключом Хеш с ключом (keyed hash) кроме обычного дайджеста сообщения содержит деленные секретные данные, известные только отправителю и получателю. Он обычно создается путем хеширования открытого текста и конкатенацией полу ченного значения с секретным ключом или его производной. Не зная секретный невозможно вычислить хеш с ключом, Примечание Хеш с ключом — один из типов кода аутентификации сообще ния MAC). Подробнее о нем — на Web-стра нице «What Message Authentication Codes» из себя представля ют коды аутентификации сообщения») 250 Часть II Методы кодирования На рис. 8-6 показана схема процесса шифрования с применением хеша с ключом.

Рис. 8-6. сообщения и создание хеша с ключом Создавая хеш с ключом, разработчики часто совершают ошибки. Сейчас я по знакомлю вас с наиболее типичными, а затем расскажу, как правильно вать хеш с ключом.

Не забудьте о ключе Забыть использовать ключ там, где нужен хеш с ключом, — наиболее распростра ненная ошибка. Одного только хеша недостаточно. Никогда не повторяйте подоб ную ошибку!

Не используйте один ключ для шифрования данных и хеша Это по частоте ошибка. Если вы зашифровали данные одним ключом а хеш — другим хакеру придется сначала узнать чтобы расшифровать и чтобы их изменить. Если для обеих целей вы применили только то для изменения данных хакеру достаточно «вычислить» лишь этот ключ.

Не создавайте на основе разработчики создают новый ключ, выполняя довольно простые опера ции над уже имеющимся ключом (например, сдвиг бит). Запомните: хакеру ниче го не стоит повторить простую операцию!

Создание хеша с ключом Как CryptoAPI. так и классы Framework поддерживают создание хеша с чом. Далее приведен пример программы на основе CryptoAPI. где хеш с ключом создается по алгоритму НМАС (Hash-Based Message Authentication Code). Она есть в папке Стандарт алгоритма НМАС описан в RFC I ffinclude ГЛАВА 8 Подводные камни криптографии DWORD DWORD void DWORD cbData, LPDWORD pcbHMAC) ( = 0;

hKey;

hKeyHash;

{ if 0, 0, PROV_RSA_FULL, // ключ хеширования.

if 0, 0, if cbKey, if hKeyHash, 0, throw;

// Создаем hKey, 0, throw;

rtmacInfo.HashAlgid = // НМАС для данных.

cbData, throw;

// Выделяем память и получаем НМАС.

= 0;

NULL, throw;

// Получаем размер хеша.

= CbHMAC;

252 Часть II Методы безопасного кодирования if (NULL == *рЬННАС) throw;

HP_HASHVAL, throw;

{ dwErr = "Ошибка - GetLastErrorO);

if 0);

if if (hKey) if (hHash) return dwErr;

void { // Ключ от char = DWORD cbKey if == { - вы не return -1;

*szData = "Жил-был в норе под землей DWORD cbData = // разместим в переменной // Длина - байт.

LPBYTE pbHMAC = NULL;

DWORD cbHMAC = 0;

DWORD = cbKey, szData, // Что-то делаем с pbHMAC.

delete [] pbHMAC;

В Framework хеш с ключом создается почти так же, как обычный хеш, с той лишь разницей, что передается ключ.

= = key;

byte [] hash = ГЛАВА 8 Подводные камни криптографии В этом примере key (ключ) и message (сообщение) получаются где-то в дру гом месте a hash — результирующий НМАС.

Внимание! Создавая хеш с ключом, применяйте возможности ОС или библиотеки классов Framework. Это гораздо проще, чем делать всю работу самостоятельно.

Создание цифровой подписи Цифровая подпись отличается от хеша с ключом и в общем случае от MAC, ТАК как она:

• создается путем шифрования хеша закрытым ключом. В MAC используется общий ключ сеанса;

• в отличие от MAC не использует общий ключ;

• может применяться для предотвращения авторства diation) (юридической стороны вопроса мы касаться не будем). MAC для этого не годится, поскольку ключ доступен всем участвующим сторонам и может создать MAC;

• работает медленнее, чем MAC (а это очень быстрый алгоритм).

Несмотря на все цифровая подпись прекрасно справляется с тификацией и проверкой целостности, точно так же, как и MAC. Процесс ния цифровой подписи показан на рис. 8-7, Зашифрованный текст Функция цифровой подписи Рис. 8-7. Шифрование и цифровое подписание Любой, имеющий доступ к вашему сертификату с открытым ключом, может проверить аутентичность сообщения (то есть что оно пришло именно от вас, точ от того, у кого есть ваш закрытый Так что позаботьтесь о защите шего закрытого ключа.

254 Часть II Методы безопасного кодирования В подписание данных и проверка цифровой подписи выполняются очень просто. Следующий пример на VBScript подписывает текст, а затем прове ряет подпись:

strText = "Я согласен выплатить кредитору $42,69."

Set = = strText = TRUE signature = fDetached) signature, fDetached Хочу обратить ваше внимание на ряд моментов. Как правило, подписывающий не проверяет после ее создания. Обычно этим занимается получатель сообщения. Программа создает автономную которая существует сама по себе, отдельно от сообщения. И наконец, этот код должен доступ или запросит у пользователя действующий закрытый ключ подписи сообщений.

В Framework создать цифровую подпись проще простого. если вы захотите получить доступ к секретному ключу сертификата, хранящемуся в CryptoAPI. вам придется вызывать или CAPICOM напрямую из емого кода, поскольку из пространства имен нет доступа к хранилищам CryptoAPI. Отличный пример приводится в книге Framework Security» («Безопасность в Profes sional, 2002) (см. «Библиографический список» в конце книги). Настоятельно ре комендую ее всем, кто имеет дело с безопасностью, работая с платформой Framework и в общеязыковой среде (Common Language Runtime), Внимание! В процессе применения алгоритма MAC или подпи сания данных следует позаботиться о том, чтобы результат все конфиденциальные данные. Любые, не охваченные хешем данные, ха кер может безнаказанно модифицировать или использовать как один из сложной атаки.

Внимание! Для предотвращения модификации зашифрованных данных при меняйте MAC или цифровую подпись.

Повторное использование буфера для открытого и зашифрованного текста На первый взгляд одного и того же буфера для хранения откры а затем шифрованного текста не таит в себе ничего плохого. В большин стве случаев так оно и есть. Однако в многопоточной среде все гораздо сложнее, Представьте себе, что в ОС возникла критическая ситуация, приводящая к вытес нению исполнения вашего а вы об этом ничего не знаете. (Подобное случа когда необходимо срочно выполнить неотложные задачи или из-за ошибок в синхронизации.) Посмотрим правде в глаза: вы ничего не узнаете о такой кри тической ситуации, пока не столкнетесь с ней, но тогда будет уже поздно!

Обычный процесс выполнения программы выглядит так:

ГЛАВА 8 Подводные камни криптографии 1. загрузить открытый текст в буфер;

2. зашифровать буфер;

3. отослать содержимое буфера получателю, Все вроде бы хорошо. Однако представьте, что в вашем многопоточном прило жении из-за критической ситуации последние две операции поменялись местами:

1. загрузить открытый текст в буфер;

2. отослать содержимое буфера получателю;

3. зашифровать буфер.

Получателю придет открытый текст! Такая ошибка была найдена и исправле на в IIS 4. Иногда, при очень высокой нагрузке и чтобы сохранить SSL-канал с пользователем, сервер начинал действовать по описанному выше сценарию и от правлял пользователю один незашифрованный пакет данных. Вероятные шения были невелики: пользователь (или, возможно, хакер) получал всего один пакет. Кроме того, приняв такой пакет, клиентское ПО обрывало соединение.

я говорил, проблему устранили. Подробнее об этой бреши рассказывается на b странице Чтобы исправить ситуацию использовали два буфера, один для открытого другой — для зашифрованного, и обнуляли второй буфер между вызовами. Если опять возникнет конкурентная ситуация, самое плохое, что может — пользователь получит последовательность нулей, а это все-таки лучше, чем пере сылка открытого текста. В псевдокоде это выглядит примерно так:

= cbPlaintext, cbCiphertext);

delete [] Никогда не пользуйтесь одним буфером для открытого и зашифрованного текста. Создавайте два буфера и заполняйте нулями буфер с шифротекстом меж ду вызовами.

Криптография как средство защиты от атак Вашему вниманию предлагается небольшой перечень криптографических реше ний, которые годятся для защиты от опасностей, обнаруженных на стадии про ектирования системы. Табл. 8-3 не претендует на полноту, однако, просмотрев вы получите общее представление об имеющихся технологиях, 256 Часть II Методы безопасного кодирования Таблица 8-3. Общие криптографические решения для защиты от распространенных типов опасности Опасность предотвращения Пример алгоритма Раскрытие Шифрование данных RC2, RC4, DES, 3DES, AES информации по симметричному (предыдущее — Порча данных Обеспечение целостности данных и сообщений путем НМАС, цифровые использования хеш-функций, подписи RSA и DSS, XML или цифровой Подмена сетевых данных Сертификаты открытого ключа объектов отправителя и цифровые подписи Документируйте все случаи использования криптографии Криптографические алгоритмы применяются во многих приложениях для самых разных целей. Однако обычно находится немного людей, способных внятно объяс нить, почему выбран тот или иной алгоритм. Вы не зря потратите время, если создадите документ, в котором отразите и обоснуете выбор алгоритмов, а затем покажете бумагу специалисту по криптографии, чтобы он дал оценку вашему выбору.

Как-то я получил письмо от разработчика, в котором тот спрашивал, по како му алгоритму лучше шифровать администратора: MD4 или MD5. Ответ ка жется очевидным? Но не спешите с выводами. Прежде всего я поинтересовался, зачем вообще хранить пароль. Далее я сказал, что MD4 и MD5 не алгоритмы шиф а То есть это но они не обеспечивают секретности тем же способом, как шифрование.

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

Резюме в приложении сейчас несложно, для этого предназ огромное количество высокоуровневых криптографических API-интерфей сов. Однако ошибиться очень легко. Очень тщательно подходите к выбору крип тографических технологий. Избавят ли они вас от тех видов риска, что перечис лены в вашей модели опасностей? И прежде всего, специалиста по крип чтобы он проверил ваш проект и приложение на наличие ошибок.

Защита секретных данных О современных компьютерах в принципе невозможно обеспечить полностью зопасное хранение секретной информации, такой, как ключи шифрования и под писи, а также пароли. Пользователю с учетной записью, обладающей достаточ ными привилегиями, или получившему физический к компьютеру просто извлечь нужные данные. Надежно сохранить секретную информацию в программе также сложно, поэтому это делать не рекомендуется. Тем не менее ино> да приходится хранить секреты в коде приложения, и мы как сделать это с минимальным риском. Трюк в том, чтобы максимально поднять планку ности и сильно затруднить доступ к данным всем, кроме полномочных пользо телей. В этой главе речь пойдет о следующем: о методах атак, об в каких ситуациях нужно (и следует ли) хранить секретные о секретной информации от пользователя, о хранении секретов в сиях Microsoft Windows, о проблемах хранения секретов в оперативной о хранении секретов в управляемом коде, о повышении уровня безопасности и об использовании устройств для шифрования секретных данных, а также о в каких ситуациях нужно хранить секретные данные.

Должен обратить ваше внимание, что мы говорим сейчас о защите ных (persistent) данных. А вот задача защиты временных (ephemeral) данных.

например сетевого трафика, решается стандартными средствами. Для шифрова ния применяются протоколы SSL/TLS, и с механизмами защи и другие. Работа с этими протоколами обсуждается в других главах.

Внимание! Секретные данные должны оставаться секретом. Как сказал один мой коллега, «ценность секрета обратно пропорционально его доступ Или как выразился Мюллер в популярном фильме: что зна ют знает и 258 Часть II Методы безопасного Атака на секретные данные Есть два вида опасностей, которым подвергаются секретные данные: раскрытие (потеря конфиденциальности) и модификация информации. Есть и другие опас ности, но они определяются характером данных. Например, завла девший паролем другого пользователя Blake, может выступать от имени Blake. Таким образом, возможна подмена (spoofing) сетевого субъекта.

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

В системном реестре? Но как защитить сам ключ? Задача столь тривиальна, как кажется на первый взгляд.

Допустим, вы решили хранить данные, применив новейший, никому пока не известный метод. (Звучит, как сказка о золотой не так ли?) Например, вы создали превосходно написанное приложение, в котором секрет состоит из дан ных, поступающих из многих мест. Хеш полученного секрета применяется для аутентификации. На каком-то этапе вашему приложению все равно придется ра ботать с секретными данными в открытом (незашифрованном) виде.

достаточно подключить к вашему процессу отладчик, установить точку останова в месте, где завершается сбор данных и затем считать их. И все. Один из спосо бов предотвращения подобных атак в Windows NT и последующих ОС семейства — сократить число пользователей, обладающих привилегией Debug programs (От ладка программ). В комплекте ресурсов Microsoft Platform SDK эта привилегия называется или Она разрешает выполнять отладку процессов, работающих в контексте другой учетной записи. По умолчанию этой привилегией обладают только члены группы локальных администраторов, Другая опасность заключается в асинхронном событии сброса страницы па мяти с секретом в дисковый страничный файл. Имея к файлу атакующий получает возможность из него секретные данные. Есть и дру гой способ: считать секретную информацию из файла копии опера тивной памяти, создаваемой при переводе компьютера в режим. Дру гой, менее очевидный способ утечки секретной информации, — запись мого памяти в файл, выполняемая диагностической утилитой (например, Dr. Wat son) при сбое приложения. Секретные данные попадут на диск, если они хранят ся в программе открытым текстом.

Помните: «плохие всегда администраторы на своих компьютерах, по этому, установив вашу программу па своей машине, они с легкостью взломают ее.

Теперь, когда вы узнали, как можно воровать секреты, мы познакомим вас с тем, как их прятать.

Когда секрет хранить не обязательно Иногда следует удостоверится, что другой участник обмена информацией знает общий секрет (например, пароль), в этом случае хранить сам секрет не обязательно, достаточно иметь проверочное значение (verifier), в качестве которого обычно ГЛАВА 9 Защита секретных данных выступает криптографический хеш секрета. Например, если приложение проверять знание пользователем правильного пароля, достаточно сравнить хеш пароля, введенного со значением, приложению. В случае достаточно хранить не сам пароль, только его хеш. Это значительно паснее, потому что даже в случае компрометации системы сам пароль получить не удастся (разве что методом полного перебора) — взломщик узнает только хеш.

Что такое (hash или дайджеста (digest function), это криптографический алгоритм, применяемый к данным и возвращающий для различных наборов данных уникальный результат фик сированной длины. Хеш идентичен, но при изменении даже одного бита исходной хеш меняется. Обыч ная длина хеша — 160 все зависит от алгоритма. Например, в созданном Data Security Inc. MD5 длина хеша составляет бит, а в [разработка Национального стан дартов и технологий (National Institute of Standards and Technology, и • ' Агентства национальной безопасности (National Security Agency, — 160 (В настоящее время стандартной считается хеш-функция Однако NIST предложил Три новых разновидности Microsoft CryptoAPI поддерживает и SHA-1, a - и (Самую свежую ин формацию о новых алгоритмах SHA вы найдете на Web-странице Как попытка определить исходное так и его подбор на ос нове — задачи практически не так как на потребуется много времени даже на мощном (Близкая аналогия — отпечаток пальцев. Он прекрасно идентифицирует человека, но сам по себе так ничего не говорит о его лич ности.) Следует иметь в виду, что сказанное особенно верно для боль ших данных, а взломать хеш короткого довольно просто.

Хеш с модификатором данных Чтобы усложнить взломщику часто добавляют модификатор хеша.

Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 10 |



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.