WWW.DISSERS.RU

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

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

Pages:     | 1 |   ...   | 9 | 10 || 12 |

«Michael Howard David LeBlank WRITING SECURE CODE Second Edition Microsoft Press ...»

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

Если приложение записывает информацию о последних использованных фай лах или посещенных сайтах, позаботьтесь, чтобы это делалось отдельно для каж дого пользователя и чтобы эта информация хранилась в разделе HCKIJ реестра или в профиле пользователя, Никаких «звоночков» производителю Windows Media Player 7 вызывал проблемы, отправляя информацию о музыкаль ных компакт-дисках и DVD на сервер Microsoft. Идея неплоха: загружать список композиций из центральной базы данных, таким образом предоставляя пользо вателям дополнительные удобства. Проблемы начинаются, когда, к примеру, не кто хочет посмотреть фильм, но не желает, чтобы об этом знали другие. Первый приходящий на ум пример — фильмы и сайты «только для взрослых», но есть случаи и посерьезнее, например секретные военные материалы. Некоторые вещи впол не безобидны, если речь идет об обычных домашних пользователях, но все в корне меняется, когда имеется в виду трафик военной базы. Если приложению требует ся отправить какие-то данные на сайт компании-разработчика, необходимо пре дупредить об этом пользователя и предоставить ему возможность разрешить или запретить отсылку, а администраторам — включить или отключить эту функцию для всех пользователей системы.

Защита приложения от пользователей Представьте себе, что вы собираетесь анонсировать последнюю версию вашего финансового приложения на крупной конференции. Эксперты отрасли восхища ются новыми возможностями обеспечения конфиденциальности вашего прило жения, и тут один аналитик задает вопрос: «Как вы заботитесь о том, чтобы адми нистраторы вашего приложения не исчезли с деньгами пользователей?* В наше время необходимо очень аргументировано отвечать на подобный выпад. Когда последние штрихи в системе обеспечения конфиденциальности сделаны, снопа задайте сеое вопрос: «Смогут ли они сейчас добраться до данных?» Если вы уве рены, что возможен только отрицательный ответ, пригласите специалиста со сто роны, предоставьте ему привилегии администратора в сети и ПО и предложи re узнать номер хотя бы одной кредитной карточки. Если вас это пугает, то, вероят но, вы хорошо поработали над безопасностью, но не конфиденциальностью. Б этом разделе рассказывается о том, как не позволить «хорошим парням* получи гь доступ куда не следует.

Особые вопросы Часть IV Ограничение доступа к приложению Многие пользователи получают вполне законный доступ к данным, хранящимся в вашем приложении, и это нормально. Анализируя требования доступа, в пер вую очередь убедитесь, что только полномочным пользователям доступно ваше приложение или данные. Администратору сети совсем не обязательно быть ад министратором вашего приложения. Подумайте о различных уровнях доступа для отдельных пользователей. Пользователю, которому по должности полагается рас сылать клиентам письма по электронной почте, совсем не обязательно видеть номера их кредитных карт. Если все сделано правильно, пользователи никогда не увидят номера кредитных карт. Очень хорошо, если вы с полной уверенностью можете объявить об этом клиентам. Но об этом попозже. На рис. 22-11 показано, как последовательно сузить круг лиц, допущенных к конфиденциальной инфор мации. Разрабатывая приложение, старайтесь так выстраивать процессы, чтобы изолировать секретные данные и транзакции.

Пользователи сети Пользователи приложения с правами на чтение Пользователи приложения с доступом к конфиденциальным данным Администратор приложения Рис. 22-11. Ограничение доступа к конфиденциальным данным Фиксируйте все в документах При получении доступа к конфиденциальным данным, у пользователей возника ет соблазн просмотреть их. Один из способов обуздать их любопытство — обес печить аудит. Реализуя функции аудита, позаботьтесь о регистрации всех попы ток чтения информации. Обязательно выполняйте частое резервное копирование ГЛАВА 22 Обеспечение конфиденциальности журналов аудита и предотвращайте их удаление. Понимаю, что это непросто. Но овчинка стоит выделки: представьте себе, какими паиньками станут пользовате ли, зная, что все их действия регистрируются.

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

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

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

Собирая все части мозаики Ну вот вроде все у нас защищено: аудит включен, каналы связи и хранилища дан ных шифруются. Чего не хватает? А как насчет шифрования данных при переда че между партнерами и обеспечения того, чтобы передавались лишь необходи мые для транзакции данные? Если номер социального страхования и дата рожде ния не нужны для выполнения транзакций, не передавайте их. Если возможно, даже не собирайте их. Работайте только с теми партнерами, которые руководствуются такими же, как и вы, правилами конфиденциальности. Создавайте решения, ис пользующие минимальный объем информации, и раскрывайте се как можно мень шему числу лиц, Примечание Компанию, работающую с ненадежными партнерами, клиенты также считают ненадежной.

На рис. 22-12 пользователь заполняет форму, чтобы купить что-то через Ин тернет и предоставляет номер своей кредитной карты. Запрос пользователя пе редается по протоколу SSL/TLS на Web-сервер. Web-приложение шифрует данные и пересылает их на север базы данных по защищенному протоколу, например IPSec.

Если данные уже зашифрованы, шифровать полезные данные приложения не обязательно. СУБД хранит зашифрованные данные. Когда необходимо оформить заказ, информация о кредитной карте отправляет в процессинговый центр по протоколу EDI (Electronic Data Interchange) в зашифрованном виде с использова нием ключа, известного компании и центру. Процессинговый центр способен расшифровать пакет и выполнить указанные платежи. В этом случае никто не вид пт номер кредитной карты. Небольшой риск возникает, если заказ принимается или подтверждается через центр обработки телефонных вызовов. В таких случаях следует применять надежные процедуры аудита.

Особые вопросы Часть IV Оплата запрашивается Заказ...

по телефону кредитные карты f заказа заказа IPSec SSI7TLS Интернет Данные е СУБД хранятся в зашифрованном виде База данных Онлайновая о клиентах форма Рис. 22-12. Ограничение доступа к конфиденциальным данным при передаче по линиям связи Резюме Предоставляя клиентам возможность контролировать сбор, использование и рас пространение их персональной информации, вы добиваетесь их доверия. Кон фиденциальность — это очень сложная проблема, и ее достижение похоже на стрельбу по движущейся мишени. Защита конфиденциальности пользователей должна стать самой приоритетной при проектировании и разработке ПО. Как и в случае с безопасностью, основы конфиденциальности следует закладывать на этапе проектирования. От этого выигрывают не только клиенты, но и партнеры, создающие распределенные решения на основе вашего ПО. Позаботьтесь о том, чтобы ваше приложение собирало, хранило и использовало данные о пользова телях в полном соответствии с действующим законодательством.

ГЛАВА Общие методы обеспечения безопасности «i/та глава немного отличается от остальных. Здесь речь пойдет об особеннос тях процесса разработки безопасных приложений, каждое из которых важно, но не тянет на отдельную главу. Поэтому сейчас вам предлагается эдакое попурри из методов обеспечения безопасности!

Не предоставляйте взломщику никакой информации Сообщения об ошибках, из которых ничего не ясно, — бич рядовых пользовате лей и причина массовых обращений в службу поддержки, которые отнимают у персонала уйму времени. Однако, с другой стороны, нельзя предоставлять слип ком много информации потенциальным взломщикам. Например, при попытке доступа к файл)' недопустимо сообщение типа: «Не удается найти stuff.txt в c:\secrett tuff\docs», поскольку так вы предоставляете подробные сведения о среде. Следует возвратить простое сообщение об ошибке, например «В запросе отказано», и з i регистрировать ошибку в журнале, чтобы администратор смог узнать, что про изошло. Необходимо учесть и другое обстоятельство: возвращение информации, изначально предоставленной пользователем, чревато атаками с применением кросс-сайтовых сценариев, если в приложении задействован браузер. Создавая серверное приложение, предусмотрите регистрацию детализированных сообщений об ошибках, но они должны быть доступны для просмотра только администраторам.

Особые вопросы 580 Часть IV Используйте оптимальные методы создания служб Службы, которые являются аналогами демонов в UNIX, составляют основу Microsoft Windows NT и последующих ОС. Они поддерживают критические важные функ ции для операционной системы и пользователя, не требуя вмешательства после днего. Так на что же следует обратить внимание при создании службы?

Безопасность, службы и интерактивный рабочий стол Служба к Microsoft Windows — это обычно консольное приложение, работающее автоматически и не имеющее пользовательского интерфейса. Однако в некото рых случаях оно взаимодействует с пользователем. Службы, выполняющиеся в привилегированном контексте безопасности, например в SYSTEM, не должны размещать свои окна непосредственно на рабочем столе. Те из них, что предос тавляют пользователям диалоговые окна, называют интерактивными. В пользова тельском интерфейсе Windows рабочий стол представляет собой границу безо пасности;

любое приложение, выполняющееся на интерактивном рабочем столе, может взаимодействовать с любым из его окон, даже невидимым. И это не зави сит от контекста безопасности приложения, создавшего окно, и от самого при ложения. Система обмена сообщениями в Windows не позволяет приложению определить источник оконного сообщения.

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

Примечание В следующих версиях Windows интерактивных служб скорее всего не будет.

Мы рекомендуем создателям служб использовать для взаимодействия между клиентом и службой клиент-серверную технологию, такую, как RPC, сокеты, име нованные каналы или СОМ и для простого отображения состояния — информа ционное окно (MessageBox) типа MB SERVICE ^NOTIFICATION. Однако эти методы могут также предоставлять доступ к интерфейсам служб через сеть. Если этого не требуется, позаботьтесь о назначении соответствующих списков ACL или, если вы решили применить сокеты, создайте привязку с адресом замыкания на себя (127.0.0.1).

Соблюдайте особую осторожность, если служба обладает следующими свой ствами:

• выполняется в контексте высоко привилегированной учетной записи, в том числе T.ocalSystern И • отмечена в администраторе конфигурации безопасности Security Configuration Manager [Log on As (Вход в качестве) либо Allow Service to interact with desktop ГЛАВА 23 Общие методы обеспечения безопасности (Разрешить взаимодействие с рабочим столом) или в разделе реестра HKLM\ CCS\Services\MyService\Type параметром 0x0100 = 0x0100, ИЛИ • CreateService и dwServiceType, где SERVICEJNTERACTIVE_PROCESS равен SERW CEJNTERACTIVEJ>ROCESS, ИЛИ • код вызывает MessageBox, где иТуре и значение выражения (MB_DEFAULT_DE$K TOPJONLY | MB_SERVICENOTIFICATION \ MBJERVICE_NOTIFICATION_NT3X) не равно нулю.

ИЛИ • вызывает OpenWindowSiation («ivinstaO»,...), SetProcessWindowStation, OpenDesk top(«Default»r~) и, наконец, SetThreatDesktop создает пользовательский интерфе! it на рабочем столе, ИЛИ • вызываются функции LoadLibraryu GetProcAddress для вышеупомянутых фун кций.

CreateProcess также опасен, когда создается новый процесс в контексте SYSTEM, а поле STARTUPINFO.lpDesktop определяет интерактивный рабочий стол пользо вателя («WinstaO\Default»). Если новый процесс необходимо запустить в привиле гированном контексте, то наиболее безопасный способ выполнения этой onep.i ции — получить описатель маркера интерактивного пользователя и вызвать Create ProcessAsUser.

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

LocalSystem LocalSystem — наиболее привилегированная учетная запись. По умолчанию ей доступно множество важных привилегий. Если вы разрабатываете службу для Windows 2000 и последующих ОС, которая будет работать в домене Windows 200D, эта учетная запись обладает доступом к сетевым ресурсам. Преимущество в том, что она способна изменять собственный пароль. Многим службам, которые вы полняются в контексте локальной системы, в действительности не нужны такие высокие привилегии, особенно если речь идет о Windows 2000 и последующих версиях. Некоторым API-функциям, которым ранее требовался высокий уровень доступа (например, LogonUser), больше не нужны особые права в Windows ХР и последующих ОС. Планируя наделить свою службу полномочиями LocalSystem,, внимательно изучите вопрос — может оказаться, что такие привилегии не требу ются. Последствия для безопасности при работе под учетной записью LocalSystem очевидны: любая ошибка в коде приведет к компрометации всей системы. Если работа в контексте LocalSystem все же необходима, особо внимательно отнеси тесь к качеству проекта и реализации.

Особые вопросы 582 Часть IV Сетевая служба Network Service (Сетевая служба) — это новая учетная запись, представленная в Windows XP. У нее немного привилегий и нет доступа высокого уровня, но с точ ки зрения других сетевых объектов она выглядит как компьютер или учетная за пись LocalSystcm. Как и у LocalSystcm. у нее есть привилегия изменения собствен ного пароля (потому что это, по сути, урезанная версия учетной записи локаль ной системы). Препятствием к применению этой учетной записи может стать ее использование несколькими службами. При взломе одной службы практически гарантированно компрометируются остальные.

LocalService LocalService аналогична Network Service, но у нее нет никакого доступа к сетевым ресурсам. В остальном для нее характерны те же преимущества и недостатки, что и для сетевой службы. Если ранее служба работала в контексте LocalSystem, выби рать рекомендуется их этих двух учетных записей.

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

Вот как это было. В начале моей работы (рассказывает Дэвид) в компании Internet Security Systems, я поспорил на обед со своими коллегами, что им не уда стся взломать мою систему. В то время большинство из них были «юниксоидами», я один работал в Windows NT. Я посчитал, что если они сумеют взломать мою систему, то полученный опыт сторицей оплатит потерянный обед. Прошло бо лее года, но никому это не удалось — благодаря осторожному администрирова нию системы — никому из целого отряда матерых программистов, знающих ме тоды безопасности как свои пять пальцев. Одним прекрасным днем в процессе сканирования сети я обнаружил, что во всех системах резервное копирование выполняют службы, работающие под учетной записью с полномочиями админи стратора домена. Я немедленно устроил разнос нашему сетевому администрато ру, который оправдывался тем, что босс потребовал снизить безопасность сети, чтобы выполнять архивирование. «Вскоре доступ к рычагам управления доменом получат все, кому не лень!» — предупредил я, но он не поверил. И вот на следую щий день один из самых несимпатичных мне сотрудников явился ко мне с «ра достным» известием: он взломал мой компьютер! Одного беглого взгляда оказа лось достаточно, чтобы понять, что для компрометации системы он воспользо вался учетной записью для резервного копирования.

Недостаток применения доменной учетной записи для работы службы состо ит в том, что любой, кто является или может стать администратором, способен вычислить пароль, прибегнув к утилите Lsadump2, созданной Тоддом Сабином (Todd Sabin) из компании BindView. Обычно люди сразу интересуются, можно ли счи тать это дырой в защите. Строго говоря, это не брешь, так как всякий, получив ший права администратора, в состоянии реконфигурировать службу, подставив ГЛАВА 23 Общие методы обеспечения безопасности свой бинарный файл или даже внедрив в нее свой поток и заставив исполнять задачи в контексте пользователя службы- По сути, именно так и работает Lsa dump2 — внедряя поток в процесс Isass. Имейте это в виду, выбирая учетную за пись для службы. Если служба развернута в корпоративной сети и администра тор использует одну и ту же учетную запись на всех системах, то невозможно гарантировать безопасность системы в целом. Компрометация одной из систем приводит к сбросу пароля на них всех. Не позволяйте использовать одну учетную запись во всех экземплярах службы, и если предполагается работа службы в вы соко доверенных системах, таких, как контроллеры доменов, применяйте другую учетную запись. Это особенно верно, если служба требует высокого уровня до ступа и выполняется в контексте члена группы администраторов. Если служба дол жна работать под учетной записью пользователя домена, позаботьтесь, чтобы она выполнялась локально и в контексте непривилегированного пользователя. Пре доставляя средства управления вашей службой в корпоративной сети, постарай тесь предоставить администраторам рычаги управления службой, если каждый экземпляр службы выполняется в контексте отдельного пользователя. Помните, что пароль должен регулярно сбрасываться, Локальные учетные записи Локальная учетная запись часто оказывается оптимальным вариантом. Даже есчи у учетной записи есть права локального администратора, чтобы получить рекви зиты, взломщику нужна привилегия администратора;

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

это никак не скажется на работе службы.

Как видите, у каждого варианта свои плюсы и минусы. Тщательно проанали зируйте все их и используйте для службы учетную запись с минимально возмож ным набором привилегий, Не позволяйте информации просочиться через заголовки Согласен, это очень жесткое требование — многие программы, особенно Интер нет-приложения, предоставляют сведения о версии в заголовках, так как это пре дусмотрено коммуникационным протоколом. Например, Web-серверы вставляют заголовок Server:. Это хорошее подспорье взломщику, особенно если он узнает, что именно ваша версия уязвима для какого-то типа атак. Предоставьте возмож ность пользователю изменить или удалить этот заголовок. Хотя многие взломщики начинают атаку, не вникая в детали заголовочной информации.

20- Особые вопросы 584 Часть IV Примечание Изменять заголовок версии на Web-сервере IIS 5 можно утилитой \^^\5c^n^ttp://wunt}microsofl.com/windou's2000/downloads/recommended/ urlscan/defaultasp).

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

Например, чтобы атаковать Ism.dll (код, обрабатывающий запросы с расширени ем Mr) в IIS 5, достаточно запросить «левый» файл, например Splat.btr, получен ная ошибка Error: The requested file could not be found позволяет точно узнать, биб лиотека Ism.dll какой версии установлена и обрабатывает НТК-запросы. А все потому, что Ism.dll самостоятельно обрабатывает ошибки с кодом 404. не делеги руя эту операцию ядру Web-сервера.

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

Не включайте ничего лишнего!

Если пользователь или администратор отключают какую-то функцию, не возвра щайте ее в исходное состояние, не предупредив пользователя. Представьте себе, что вы заблокировали функцию Д а после установки функции В, А «чудесным образом* снова включилась. Я видел это несколько раз в больших приложениях, которые в процессе установки развертывают массу различных продуктов и ком понентов.

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

Но прежде чем нырнуть в глубины операционной системы, хочу отметить, что вы должны использовать утилиту верификации драйверов Driver Verifier в систе ме с аутентичными файлами Ntoskrnl.exe и Hal.dll — это позволит убедиться, что ваш драйвер удовлетворяет минимальным требованиям стандарта качества. В документации к Windows DDK, комплекту ресурсов для разработки драйверов, все ГЛАВА 23 Общие методы обеспечения безопасности это описано весьма подробно. Неплохо также для обработки строк задействовать версию Strsafe.h для работы в режиме ядра (см. главу 5). Версия режима ядра на зывается NTStrsafe.h и описана в сопроводительных документах к ресурсам для разработки драверов — Windows XP SP 1 DDK (Шр://www.microsofl.com/ddk/relnote XPspLasp).

Высокоуровневые проблемы безопасности При создании объектов-устройств почти все драйверы, которые это умеют делать, должны устанавливать FILE_DEV1CE_SECURE_OPEN. He устанавливают этот бит только те драйверы, которые реализуют собственную проверку безопасности, например файловые системы. Этот бит застаиляет диспетчер ввода/вывода все гда применять ограничения защиты к объекту «устройство», Детали защиты объекта-устройства, определенные в DACL-таблице в дескрип торе безопасности, необходимо определять в INF-файле драйвера. Это наилучшее место. Дескрипторе безопасности определяют в разделе AddReg группы [Classics tall32J или [DDInstall. HW] INF-файла. Следует иметь в виду, что если INF-файл модифицировался, а драйвер подписан WHQL (Windows Hardware Quality Labs), то установщик сообщит об этом.

Используйте процедуру loCreateDeviceSecure (она появилась в DDK-наборе Microsoft Windows.NET Server 2003 и Windows XP SP1) для создания именованных объектов-устройств и физических объектов-устройств, который можно открывать в «сыром» (raw) режиме (то есть без функционального драйвера, загружаемого через физический объект-устройство). Эту функцию поддерживает Windows 2000 и последующие ОС;

не забудьте включить в исходный текст файл \Ydmsec.h и вы полнить компоновку с Wdmsec.dll.

Исторически сложилось так, что многие элементы управления вводом/выво дом (input/output control, IOCTL) определены с FILE_ANY_ACCESS. Их непрост заменить в унаследованном коде из-за проблем с обратной совместимостью. Од нако в новых программах для укрепления защиты этих IOCTL-элементов в драй верах предусматривают процедуру loValidateDeinceloControlAccess для выяснения, есть ли у открывающего процесса доступ для чтения или записи. Эта функция поддерживается Windows 2000 и последующими ОС и определена в Wdmsec.h.

Инструментарий управления Windows (Windows Management Instrumentation, WMI) применяется для управления устройствами, но его система безопасности работает по-другому: защита обеспечивается в разрезе интерфейсов, а не устройств, В Windows XP и более ранних ОС дескриптор безопасности по умолчанию у WMI GUID разрешает полный доступ исем пользователям, а в Windows.NET Server и последующих версиях — только администраторам. Защиту в разрезе интерфейс* >в в WMI определяют, добавив раздел [DDInstall.WMI] (новинка в DDK-наборе для Windows.NET Server 2003 и Windows XP SP1) и определив в его подразделе AddRvg SDDL-строку.

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

з нет негибкой, что чревато трудностями при администрировании.

Часть IV Особые вопросы Описатели Драйверы работают с описателями двух типов: относящимися к процессам опи сателями, создаваемыми приложениями пользовательского режима, и глобальными системными описателями, создаваемыми драйверами. При вызове функций, воз вращающих описатели, драйверы должны обязательно определять атрибут OBJ_KER NEL_HANDIM в структуре атрибутов объекта. Это обеспечит доступность описате ля в контекстах всех процессов, и невозможность закрыть его в приложении пользо вательского режима.

Драйверы должны быть чрезвычайно осторожны при работе с описателями, предоставленными программами пользовательского режима. Во-первых, такие описатели контекстно-зависимые. Во-вторых, пока драйвер работает с описате лем, взломщик может закрыть и повторно открыть его, чтобы подменить объект, на который тот указывает. В-третьих, взломщик может передать такой описатель, чтобы «юбмануть» драйвер и заставить выполнить операции, которые не разре шены приложению, потому что проверка на право доступа не проводится для программ режима ядра, вызывающих Zw-функции*. Если драйверу необходим описатель пользовательского режима, он должен вызвать QbReferenceObjectByHandle, чтобы немедленно поменять описатель на указатель на объект, Кроме того про граммы, вызывающие ObReferenceObjectByHandle, должны всегда определять ожи даемый тип объекта и пользовательский режим в качестве режима доступа (при условии, что у пользователя такой же уровень доступа к объекту-файлу, что и у драйвера).

Символические ссылки Многие авторы драйверов ошибочно предполагают, что их устройство нельзя открыть без символической ссылки. Это ошибочное мнение, ведь в Windows NT используется единое объединенное пространство имен, доступное из любого приложения. Поэтому необходимо обеспечить безопасности любого «поддающе гося открытию» устройства.

Квота Драйверы часто выделяют память от имени приложений. Она должна выделяться вызовом функции ExAllocatePooWithQuotaTag, размещаемой в блоке try/except. Эта функция инициирует исключение, если приложение выделило слишком много системной памяти.

Примитивы сериализации Не путайте виды спин-блокировки. Нсли спин-блокировка получена вызовом КеАс quireSpinLock, она доступна только с применением этого примитива. Ее нельзя связать с другой спин-блокировкой, например в стеке. Также это не может быть внешняя спин-блокировка, связанная с объектом прерывания или служащая для То есть тех, название которых начинается с Zw, например ZwSignalAndWaitForSingleObject. — Прим. перев.

ГЛАВА 23 Общие методы обеспечения безопасности контроля interlocked-списка через ExInterlockedlnsertHeadList. Смешивание типов спин-блокировки чревато взаимными блокировками потоков (deadlock).

Примечание Постройте иерархию блокировок для всех примитивов сериали зации и строго соблюдайте ее.

Естественно, основное правило заключается в том, что драйвер не может ожи дать занятый объект-диспетчер на уровне IRQL_DISPATCH_LEVEL или выше. Попы гка выполнить эту операцию приводит к сбою ОС.

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

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

Устраняют большинство этих проблем, проверяя все адреса пользовательско го режима в блоке try/except до вызова таких функций, как MmProbeAndLockPages и ProbeForRead, и размещая весь код доступа к пользовательскому режиму в бло ках try/except. Вот пример.

NTSTATUS AddItem(PWSTR ItemName, ULONG Length. ITEM «pltem) { NTSTATUS status = STATUS_NO_MORE_MATCHES;

try { ITEM *pNewItem = GetNextltemO;

if (pNewItem) { // При сбое Probe-функция инициирует исключение.

// Выровнять на границу LARGE_INTEGER.

ProbeForWrite(pItem, sizeof ITEM, TYPE_ALIGNMENT(LARGE_INTEGER));

RtlCopyMemory(pltem, pNewItem, sizeof ITEM);

status = STATUS_SUCCESS;

} } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCodeO;

} return status;

:

Есть один, относящийся к буферам момент, о котором вы должны знать: раз решается нулевая длина данных на запись или на чтение, и в этом случае на драйвер отправляется пакет запроса на ввод/вывод (I/O request packet, IRP) с установлен ным в нуль полем длины (ioStack->ParametersReadLengtb). Драйверы должны про верять это поле до чтения других полей в предположении, что они ненулевые.

Особые вопросы 588 Часть IV При чтении нулевого пакета верны следующие утверждения в зависимости от типа ввода/вывода:

• прямой ввод/вывод: lrp->MdlAddress равняется NULL;

• буферизованный ввод/вывод: Irp->AssociatedIrp.SystemBuffer равен нулю;

• отсутствие ввода/вывода: Irp->UserBuffer указывает на буфер, но его длина равна нулю.

Не рассчитывайте, что при нулевом вводе/выводе ProbeForRead и ProbeForWrite инициируют исключение — они прекрасно поддерживают операции с буфера ми нулевой длины!

Выполняя запрос, диспетчер ввода/вывода в Windows слепо доверяет числу байт, указанному в Irp->IoStatus.Information, при условии, что lrp->IoStatus.Status являет ся любым действительным значением. Значение, возвращенное в Irp->IoStatusJnfor mation, диспетчер ввода/вывода использует как число байт, которые копируются обратно в буфер пользовательских данных, если в запросе действует буферизи рованпый ввод/вывод. Это число байт никак не проверяется. Никогда не присва ивайте Irp->IoStatus.Status значение, предоставленное пользователем, например loStack->Parameters.Read.Length, В этом случае велик риск раскрытия информации.

Пример: драйвер предоставляет 4 байта действительных данных, но пользователь определил буфер в 8 кб, так что длина выделенного системного буфера составля ет 8 кб, и диспетчер ввода/вывода копирует 4 байта достоверных данных и от 8 кб до 4 байт случайных данных из системного буфера. При выделении системный буфер не инициализируется, поэтому эти последние 8 кб-4 байт содержат слу чайную, устаревшую информацию из невыгружаемого системного пула памяти, Также имейте в виду, что диспетчер ввода/вывода пересылает байты назад в пользовательский режим, если Irp->IoStatus.Status содержит значение-предупреж дение (то есть из диапазона 0x80000000—OxBFFFFFFF). В состоянии ошибки (OxCOOOOOOO—OxFFFFFFFF) диспетчер ввода/вывода не пересылает никаких байт.

Соответствующий код состояния ошибочного IRP-пакета отличается в каждом из этих случаев. Например, STATUS_BUFFER_OVERFLOW ~ это предупреждение (дан ные передаются), a STATUS_BUFFER_TOQJ$MALL — ошибка (не передано ни одно го байта).

При прямом вводе/выводе создается список описателей памяти (Memory Descrip tor List, MDL), который применяется для непосредственного отображения пользо вательского буфера данных на виртуальное адресное пространство ядра. Это оз начает, что буфер одновременно проецируется на виртуальное адресное простран ство ядра и на пространство пользователя. Пользовательское приложение обла дает доступом одновременно с драйвером, поэтому очень важно никогда не по лагаться на постоянство данных в буфере между обращениями к нему. То есть «откусывая» данные небольшими порциями из пользовательского буфера, не сле дует рассчитывать, что информация полностью согласована и не изменилась между обращениями — ничто не запрещает пользовательскому процессу в любой момент изменить содержимое буфера. По этой же причине не применяйте пользователь ский буфер данных для временного хранения промежуточных результатов, оши бочно полагая, что пользователь не изменит их.

ГЛАВА 23 Общие методы обеспечения безопасности Одна из наиболее обычных проблем с IOCTL- и FSCTL-элементами (File System Control) — отсутствие проверки корректности буфера (заранее предполагает ся, что буфер существует, его длина указана правильно, а данным в нем можно дове рять). Распространено заблуждение, что приложение пользовательского режим;

! — единственное, кто «разговаривает» с драйвером. Это неверно.

Есть проблема с применением METHOD ^NEITHER в IOCTL- и FSCTL-элементах;

пользовательские параметры Inbuf/er, InBufLen, Quffiuffer\\ OutBuJien диспетчер ввода/вывода передает слепо, не выполняя никакой проверки на корректность. Это сильно усложняет работу с METHOD_Л'EITHER по сравнению с METHOD _BUFFER!:D, METHOD_IN_DIRECT\\ METHODJ)UT_DIRECT. He забывайте: доступ должен выпол няться в контексте вызвавшего процесса!

Та же проблема возникает при использовании быстрого ввода/вывода. Хотя для записи и чтения его могут осуществлять только файловые системы, в обычных драйверах его удается реализовать для IOCTL. Это равноценно использованию типа METHOD _NEITHER.

В обоих случаях даже при непустом (не NULL) указателе на буфер и отличной от нуля длине буфера указатель на буфер может оказаться недействительным и [и, хуже того, указывать па адрес, к которому доступ есть только у драйвера, но пс у пользователя, Отмена IRP-пакетов Одна из самых больших проблем с драйверами — процедура отмены, что обус ловлено неустранимой конкуренцией между отменой IRP-пакетов и иницииро ванием запросов на ввод/вывод, завершение ввода/вывода и очистку (IRP_MJ_CLl\A NUP). В такой ситуации воспользуйтесь советом: отменяйте IRP только в случае крайней необходимости. Драйверы, которые в состоянии гарантировать полное выполнение IRP-запросов в «достаточное короткое время» (обычно несколько секунд), вообще не нуждаются в отмене. Откажитесь от отмены — не напраши вайтесь на неприятности, Не пытайтесь отменять уже исполняющиеся запросы на ввод/вывод, так как это практически всегда чревато проблемами, исключение составляют ситуации, ког да ввод/вывод выполняется неограниченно долго. Ясно, что в некоторых драйве рах пе обойтись без отмены, например в драйвере последовательного порта, так как запрос на чтение в нем может «висеть» практически вечно. Но даже в этом случае включайте таймер, чтобы проследить, не завершится ли запрос «по соб ственной воле» и в «разумное время*.

Никогда пе пытайтесь оптимизировать отмену IRP — она случается редко, и ее оптимизация бессмысленна. При реализации отмены IRP рекомендуем использо вать функции семейства foCsqXxxx, которые определены в CSQ.H.

При наличии системной очереди советую вызывать loSetStartloAttributes со значением TRUE в параметре NonCancellable. (Эта функция есть в Windows XP и последующих ОС.) Таким образом вы гарантируете, что входная точка драйвера (startlo) никогда не будет вызываться для отмены IRP. Этот метод очень полезен, так как предотвращает жесткую конкуренцию, его всегда следует применять, ког да поддерживается системная очередь и драйвер не поддерживает отмену испол няющихся запросов, Особые вопросы 590 Часть IV Относящиеся к безопасности комментарии в коде приложения Очень часто в процессе анализа безопасности приложения мне приходилось за давать гордым создателям ряд вопросов: «Почему было принято именно такое решение по безопасности?» или «Какие предложения по защите сделаны на этом этапе?» И так же часто ответом был изумленный взгляд и круглые глаза разработ чиков. Отсюда понятна необходимость комментирования критичного с точки зрения безопасности кода. Вот простой пример (конечно же, вы вправе исполь зовать собственный стиль, но суть от этого не меняется).

// БЕЗОПАСНОСТЬ!

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

HFILE HFile = CreateFile(szParam.

GENERIC.READ, FILE_SHARE_READ, NULL, OPEN.EXISTING, FILE_ATTRI8UTE_HORMAL, NULL);

if (hFile != INVALIO_HANDLE_VALUE) ( // Выполняем операции с файлом, \ Этот небольшой комментарий помогает понять, какие решения и предполо жения относительно безопасности сделаны в момент написания кода.

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

Не рассчитывайте, что пользователи всегда принимают «правильные» решения Часто мне встречаются приложения, где принятие серьезных решений относи тельно безопасности возлагается на пользователя. Зарубите себе на носу: большин ство пользователей — полные профаны в безопасности. В действительности они ничего не желают о ней знать — им нужно, чтобы их данные и компьютеры кто то защищал, избавляя от необходимости принимать сложные решения. Также не забывайте, что в случае чего большинство пользователей выберет путь наимень шего сопротивления и щелкнет кнопку, предложенную по умолчанию. Это очень непростая задачка, так как в некоторых ситуациях все-таки приходится заставлять ГЛАВА 23 Общие методы обеспечения безопасности пользователя принимать решение. В этом случае сформулируйте задачу максимально просто и понятно. И не перегружайте диалоговое окно излишней информацией.

Один из моих любимых примеров — процесс добавления пользователем но вого корневого сертификата Х.509 в Microsoft Internet Explorer 5;

масса маловра зумительной абракадабры в диалоговом окне (рис. 23-1).

Root Certificate Slote Da yqu «ant tn Subject : ca®digsig trust, com, Safcimora Ё2 by DST, Oigla) Signature TwsSCo,, issue*! se? issued Time VaMitv : Tuesday, July ад, 1999 throng SHay, July 03, Serial Numbe? r 378260- Thlifflbprnt (shel) : АЗЕЗШгЭ S2E46A32 8S2tH7a>QCBE9E23S?SKOC Thumbprint !md5): АЗЗРЗЗРЕ 161ВШ=9 SC9F1A7F E«C89DOa Vi-i.

J Рис. 23-1. Окно установки нового корневого сертификата в Internet Explorer Я попросил жену сказать, как она понимает сообщение в диалоговом окне, и получил вполне закономерный ответ: «Не имею ни малейшего понятия!* Такой же ответ последовал на вопрос, какую кнопку она выберет! Продолжая наступление, я сообщил, что кнопка No скорее всего не позволит выполнить задачу, а при иы боре Yes удастся успешно справиться с заданием. На основании этой информа ции она сообщила, что щелкнет Yes, потому что главное — выполнить задачу. Ну.

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

Предусмотрите безопасный вызов функции CreateProcess Как же избежать обычных ошибок при вызове функций CreateProcess, CreateProct'ss AsUser, CreateProcessWitbl.ogonW, SbettExecute и WinExec, промахов, способных п| >и вести к уязвимости приложения? Для краткости я буду рассказывать о CreateProcess, подразумевая все остальные функции из указанного семейства.

Функция может неправильно разобрать значения некоторых параметров, син таксис которых отличается от ожидаемого, и в принципе способна вызвать про грамму, отличную от той, на которую рассчитывал разработчик. Наиболее опас ный сценарий развития событий — запуск «троянца* взамен нужной программы, CreateProcess создает новый процесс, руководствуясь двумя параметрами, IpApfili cationName и IpCommandLme. В первом передается имя исполняемого файла, а во втором — указатель на строку с передаваемыми программе параметрами. В Platform SDK сказано, что IpApplicationName может равняться NULL, в случае чего имеьем программы считается первая, отделенная пробелом часть командной строки IpCom mandiine. Однако если в имени программы (или в пути) есть пробелы, то при условии некорректной обработки строк в принципе возможен запуск злонамерен ной программы. Вот пример.

CreateProcess(NULL, "C:\\Program Files\\MyDir\\MyApp.exe -р -а", 592 Часть IV Особые вопросы Обратите внимание на пробел между Program и Files. Первый параметр в Creole Process ранен NULL, поэтому функция должна выполнить дополнительные опера ции, чтобы выяснить, что от нее требуется. Если файл C:\Program.exe существует, функция вызовет именно его и передает ему в качестве параметров командную строку Fties\MyDir\MyApp.exe -р -а.

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

Есть и другая потенциальная брешь. Если имя файла, передаваемое в Create Process, не содержит полного пути к каталогу, система в принципе может запус тить «не ту» программу. Пусть на сервере есть два файла с одинаковым именем MyApp.exe, но в разных каталогах: C:\Temp и C:\winnt\system32. Программист, рас считывая 3anycnfrbMyApp.exew.3system32, передал в CreateProcess только имя файла, Если приложение, вызывающее CreateProcess, запущено из каталога C:\Temp, то в результате исполнится программа MyApp.exe. А все потому, что не указан полный путь к нужной программе в system32, — ОС в первую очередь ищет нужный файл в каталоге, из которого загружена программа (C:\Temp) и. найдя его. прекращает поиск и просто запускает его на выполнение. В Platform SDK описана последова тельность поиска функцией CreateProcess нужного файла, когда путь к каталогу не указан.

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

Не передавайте NULL в качестве значения IpApplicationName Передавая NUU^ в параметре IpApplicationName, программист полагается на встро енные в функцию механизмы синтаксического разбора и выделения в командной строке пути исполняемого файла и остальных параметров, передаваемых програм ме. Однако полный путь и имя исполняемого файла следует передавать и четко указывать в IpApplicationName, а все дополнительные параметры периода выпол нения — только в IpCommandLine. Вот пример предпочтительного способа вызо ва CreateProcess:

CreateProcess( "С: \\Prog ram Files\\MyDir\\MyApp.exe", "MyApp.exe -p -а", Выделение пути к исполняемому файлу в IpCommandLine кавычками Если значение IpApplicationName равно NULL, а передаваемое имя файла содержит пробел, для отделения полного имени исполняемого файла от аргументов следу ет применять кавычки:

CreateProcess(NULL, "\"C:\\Prograni Files\\MyDir\\MyApp.exe\" -p -a", ГЛАВА 23 Общие методы обеспечения безопасности Если вы четко знаете полное имя (с путем) исполняемого файла, так почему бы сразу не вызвать CreateProcess с правильным набором аргументов?

Не создавайте общих или перезаписываемых сегментов Если приложение поддерживает общие и перезаписываемые сегменты с данны ми, то опасность очень высока;

хорошо хоть, что такие сегменты редко встреча ются. Хотя они и поддерживаются в Microsoft Windows для совместимости с уна следованным 16-разрядными приложениями, использовать их настоятельно не рекомендуется. Общие перезаписываемые блоки памяти объявляются в DLL и со вместно используются всеми приложениями, которые загружают данную DLL, Проблема в том, что такой блок полностью беззащитен, и любое «нечистоплот ное* приложение в состоянии, загрузив DLL, записать в него какие угодно дан ные, Иногда приходится обеспечивать взаимодействие с бинарными файлами, ко торые поддерживают общие разделы памяти. В приведенных далее примерах та кой раздел называется.dangersec. Программа уязвима, если в ней есть объявления, подобные приведенным ниже:

• в файле с расширением.def.

SECTIONS.dangersec READ WRITE SHARED • в файлах с расширением а.Ь' или.с'-.

йргадта comment(linker, "/section:.dangersec, rws") • в командной строке компоновщика -SECTION:.dangersec, rws К сожалению, в статье «HOWTO: Share Data Between Different Mappings of a DLL» в базе Knowledge Base рассказывается, как создавать такие опасные разделы па мяти.

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

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

Особые вопросы 594 Часть IV Это вдвойне важно в Microsoft Windows.NET Server 2003, потому что в этой ОС способность олицетворения — это привилегия, которой у процесса может не оказаться. Подробнее об этой привилегии — в главе 7.

Обязательно проверять возвращаемое значение следующих функций: Rpdmper sonateClient, ImpersonateNamedPipeClient, ImpersonateSelf, SetThreadToken, Impersonate LoggedOnUser, CohnpersonateClient, ImpersonateAnonymousToken, ImpersonateDdeClient Window и ImpersonateSecurityContext. В общем случае сбой олицетворения должен обрабатываться так же, как и отказ в доступе.

Не размещайте никаких пользовательских файлов в каталоге (Program Files Я уже подчеркивал это в главе 7, но, думаю, стоит повториться. Для записи в ката лог \Program Files требуются административные привилегии, так как запись АСЕ для обычного пользователя содержит разрешение на чтение, выполнение и про смотр списка содержимого. Предоставление административных привилегий про тиворечит принципу наименьших привилегий. Если надо сохранять пользователь ские данные, размещайте их в каталоге профиля пользователя: %<имя_пользовате ля>%\Му Documents, к которому у него есть полный доступ. Если требуется сохра нить данные для всех пользователей данного компьютера, запишите их в \Documents и Settings'\AU Users\Application Оа1а\<имя_папки>, Запись в \Program Files — одна из двух главных причин того, что многие при ложения, перенесенные из Windows 95 в Windows NT и последующие ОС, требу ют, чтобы пользователь имел права администратора. Вторая причина — запись в ветвь HKEY_LOCAL_MACHINE реестра;

об это этом сейчас и поговорим.

Не записывайте никаких пользовательских данных в раздел HKLM Как и \Program Files, раздел HKEY_LOCAL_MACHINE также не рекомендуется для размещения пользовательской информации приложения, потому что ACL этой ветви реестра предоставляет пользователям [а точнее группе Everyone (Все)] до ступ для чтения. При необходимости хранения таких данных в реестре размещайте их в HKEY_CURRENT_USER, к которой у пользователя есть полный доступ.

Не открывайте объекты для FULL CONTROL или ALL_ACCESS Этот совет приводился еще для Windows NT ЗЛ в 1993 г. и подробно объясняется в других главах книги, но я все-таки повторюсь;

если требуется открыть объект, такой, как файл или раздел реестра для чтения, открывайте его с флагом «только для чтения» и не запрашивайте полный доступ. В последнем случае неявно пред полагается, что ACL на целевом объекте очень слабая, так как иначе операция по терпит сбой.

Ошибки при создании объектов Такие ошибки связаны с особенностями работы некоторых функций, в названии которых присутствует слово Create. Вообще говоря, у таких функций, в том числе у CreateNamedPipe и CreateMutex, есть три возможных возвращаемых состояния:

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

Для создания exploit-программы взломщику необходимо «залезть» в выполня ющийся в процессе код, создающий объекты, после чего его возможности прак тически ничем не ограничены.

Дыра в защите сервера Microsoft Telnet, связанная с именованными объекта ми, обсуждается в статье «Predictable Name Pipes Could Enable Privilege Elevation via Telnet» (Предсказуемы имена именованных каналов позволяют повышать при вилегии при работе через Telnet) на странице http://www.microsoft.com/tecbnet/ security/buttetin/MSO 1-031.asp. Telnet-сервер создавал именованный канал со стан дартным именем, что позволяло атакующему перехватить имя до запуска канала, Создавая канал. Telnet-сервер фактически получал описатель существующего ка нала, принадлежащего процессу, который контролировал взломщик.

Мораль сей «басни» проста;

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

Рекомендуется программировать с дополнительной защитой, то есть позволяя ш >ду открывать только новый объект и инициировать ошибку, если тот уже существует.

ttifndef FILE_FLAG_FIRST_PIPE_INSTANCE Я define FILE_FLAG_FIRST_PIPE_INSTANCE 0x tendif int fCreatedOk = false;

HANDLE hPipe = CreateNamedPipe("\\\V\\pipe\\HyCoolPipe", PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_1NSTANCE, PIPE_TYPE_BYTE, 1, 2048, 2048, NMPWAIT_USE_DEFAULT_WAIT, NULL);

// Дескриптор безопасности по умолчанию if (hPipe != INVALID_HANDLE_VALUE) { // Похоже, что дескриптор успешно создан!

CloseHandle(hPipe);

fCreatedOk = true;

} else { printf("Ошибка CreateNamedPlpe %й", GetLastErrorO);

} return fCreatedOk;

Обратите внимание на флаг FILE_FLAG_FlRS'i_PlPE_INS'l'ANCE\ если приведен ному выше коду не удастся создать исходный именованный канал, функция воз вратит в GetLastError ошибку доступа. Этот флаг появился в Windows 2000 SP 1.

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

Особые вопросы 596 Часть IV Позаботьтесь о защите этого места от доступа и перезаписи взломщиком. Одна ко такое решение не избавляет полностью от проблемы, если серверный конец канала уязвим для DoS-атак.

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

HANDLE hMutex = CreateMutex{ NULL, // Дескриптор безопасности по умолчанию.

FALSE, "MyHutex");

If (hMutex == NULL) printf("Ошибка CreateMutex: Kd\n", GetLastErrorO);

else if (GetLastErrorO == ERROR_ALREADY_EXISTS ) printf("CreateMutex открыла "существующий* мьютекс\п") ;

else printf("CreateMutex создала новый мьютекс\п");

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

Уход и забота о CreateFile \Ут32-функция CreateFile в состоянии открывать не только файлы, но и описате ли именованных каналов, почтовых ящиков и коммуникационных ресурсов. Если ваша приложение получает имя открываемого файла из ненадежного источника, — а это, как вы знаете, нехорошо! — вы обязаны убедиться, что описатель, получен ный в результате вызова CreateFile, действительно указывает на файл, а для этого следует дополнительно вызвать GetFileType. Кроме того, никогда не следует вызы вать CreateFile в контексте высоко привилегированной учетной записи и с име нем файла, полученным из ненадежного источника, ведь ничто не мешает взлом щику подсунуть вместо файла имя канала. По умолчанию при открытии имено ванного канала вы разрешаете коду, прослушивающему на другом конце, право олицетворять вас. Если взломщик даст вам имя канала в то время, когда вы рабо таете под привилегированной учетной записью, код на другом конце канала (а это вполне может быть код взломщика) в состоянии выступать от вашего приви легированного имени — типичная атака с повышением привилегий, Для дополнительной защиты следует присвоить параметру dwFlagsAndAttributes значение SECURITY_SQOS_PRESENT \ SECURITYJDENTIFICATION - это предотвратит олицетворение:

ГЛАВА 23 Общие методы обеспечения безопасности HANDLE hFile = CreateFile(pFullPathNanie, О,О,NULL, OPEN_EXISTING, SECURITY_SQOS_PRESENT [ SECURITY.IDENTIFICATION.

NULL);

У этого способа есть небольшой отрицательный побочный эффект. Значение SEamJY_SQOS_PRESENT\SECURIT\'_IDENTlFICATIONсовпадает со значением флага FILE FLAG_OPENNQ_RECALL, а тот предназначен для удаленных хранилищ. По этой причине программа с таким флагом не сможет выбирать данные из удаленного хранилища и перемещать их в локальное.

Внимание! Обращение к файлу, имя которого задается пользователем, — все гда представляет опасность, независимо от семантики вызова CreateFue.

Безопасное создание временных файлов UNIX давно славится постоянно всплывающими то тут то там брешами, свя*ан ными с неудачным управлением временными файлами. На сегодняшний момент и Windows подобных обнаруженных прорех очень мало, но это не значит, что их нет вовсе. Далее показаЕЮ несколько примеров брешей, которые в принципе воз можны и в Windows, • Брешь, связанная с конкуренцией за ресурсы в MandrakeUpdate ОС Linux-Mandrake. Файлы, загружаемые утилитой MandrakeUpdate, размещаются в плохо защищенном каталоге /tmp. Взломщик в состоянии модифицировать или подменить их до начала их установки. Подробнее — на сайте http://un.viv.secu rityfocus.com/bid/1567 • Уязвимость каталога/tmp в XFree86 4.O.I. Причин этой проблемы несколько, и прежде всего — предсказуемые имена файлов и слабо защищенный контекст установщика. Это позволяет взломщику изменять временные данные до их установки. Подробно об этом — на сайте http://ivww.securityfocus.eom/bid/l 430.

Безопасный временный файл характеризуется тремя свойствами;

• уникальным именем:

• именем, которое трудно угадать;

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

При создании временных файлов в Windows не следует изобретать собстиен пые варианты, а применять системные функции GetTempPath и GetTempFileName, Не полагайтесь на значения системных переменных ТМР или TEMP — для выде ления временного каталога лучше использовать GetTempPath.

Эти функции удовлетворяют первому и третьему требованию: GetTempFileName гарантирует уникальность имени, a GetTempPath обычно создает временные фай лы в принадлежащем пользователю каталоге, защищенном надежным ACL. Я ска зал «обычно*, потому что службы, выполняющиеся в контексте локальной систе мы, размещают свои временные данные в соответствующем системном каталоге Особые вопросы 598 Часть IV (обычно C:\Temp~) даже при олицетворении пользователя. Однако в Windows XP и последующих ОС службы, работающие под учетными записями LocalService и NetworkService, хранят временные файлы в собственном частном каталоге, Однако две эти функции не гарантируют, что имя файла будет трудно угадать.

На самом деле GetTempFileName создаст уникальные имена файла, ипкрементируя свой внутренний счетчик, поэтому угадать следующий каталог довольно легко!

Примечание GetTempFileName не создает трудно угадываемого имени файла, а лишь гарантирует уникальность имени, Следующий пример (см. папку Secureco2\Cbapter23\CreatTempFile) демонстри рует, как создавать временные файлы, удовлетворяющие первому и второму тре бованиям, ((include HANDLE CreateTempFileCLPCTSTR szPrefix) { // Получаем имя временного каталога.

TCHAR szDir[MAX_PATH];

if (GetTempPath(sizeof(szDir)/ sizeof {TCHAR), szDir) == 0) return NULL;

// Создаем временный файл во временном каталоге.

TCHAR szFileName[MAX_PATH];

if (! GetTempFileName(szDir, szPrefix, 0, szFileName)) return NULL;

// Открываем временный файл.

HANDLE hTerap = CreateFile(szFileName, GENERIC.READ | GENERIC_WRITE, О, // Не предоставлять совместный доступ.

NULL, // Дескриптор безопасности по умолчанию CREATE_ALWAYS, FILE_ATTRIBUTE_TEHPORARY j FILE_FLAG_DELETE_ON_CLOSE, NULL);

return nTemp == INVALID_HANDLE_VALUE ? NULL : hTerap;

• int main() { BOOL fRet = FALSE;

HANDLE h = CreateTefnpFile(TEXT<"tmp"));

if (h) { // Выполняем операции с временным файлом.

ГЛАВА 23 Общие методы обеспечения безопасности CLoseHandle(h);

i return 0;

!

Обратите внимание на флаги в вызове CrealeFile. В табл. 23-1 объясняется, за чем они нужны при создании временных файлов.

Таблица 23-1. Флаги CreateFile, используемые при создании временных файлов Флаг Примечание Предусматривает создание нового файла при любых CRE4TE ALWAYS обстоятельствах. Если файл уже существует, например, из-за того что взломщик создал условия конкуренции за ресурсы и воспользовался этим, подложный файл уничтожается и перезаписывается новым. Это значи тельно снижает вероятность успеха атаки Обеспечивает небольшой выигрыш в производительно FILE ATTRIBUTE TEMPORARY' сти за счет размещения данных в памяти Обеспечивает принудительное уничтожение файла при FILE FLAG DELETE ON CLOSE закрытии последнего указывающего на него описателя.

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

Если требуется предотвратить индексирование содержимого файла службой Indexing Service (Служба индексирования), позаботьтесь, чтобы отключить пара метр каталога For fast searching, allow Indexing Service to index this folder (Разре шить индексирование папки для быстрого поиска) (рис. 23-2).

AdvancRd Attributes ЙЛ Choose the settings you иапС for this FcMer tfftien you apply these chafiges you wf be asked f you waot the changes to affect all subfolders and Fites as well.

Compress or Ёчкуог ahtr.kmtes О Compress contents to save disk space OlWf* contents to secure data Рис. 23-2. Предотвращение индексирования конфиденциальных данных Параноикам, желающим выполнить второе требование, могу порекомендова гь затруднить задачу для взломщика, создавая случайный префикс в именах временных файлов. Вот пример, где для решения этой задачи используется CryptoAPI (см. папку Secureco2\Chapter23\CreateRandomPrefix).

Часть IV Особые вопросы // CreateRandomPrefix.cpp ((include ^include ttdefine PREFIX_SIZE (3) DWORD GetRandomPrefix(TCHAR *szPrefix) { HCRYPTPROV hProv = NULL;

DWORD dwErr = 0;

TCHAR -szValues = TEXT("abcdefghij klmnopqrstuvwxyzOI23456789");

if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) return GetLastError();

size_t cbValues = Istrlen(szValues);

for (int i = 0;

i < PREFIX_SIZE;

i++) { DWORD dwTemp;

CryptGenRandom(hProv, sizeof DWORD, (LPBYTE)&dwTemp);

szPrefix[i] = szValues[dwTemp % cbValues];

I szPrefix[PREFIX_SIZE] = '\0';

if (hProv) CryptReleaseContext{hProv, 0);

return dwErr;

Установщики и EPS Если пользователи вашей программы работают с шифрованной файловой систе мой (EFS), они обычно шифруют свои каталоги для временных файлов, как это рекомендует Microsoft. Возможны небольшие неприятности, если ваш компонент создает временные файлы в стандартных каталогах, например в %ТЕМР%, а затем перемещает их в место «постоянной дислокации*. Поскольку файлы зашифрова ны ключом EFS учетной записи пользователя, установившего приложение, другим пользователям приложение недоступно. Чтобы обеспечить совместимость с EFS, программа установки должна выполнить одно из перечисленных далее действий:

• создать собственный временный каталог со случайным именем;

• создать файлы с установленным системным атрибутом (параметру dwFlagsAnd Attributes функции CreateFile следует присвоить значение FILE_ATTRIBUTE SYS TEM);

• выяснить, не зашифрован ли каталог %ТЕМР% (вызовом GetFileAltributes), и при необходимости расшифровать файлы.

Общие методы обеспечения безопасности ГЛАВА Проблемы точек повторной обработки в файловой системе Начиная с Windows 2000, система NTFS поддерживает точки подключения (junc tion). Они похожи на символические ссылки в UNIX, которые переназначают ссылку с одного каталога на другой в пределах одной машины. Для создания и управле) 1ия точками подключения служит Linkdexe, утилита из комплекта Windows Resource Kit.

Точки подключения представляют опасность в любой программе, которая выполняет рекурсивный обход структуры каталогов. Есть два вида приложений, уязвимых по отношению к этой напасти. Наименее опасно приложение, которое выполняет простой рекурсивный просмотр, например/ш^/r/s. Атакующий в со стоянии воспользоваться Linkd.exe, чтобы создать замкнутый цикл в иерархии каталогов, например чтобы c:\users\attacker ссылался на с:\. Любой рекурсивный поиск, начинающийся с c:\users, пойдет по бесконечному циклу.

Более опасная атака направлена на процесс, выполняющий разрушительные действия (например, командой rd /s). Злоумышленник может подложить свинью, перенаправив c:\temp\tempdir па c:\windows\system32. Решив удалить занимающие слишком много места временные файлы, администратор уничтожит файлы опе рационной системы, выполнив команду rd /s c:\temp.

Любое приложение, просматривающее иерархию каталогов, и особенно рекур сивно выполняющее разрушительные изменения в иерархии каталогов, должно распознавать точки подключения и не переходить по ним. Поскольку точки п >д ключения реализованы как точки повторной обработки (reparse points), прило жения должны перед началом работы с каталогом выяснять, установлен ли для т< )го атрибут FILE_REPARSE_POINT. Программа безопасна, если не обрабатывает ника ких каталогов с параметром FILE_REPARSE_POINT. Наличие этого параметра про веряется такими функциями, как GetFileAttributes и lpFindFileData->dwFtteAttributes в FindFirstFue.

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

Любая клиентская система взламывается при наличии отладчика, времени и же лания.

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

Другой серьезный аргумент — излишнее доверие клиенткой проверке препят ствует делегированию задач пользователям, не являющимся администраторами, Например, во всех ОС семейства Windows NT до Windows ХР для настройки IP Особые вопросы 602 Часть IV адреса необходимы полномочия администратора. Может показаться, что проблема решается простой настройкой записей управления доступом к разделу реестра Tcplp, но пользовательский интерфейс все равно проверяет, имеет ли пользователь права администратора. При изменении IP-адреса средствами пользовательского интер фейса подобная проверка происходила всегда, и рядовому пользователю не уда валось изменить IP-адрес. Если всегда применять средства управления доступом к основным системным объектам, значительно легче настроить, кому разрешено выполнять те или иные задачи.

Примеры часто служат шаблонами Создавая примеры п р. кений, знайте, что многие из пользователей (или чита тели) будут копирова 1 1. кид для создания собственных приложений. Таким обра зом распространяется и небезопасный код, если сам пример не отличается пре красной защитой. Я осознал это при работе с командой разработчиков Microsoft Visual Studio.NET, когда один из них сказал, что на самом деле это не примеры, а шаблоны. Я понял, что его устами глаголет истина.

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

усовершенствовать пример или отказаться от его использования. Люди учатся на примерах, а плохой код только приумножает число некачественных приложений, Во время кампании Windows Security Push мы установили простой и понятный критерий качества кода, включаемого в состав комплекта Platform SDK: «Стали бы вы применять этот код в продукте Microsoft?* Когда большинство отвечало: «Нет», код подлежал обязательной переделке пока не становился достаточно безопасным.

Влезьте в шкуру пользователя!

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

Хорошая проверка: в соответствии с принципом наименьших привилегий уда лите себя из локальной группы администраторов и поработайте со своим прило жением. Не сбоит ли какой-либо из его компонентов? Если да, то вполне возмож но, что вы советуете своим пользователям выполнять приложение в администра торском контексте? Хочется надеяться, что нет!

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

Общие методы обеспечения безопасности ГЛАВА Вы ответственны за пользователей, которых «приручили» Соблюдайте исключительную бдительность, если ваше приложение выполняется в контексте высоко привилегированный учетной записи — администраторской или локальной системы — или является компонентом или библиотекой, которая при меняется в других приложениях. Разрушительные возможности приложения с повышенными привилегиями очень высоки, поэтому следует предпринять допол нительные шаги, чтобы удостовериться, что структура программы надежна, код защищен от атак, а тестирование выполнено на самом высоком уровне.

То же верно и по отношению к компонентам или библиотекам. Пред ставь се, что ваша библиотека классов C++ или С#, которую используют тысячи пользова телей, оказалась «дырявой*. В один миг все эти тысячи подвергнутся огромной опасности. Резюме: создавая повторно используемый код, такой, как классы С-+, СОМ-компоненты или классы.NET, необходимо многократно перепроверить на дежность кода.

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

PSID GetAdminSIDQ { BOOL fSIDCreated = FALSE;

SID_IDENTIFIER_AUTHORTTY NtAuthority = SECURITY_NT_AUTHORITY;

PSID Admins;

fSIDCreated = AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUI LTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, SAdmins);

return fSIDCreated ? Admins : NULL;

BOOL flsAnAdmin = FALSE;

PSID sidAdmin = GetAdminSIDO;

if (IsidAdnin) return;

if {GetTokenlnformationfnToken, TokenGroups, ptokgrp, dwInfoSize, 604 Часть IV Особые вопросы idwInfoSize)) { for (int i = 0;

i < ptokgrp->GroupCount;

if (EqualSid(ptokgrp->Groups[i].Sid, sidAdmin»{ flsAnAdmin = TRUE;

break;

if (sidAdmin) FreeSid(sidAdmin);

Этот код представляет опасность в Windows 2000 и последующих ОС] по при чине самой природы ограниченных маркеров. В системе, где возможны ограни ченные маркеры, в действительности, любой SID может оказаться идентифика тором с проверкой только на запрет (deny-only SID), в том числе для админист раторов, Это означает, что предыдущий код возвратит TRUE независимо от того.

является ли пользователь администратором или нет. — просто потому что в мар кере есть администраторский SID. Подробнее об ограниченных маркерах расска зывается в главе 7. Дпя получения корректного результата достаточно совсем чуть чуть подправить предыдущий пример:

for (int i = 0;

i < ptokgrp->GroupCount;

if (EqualSid(ptokgrp->Groups[i].Sid, sidAdmin) && (ptokgrp->Groups[I]. Attributes & SE_GROUP_ENABLED)){ flsAnAdfflin = TRUE;

break;

} Хотя этот код и лучше, но единственный приемлемый способ выполнять по добную проверку в Windows 2000 и последующих ОС — вызов CheckTokenMember sbip. Итак, если объект защищается посредством ACL, предоставьте операционной системе выполнять проверку доступа и не изобретайте собственных почти заве домо несовершенных механизмов.

Обеспечьте поддержку длинных паролей Если ваше приложение принимает пароли для прохождения аутентификации Windows, не ограничивайте программно длину пароля 14-ю символами. До Win dows 2000 системы этого семейства поддерживали пароли длиной до 14 знаков, но в Windows 2000 и последующих ОС разрешаются пароли длиной до 256 сим волов (иногда с учетом завершающего NULL). Оптимальное решение для хране ния паролей в Windows XP — задействовать возможности компонента Stored User Names and Passwords (Сохранение имен пользователей и паролей) (см. главу 9) Будьте осторожны с alloca Функция _аиоса выделяет динамическую память в стеке. Выделенное простран ство освобождается автоматически при выходе из вызывающей функции, а не при Общие методы обеспечения безопасности ГЛАВА выходе выделенной памяти из области видимости. Вот типичный фрагмент про граммы с _alloca.

void function(char *szData) { PVOID p = _alloca(lstrlen(szData));

// Выполняем операции с р } Если атакующий предоставит большое значение szData, больше размера сте ка, _alloca инициирует исключение, вызвав тем самым остановку приложения.

Подобное особенно опасно, если это серверный код, Более корректный способ поведения с подобными ошибками — заключить _а!1оса в обработчик исключений и в случае ошибки восстанавливать стек:

void function(char *szData) { try { PVOID p = _^alloca(lstrlen(szData));

// Выполняем операции с р } „except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCodeO) ?

EXCEPTION_EXECUTE_HANDLER :

EXCEPTION_CONTINUE_SEARCH) { _resetstkoflw();

Макросы преобразования в ATL Следует быть осторожным с некоторыми макросами преобразования строк из библиотеки ATL, так как они также вызывают _а!1оса. ЭтоА2№, W2A, CW2CTn дру гие. Если речь идет о серверном коде, не вызывайте этих макросов без предвари тельной проверки длины данных. Это еще одно подтверждение того, что не сле дует слепо доверять вводимым данным, В ATL 7.0 из состава Visual Studio.NET 2003 поддерживаются макросы преоб разования строк, которые выгружают данные в кучу, если объем исходных дан ных слишком велик. Максимальный разрешенный размер указывается при созда нии объекта класса:

Sinclude "atlconv.h" LPWSTR szwString = CA2WEX<64>(szString);

Следует заметить, что в С# есть конструкция stackalloc, которая похожа на _alloca.

Однако stackalloc поддерживается только тогда, когда программа компилируется с параметром /uiisafe, а функция отмечена модификатором unsafe-, public static unsafe void FibonacciO { int* fib = stackalloc int[100];

int* p = fib;

*p++ = *p++ = 1;

for (int 1=2;

i<100;

++i, ++p) *P = p[-1] + p[-2];

Особые вопросы 606 Часть IV f o r (int 1=0;

i<10;

++1) Console.WriteUne (fib[i]);

' Никаких внутрикорпоративных имен в приложении!

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

#ifdef INTERNAL_USE_ONLY ft ifndef.DEBUG error "Нельзя скомпоновать код для внутреннего использования или не для отладки" Я endif //.DEBUG // Здесь размещается "экспериментальный" код Sendif // INTERNAL.USE.ONLY Примечание В этом примере есть дополнительные «пред охранители»: компи лятор не сможет выполнить свою задачу, если код компилируется для внутреннего использования или не для отладки.

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

• стандартные DNS- и NetBIOS-имена серверов;

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

• имена доменных учетных записей, например EXAlR\account и account@explora tionair.com.

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

ГЛАВА 23 Общие методы обеспечения безопасности Ведение журналов в приложении Подчас информативность журналов становится тем. что отделяет способность обнаружить и отследить атаку от полной беспомощности перед угрозой. Журна лы, будь то файлы событий или более детализированные журналы, подобные тем.

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

Знайте: DNS- и NetBIOS-имена часто недостаточно информативны, поэтому не плохо помимо них заносить в журнал и IP-адреса.

Раз уж речь зашла об IP-адресах, то замечу, что, если в приложении на при кладном уровне есть информация об IP-адресе источника, а также известно имя источника, регистрировать следует оба значения. Расскажу о проблеме, которую обнаружил у журналов службы терминалов: она регистрировала IP-адрес пользо вателя, не пакета. Но что, если пользователь располагается за сервером преобра зования имен (NAT) или брандмауэром? IP-адрес может оказаться частным, нап га мер 192.168.0,1. Это не сильно поможет при выяснении источника подключения!

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

Решение о месте хранения информации — в поддерживаемом ОС системном журнале Application Log (Журнал приложений) или в собственных журнала?: — зависит от объема данных. Если информации много, следует позаботиться о соб ственных файлы, так как объем системных журналов жестко ограничен. Есть еще одна сложность с системным журналом приложений: до Microsoft Windows.NET Server 2003 эти журналы были доступны через сеть любому прошедшему аутен тификацию пользователю. Поэтому следует назначать более жесткие ACL и.за прещать сетевым пользователям доступ по умолчанию к этим журналам. С исклю чительной осторожностью относитесь к размещению в Application Log конфиден циальной информации, К дополнительным рекомендациям следует отнести совет размещать журна лы в определяемом пользователем каталоге, причем лучше каждый день создавать новый журнал. Иногда предпочтительнее создать несколько журналов: один.для обычных событий, а другой для размещения детальной информации об экстра ординарных событиях. Прикладные журналы должны быть доступны для изменения только администраторам и пользователю, в контексте которого выполняется служ ба. Конфиденциальная информация и критичные для безопасности сведения не должны оказаться доступными обычным пользователям.

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

Часть IV Особые вопросы Превратите опасный код на C/C++ в управляемый В процессе многих кампаний по безопасности в Microsoft мы настойчиво пропа гандировали выявление и при необходимости перенос опасных компонентов, написанных на С или C++, на С# или другой управляемый язык. Это не означает, что код автоматически станет безопасным, но некоторые классы нападений — скорее всего атаки с переполнением буфера — станет намного труднее эксплуа тировать. Это же верно по отношению к DoS-атакам на серверы, которые возможны из-за утечки памяти и других ресурсов. Вы должны выяснить, какие части прило жения можно превратить в управляемый код.

ГЛАВА Документация по безопасности и сообщения об ошибках ^_7то очень важная глава, в которой аккумулирован опыт массы экспертов в об ласти документирования из самых разных групп в Microsoft. Глава состоит из двух основных частей: анализа безопасности в документации и сообщений об ошиб ках. А собраны эти, казалось бы, довольно разные темы в одну главу потому, что чаще всего технические писатели, отвечающие за создание документации, зани маются и написанием текстов сообщений об ошибках. Самые неудачные сообщения об ошибках — это, как правило, вина программистов, поленившихся проконсуль тироваться с профи, занимающимися поддержкой и обучением пользователей!

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

Безопасность в документации Ясно, что крайне важно рассказать пользователю, как повлияет на безопасность использование той или иной функции приложения, особенно если она отключе на по умолчанию. Однако пользователи, как правило, не заглядывают в докумен Особые вопросы 610 Часть IV тацию, пока не грянет гром, Так что если вы настроите продукт на рабо'гу с наи меньшими привилегиями и с безопасными параметрами по умолчанию, ваши пользователи обнаружат, что многое из того, что «только что работало», больше не доступно. Им ничего не останется, как обратиться к документу, где (надеюсь, вы об этом позаботились) описано, как развертывать и использовать приложение, чтобы оно работало максимально безопасным образом.

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

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

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

Ясность. Информацию о безопасности следует поместить в соответствующем месте и на соответствующем уровне структуры документа. Четко и без утайки расскажите об известных опасностях и риске, которому подвергается продукт.

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

Краткость. Снабдите пользователя пошаговыми инструкциями по безопасной работе с приложением. Не перегружайте их лишней информацией, например об особенностях шифрования открытым ключом или как инвертируется не полиномиальная хэш-функция. Пользователей больше интересует практичес кая сторона вопроса, нежели теория, которой и так посвящена масса книг. Для ГЛАВА 24 Документация по безопасности и сообщения об ошибках полноты предоставьте ссылки или библиографический список книг для инте ресующихся деталями. Таким образом, пользователи найдут в документации только то, что они должны знать для выполнения задачи, и где найти допол нительную информацию, чтобы глубже понимать суть вопроса, В процессе редактирования редакторы и писатели должны помнить: следует приложить все силы, чтобы документация была достоверной. Поэтому они долж ны разбираться в моделировании опасностей и основных проблемах безопасно сти, коль скоро их обязанность писать и проверять соответствующие материал oi.

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

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

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

Помните: выпускать приложение с небезопасной конфигурацией по умолча нию, предполагая, что пользователи прочитают документацию и защитят себя сами — отвратительная идея. Вы должны бить в набат, обнаружив, что в качест!*е ответных мер на многие опасности предлагается «читать документацию». Хотя необходимость написать горы скучнейшей документации и обеспечит вас рабо той, но СОСЛУЖИТ ПЛОХУЮ услугу вашим клиентам.

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

Проверенные методы обеспечения безопасности за счет документирования Документируя приложение (или его подсистему), предусмотрите раздел «Прове ренные методы обеспечения безопасности*, в котором опишите, как использова гь приложение (или подсистему), чтобы защититься от тех или иных угроз. Стоит также заставить администраторов приложения мыслить в терминах конкретных опасностей, В следующем примере демонстрируется решение проблем безопасности, свя занных с развертыванием вымышленного серверного приложения SOAP-Serve:1.

Часть IV Особые вопросы ЮАР-Server позволяет клиентам удаленно выполнять расположен ные на сервере SOAP-сценарии.

По умолчанию SOAP-Server выполняет код в контексте безопас ности серверного процесса. В некоторых случаях коду предостав ляется больше привилегий, чем хотелось бы (например, право открывать сокеты). Однако иногда привилегий не хватает для успешного выполнения операции (например, нет доступа к чте нию нужных пользовательских файлов). Всегда выполняйте код с наименьшими возможными привилегиями, необходимыми для выполнения задания. Инструкции по конфигурированию контек ста, в котором выполняется SOAP-сценарий, см. в разделе «Кон фигурирование среды выполнения».

Иногда SOAP-Sen>er и клиент обмениваются конфиденциальными данными, а значит, последние подвергаются угрозе раскрытия.

В этом случае желательно устанавливать флажок Encrypt Communications для соответствующего сценария. Это задейству ет протокол TLS и защитит канал связи между клиентом и SOAP Server прослушивания. Для дополнительной защиты годятся и другие технологии, например IPSec, вместо или в дополнение к 715.

В некоторых случаях требуется ограничить доступ определен ных клиентов к SOAP-сценариям. SOAP-Server позволяет ограни чить доступ на основе IP-адреса или идентификатора, проверя емого механизмом аутентификации. Инструкции по включению ограничений доступа вы найдете в разделе «Ограничение досту па» и «Аутентификация».

Примечание: если пользователи проходят аутентификацию, мож но реализовать дополнительный уровень защиты, применив списки управления доступом (ACL) в SOAP-сценариях. Чтобы получить информацию о применении ACL, выполните поиск в справочной системе Windows NET Sewer no ключевой фразе «Access Control List».

Клиенты подключаются к SOAP-Server через TCP-порт 80 (если сеанс не шифруется) или порт 443 (при защищенном сеансе). Если требуется разрешить SOAP-сценарии только в локальной сети, сконфигурируйте брандмауэр на удаление любых внешних TCP пакетов, адресованных SOAP-Server.

Если SOAP-Server управляет важными данными, подумайте о вы делении ему отдельного компьютера, на котором отключены все сервисы, не нужные для его работы. Это поможет сократить «площадь поражения» и снизить зависимость от функций, кото рые вы не контролируете, Вам может показаться неочевидным, но эта документация родилась при про верке модели опасностей. Ниже я привожу выдержку из модели опасностей. Каж дой ситуации соответствует отдельный абзац документации.

ГЛАВА 24 Документация по безопасности и сообщения об ошибках Опасность №4: слишком много привилегий у учетной записи ISQAPjocx Процесс SOAP-Server запускается от имени учетной записи 1$ОАР_<имя_машшш>, у которой может оказаться больше возможностей и привилегий, чем необходи мо для выполнения задачи. Таким образом, возможна атака с целью неправомоч ного превышения привилегий. Вероятность реализации опасности невысока, но вполне реальна.

Опасность №13: канал между клиентом и сервером не защищен При передаче между клиентом и сервером данные не защищены от раскрытия и подлога. Инструменты администрирования позволяют включить SSL/TLS, но го умолчанию эти протоколы отключены.

Опасность №14: по умолчанию SOAP-Server доступен всем Чтобы облегчить работу с приложением, аутентификация для доступа к SOAP-Server не выполняется и доступ к системе не ограничивается конкретными диапазона ми IP-адресов и DNS-имен. Этого сделать нельзя, поскольку наперед не известно, имеется ли пользовательская политика и установлен ли брандмауэр. В следующей версии надо создать мастер установки, который и задаст нужные вопросы пользо вателю.

Опасность №19: приложение тестировалось только на специально выделенных серверах Не представляется возможным оттестировать SOAP-Server во всех возможных комбинациях сервисов и приложений на компьютере под управлением Micro soft Windows.NET Server 2003- Все. что нам известно: некоторым сервисам требуют,:я для работы возможности, из-за которых ЮАР-Server окажется незащищенным.

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

Очень часто сообщения об ошибках защиты сбивают пользователя с толку и никак не помогают понять, в чем же проблема и что следует делать. В чем же причина низкого качества подобных сообщений? Под термином «сообщение об ошибке* я понимаю все виды информационных окон, включая предупреждения, подтверждения, вопросы и информацию о состоянии (статус). Большая часть сказанного применима также к записям в журнале. Сейчас я познакомлю вас с трудностями при написании сообщений для функций, связанных с безопаснос тью, и необходимой для его создания информации и дам несколько советов по проектированию и отображению сообщений, связанных с безопасностью, Часть IV Особые вопросы Типичное сообщение об ошибке На рис. 24-1 показано типичное неудачное сообщение об ошибке безопасности типа «подтверждение».

?j This page is accessinfl utotmatian mat is not игнег it :onffd This poses a secunty risk Do you wan! К Рис. 24-1- Пример распространенного, по плохого сообщения об ошибке* Это окно с уведомлением, причем оно содержит некое подобие объяснения.

Пользователь вправе продолжить просмотр страницы, щелкнув кнопку Yes, или проявить осторожность и щелкнуть No. Позвольте мне показать (рис. 24-2), что на самом деле «видит» пользователь, читая сообщение на рис. 24-1.

Do you wan! to get the job dor»?

Рис. 24-2. Как на самом деле пользователь воспринимает информацию** Что же «не так» в этом сообщении? Оно задает вопрос, на который невозмож но дать осмысленный отпет. Ему говорят, что Microsoft Internet Explorer собира ется отобразить страницу и исподволь подталкивают отказаться от ее загрузки как самой формулировкой, так и выбором по умолчанию кнопки No. Однако риск для безопасности, которому подвергает загрузка страницы, никак не конкретизиро ван, и последствия продолжения загрузки не ясны. Короче: сообщение плохое, потому что не предоставляет пользователю достаточно информации для приня тия правильного решения. Следовательно, оно вообще бесполезно.

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

Перевод текста в информационном окне: "Страница обращается к неподконтроль ной ей информации. Это опасно. Продолжить?* Перевод текста в информационном окне: "Заинтересованы ли вы вообще в выполне нии задачи?» ГЛАВА 24 Документация по безопасности и сообщения об ошибках Если вы уделяете достаточно внимания сообщениям об ошибках, то узнаете, как много из них удается почерпнуть, если они реализованы из рук вон плохо, или как остаться «при своих», когда сообщения написаны корректно. Вот нагляд ный пример. Вы ввели неправильный пароль при входе в систему. И хотя Windows в состоянии точно определить, что не так с паролем, предоставление этой инфор мации чревато раскрытием информации о нем. Поскольку пароль остается в бе зопасности, пока держится в секрете, его никогда нельзя отображать или описы вать каким бы то ни было способом. Поэтому вместо предоставления информа ции, что не так с введенным паролем, Windows отобразит сообщение, показан ное на рис. 24-3.

1Ье password и intoпеЛ. Ptesse 'etype /our password. 1*ЙМ8 1 passweed яшЯ be typed usingBie eoc red. case, Рис. 24-3- Пример «правильного* сообщения об ошибке, предотвращающего раскрытие информации* Это хороший пример того, каким должно быть полезное сообщение об ошиб ке, даже в случае работы с конфиденциальными данными. Оно содержит:

• уведомление о проблеме (неправильный пароль);

• объяснение причин возникновения проблемы (явно говорится о вводе невер ного пароля);

• способ решения проблемы (ввести пароль заново, уделив особое внимание регистру символов).

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

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

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

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

"* В русскоязычных версиях Windows ошибка ввода пароля часто обусловлена непра вильно выбранной раскладкой клавиатуры. — Прим. перев.

21- Особые вопросы 616 Часть IV требуют обстоятельства. Microsoft Internet Information Services (IIS) раньше ото бражал синтаксические ошибки, предоставляя всем пользователям специальную страницу с описанием проблемы и отрывком исходного кода, где случилась не поладка. В этом случае взломщик получает массу полезной для себя информации.

Гораздо лучше предоставлять эту информацию только тем, кому она нужна (в данном случае — разработчику приложения), а всем остальным пользователям предоставлять стандартное сообщение об ошибке. Именно так IIS и ведет себя сейчас.

Информированное согласие Нельзя все плохие сообщения об ошибках огульно обвинять в раскрытии инфор мации. Посмотрите на одно из самых отвратительных на мой взгляд диалоговых окон (рис. 22-4) с запросом на добавление сертификата в корневое хранилище.

Ооуац want fa ADD (he tdk*»t;

;

>"^ Ciiti t,: JSI ':.d!lf TiraeVaidte:

Рис. 24-4- Идиотское сообщение об ошибке, перегруженное информацией Кроме выбранной по умолчанию кнопки No, это сообщение не дает пользо вателю никакой информации о том, что же делать дальше. Если уж на то пошло, то вообще непонятно, что предлагается. Как и в первом примере, задается воп рос, на который нельзя дать осмысленный ответ. Какая-то куча маловразумитель ной информации. А что она означает? Когда на ее основании следует отвечать «Yes*?

А когда «No»?

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

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

ГЛАВА 24 Документация по безопасности и сообщения об ошибках • что на самом деле предлагается сделать и как это связано с задачей, которую я пытаюсь выполнить;

• насколько серьезна проблема с безопасностью:

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

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

• если я ошибусь при выборе ответа, смогу ли я исправить проблему позже? Если да, то как:

• какой выбор рекомендует программа? Почему?

Решение вопроса безопасности без информированного согласия лишено смыс ла. Большинство пользователей почти ничего не знают о безопасности и дове рии. Они лишь хотят выполнить свою работу безопасным образом;

это справед ливо и в отношении системных администраторов, но только не очень крупных организаций. Сочиняя сообщения о проблемах с безопасностью, рассчитывайте на полных «чайников*, если только ваша программа не предназначена специа/ъ но для экспертов по безопасности.

На рис. 24-5 показана улучшенная версия сообщения корневого хранилища сертификатов, помогающая пользователю ответить на большинство вопросов.

You are about to install a root certificate from a cerHf4cat>Dn authority (CA) claiming to represent;

Acme Incorporated Windows cannot validate that the certificate is actually fram Acme Incorporated. If you have actf doubt about Bus validity of ttis certificate, you should confirm its crigtnby contactlftg Лете [ncorporated before installing.

If you installing root certificate, Windows automatical)-trusts any certificate issued by this certification authority. *o installing an invalid certificate к а significant security Uric.

Do you want to instafi this root certificate? Click Yes if you believe the certificate 15 valid, otherntse dick NO.

Рис. 24-5. Улучшенная версия сообщения об установке корневого сертификата * «Установка корневого сертификата.

Вы собираетесь установить корневой сертификат центра сертификации, который, по всей видимости, представляет компанию Acme Incorporated.

Windows не в состоянии убедиться, действительно ли этот сертификат принадлежит компании Acme Incorporated. Если вы сомневаетесь в подлинности сертификата, пе ред установкой выясните его происхождение, напрямую связавшись с Acme Incorporated.

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

Установить этот корневой сертификат? Если вы уверены в происхождении сертифи ката, щелкните Yes, в противном случае — No.» — Прим, перев.

Часть IV Особые вопросы Я понимаю, что это довольно большое сообщение, но зато оно детально разъяс няет суть вопроса, возможные последствия для безопасности в каждом случае. Нет никакого смысла его сокращать.

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

Лучший способ предоставить всю информацию, не доводя при этом пользо вателя до умопомешательства, — последовательное раскрытие (progressive disc losure). Основное сообщение должно содержать минимум информации, необхо димый для осознанного ответа на заданный вопрос. Все сверх того следует пре доставлять по требованию, разместив в информационном окне гиперссылку или специальную кнопку (и).

На рис. 24-6 показана версия сообщения с применением последовательного раскрытия — со ссылками на дополнительную информацию.

"" ' Vouare aboytto installs f«A certificate from a certification aiihorSytCA) claiming to represent;

Ac we Incorporated I View сейЙса1в..с^Ц$ Windows cannot validate thai tie certificate it aehwlh1 from Acme tnroreorated. if you bays any doubt about tt»;

valdly of ENs certificate, you should Confirm its origin by contacting Acme Incorporated beFwe installing. Learn more «bout t^ffl, *!9. У й№в!. f ff jjf JfflteE • IT you install this root certificate, Windows automatically trusts any certificate issued by this certification authority, to installing an invalid certificate is a significant security risk.

Do you want to Install this f«t ortfieate? Q«k Vec J you believe the certificate Is vsH click NO.

i Рис. 24-6. Сообщение об ошибке, в котором применяется метод последовательного раскрытия Будьте конкретны Большинство сообщений можно улучшить, значительно конкретизировав их. Это особенно справедливо в отношении сообщений об ошибках. Вернемся на мину ту к самому первому примеру плохого сообщения-подтверждения (прежде чем чи тать дальше, не поленитесь еще раз взглянуть на рис. 24-1).

Как уже говорилось, сообщение на рис. 24-1 ужасное, поскольку не дает ника кого представления о возникающем риске. Давайте подправим его, просто конк ретизировав (рис. 24-7).

ГЛАВА 24 Документация по безопасности и сообщения об ошибках Thl! радей accessing шгсттйюп that is not under its contra!, which poses a security risk. For example, this page might owe unauthorized жхея to any sensitive information you enter, Leaf rt more cfeout peteMi Ун should not Cbntinue if you do not know or trust the developer of this page.

Doyeywaritto corsage? •...

Рис. 24-7. Сообщение об ошибке с конкретизированной информацией* Эта версия сообщения информирует о наиболее вероятном риске для безопас ности, который следует принять во внимание, и дает гиперссылку на ресурс с дополнительной информацией о риске, а также совет, как следует поступить.

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

Сообщения о безопасности не всегда удается выразить в двух словах. Крат кость — сестра таланта, но, когда речь идет о безопасности, не надо стараться бы гь «•слишком талантливым», Запомните основной принцип: проблемы с безопасностью всегда заставляют пользователей нервничать, а большинство сообщений, которые они видят, выглядит так:

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

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

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

Узнайте больше о потенциальном риске для безопасности, связанном с этой страни цей.

Ни в коем случае не продолжайте, если не знаете разработчика страницы или не доверяете ему.

Продолжить?» — Прим, перев.

620 Особые вопросы Часть IV Подумайте, может, вообще обойтись без вопросов Есть веские причины вообще избегать вопросов, связанных с безопасностью, потому что пользователи просто не в состоянии принять правильное решение в отношении доверия. Но какие варианты есть? Очевидный выход — вообще не задавать вопросы. Так стоит поступать, когда вы точно знаете, как пользователю следует себя вести в конкретной ситуации.

Например, если пользователь удаляет сертификат на вкладке Content (Содер жание) диалогового окна Internet Options (Свойства обозревателя) в Internet Explorer, можно спросить, надо ли удалить соответствующий сертификату секрет ный ключ. В команде по безопасности Windows в Microsoft пришли к выводу, что это надо делать всегда, и поэтому никаких вопросов не задается. Вот и чуднень ко — одним неудачным сообщением меньше.

Другой вариант — определить высокоуровневую политик}- безопасности и не запрашивать у пользователя разрешение по поводу и без повода. Подобный под ход настраивается на вкладке Security (Безопасность) диалогового окна Internet Options в Internet Explorer (рис. 24-8).

оо Мвя« LocdnmH Tlustedaei Reslriclec Intnno* This zone ссшлт ulWeb ^itei yrj ( haven't placed г olher lute;

- Sate browsing an '.,.i • Prompt;

before down -.3- •-;

pol;

-rially ure • Unsigned ActiveX саам я* пи be downloaded Appropriate lor most I "lane: :)=:

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

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

• понятен ли контекст сообщения;

• понятен ли текст сообщения;

• осознал ли пользователь уровень риска для безопасности;

• получил ли пользователь все необходимые сведения для информированного выбора;

• помогла ли ему информация или, наоборот, сбила с толку;

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

• какое решение он принял и почему;

• уверен ли пользователь в правильности принятого решения;

• понимает ли он последствия этого решения;

• оказалось ли решение правильным в тех или иных обстоятельствах?

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

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

• описания брешей в защите клиента, устраненные за счет внесения изменений в проект или код;

• описания особенностей архитектуры, по которым хакер сможет догадаться о существовании дыр в защите;

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

• множество способов выполнения определенной операции, причем в специри кации нечего не говорится о том, какой из них наиболее безопасный;

622 Часть IV Особые вопросы • описание сценария, в котором новая функция не будет работать без пониже ния уровня безопасности;

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

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

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

Вот пример. Если у вас установлена Windows XP или Windows 2000, откройте Control Panel (Панель управления) и в папке Administrative Tools (Администриро вание) дважды щелкните значок Local Security Policy (Локальная политика безо пасности). Вы увидите множество параметров, настройка которых позволит сде лать систему более (или менее) устойчивой к атакам. Последовательно выберите папки Local Policies (Локальные политики) и Security Options (Параметры безо пасности). Масса интересного, но что все это означает? Скажем, вы решили вклю чить параметр Do not Allow Anonymous Enumeration of Accounts and Shares (He разрешать перечисление учетных записей и общих ресурсов) в разделе Network Access (Сетевой доступ). Каковы последствия этого? Что перестанет работать? Какие реальные ограничения при этом налагаются? Щелкнув параметр правой кнопкой и выбрав в контекстном меню команду Help (Справка), вы попадете в раздел Security Settings (Управление параметрами безопасности), где прекрасно написано об этом параметре.

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

Управление безопасностью в масштабах целого предприятия еще проблема тичнее. Настроить безопасность одного сервера очень просто, но проделать то же самое на 1000 серверах очень трудно (или вовсе невозможно). Возможность легко администрировать большое число систем следует предусмотреть на ранних стадиях проектирования и ни в коем случае не пренебрегать ею. Подумайте о создании административной консоли, подобной оснастке для управления поли тиками безопасности Active Directory, в которой системы можно объединять в группы и управлять ими всеми одновременно. Кроме того многие системы адми нистрируют при помощи небольших приложений и сценариев — не забудьте предоставить доступные удаленно интерфейсы, позволяющие управлять серверами программно.

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

ЧАСТЬ V Приложения ПРИЛОЖЕНИЕ А Опасные API-функции ]У1ногие люди упорно считают некоторые API-функции опасными, И хотя некор ректные вызовы отдельных функций действительно могут иметь опасные послед ствия, вы уже знаете, что просто запрещать, объявлять «вне закона» или препят ствовать их применению полезно, но не достаточно для повышения безопаснос ти кода. Более того, это создает ложное чувство защищенности. Как показано в главе 5 на примере ошибки занижения размера буфера на единицу, даже доста точно надежные функции при некорректном использовании оставляют прекрас ную лазейку для взломщиков. Но все же многие проекты удалось в некоторой сте пени защитить, отказавшись от трудно поддающихся безопасному использованию функций, Дэйв Катлер (Dave Cutler), главный архитектор Microsoft Windows NT, как-то заметил, что нет опасных функций, а есть бестолковые — и поэтому опасные — программисты. Пожалуй, он прав. Саедует учитывать побочные эффекты и нюан сы используемых функций, поэтому в этом приложении описаны наиболее по пулярные из них. Посмотрим правде в глаза: некоторые разработчики вообще не способны создавать безопасный код, каждый день у них выдается «черным*, и им следует подумать о смене занятия, например стать менеджерами проектов! У бо лее ценного меньшинства программистов всего один «плохой» день (когда они делают много ошибок) на сотню, А нам, подавляющему большинству посредствен ностей, стоит выбирать те функции и классы, при использовании которых веро ятность совершить ошибку низка. А если к этому добавить глубокое понимание этих функций, то в результате удастся уменьшить количество ошибок на порядки.

Важнее всего понимать, что большинство проблем с безопасностью возника ют из-за слепого доверия данным, введенным пользователем. Необходимо конт ролировать, какие данные приходят в программу, и четко представлять послед ствия обработки этих данных. Можно писать вполне безопасный код, пользуясь Приложение А Опасные API-функции так называемыми «опасными* функциями, при условии, что данные стопроцент но корректны и им можно полностью доверять.

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

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

В этом разделе описаны некоторые «чемпионы» в этой области, strcpy, wcscpy, Istrcpy, _tcscpy и jnbscpy — эти функции не проверяют размер буфера-приемника и значение указателей, не отметают •указателей на null ил i с другими некорректными значениями. Если буфер-источник не завершается нулем.

результат такой функции непредсказуем. Настоятельно рекомендую применять n-версии (название которых начинается с п) этих функций из библиотеки strsqfe.

,-^^ццдщдцдцы.шицншц.цыJAXI^ ШИВИЕИИ^ЯИШИ -„j.fj.^tfXZgX^rj^mn Внимание! Сами по себе n-версии функции из библиотеки strsafe не гаранти руют безопасность кода;

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

strcat, wcscat, Istrcat, Jcscat и jnbscat — те же рекомендации, что для преды дущего семейства.

strncpy, wcsncpy, Jcsncpy, Istrcpyn и jnbsnbcpy — нет никакой гарантии, что эти функции завершат нулем буфер-приемник. Они также не отбрасывают указа телей на null или другие некорректные значения.

strncat, wcsncat, Jcsncat и jnbsnbcat — убедитесь, что число копируемых сим волов равно числу символов, оставшихся в буфере, а не размеру буфера. Этим функциям необходимо, чтобы буферы — источник и приемник — завершались нулем, тетеру и СоруМетогу — размер буфера-приемника должен быть достаточн ым для размещения числа символов, указанных в аргументе Length. В противном слу чае не исключено переполнение буфера. Подумайте о применении _тетсру>, если заведомо известно, что копировать придется исключительно в определенный на бор символов.

sprint/и swprintf — эти функции не гарантируют завершения нулем буфера приемника. Если нет жесткого определения размера полей, крайне тяжело обес Приложения 628 Часть V печить безопасную работу этих функций. Подумайте об использовании вместо них функции StringCchPrintf.

_snprint/H jsnwprintf— эти функции могут не завершить нулем буфер-прием ник. У них также наблюдаются проблемы с межплатформенной совместимостью, поскольку способ выхода (и завершения) зависит от платформы. Рекомендуется заменять эти функции на StringCchPrintf.

Семейство print/ъключаег? printf, ^sprintf, _$nprintf, vprintf, vsprint/и соответству ющие варианты для Unicode-символов. Проверяйте, чтобы в качестве строк фор мата не передавались предоставляемые пользователем строки. Кроме того, явное преобразование Unicode-символа в однобайтный с помощью спецификатора %s может привести к тому, что в результирующей строке оказывается меньше сим волов, чем во входной. Для более жесткого контроля над происходящим рекомен дуется применять WideCharToMultiByte, Также будьте бдительны со строками форматирования, содержащими висящие спецификаторы %s (например, sprintf(szTemp, "%d,%s",dwData,szString), посколь ку в этом случае последний аргумент так же опасен, как и strcpy. Предпочтение рекомендуется отдавать _snprintfl или StringCchPrintf.

strlen, _tcslen, jnbslen и wcslen — все эти функции в состоянии корректно об работать буфер только при условии, что он завершается нулем. Их вызов не при водит к <• эксплуатируемому» переполнению буфера, но способен вылиться в ошибку нарушения доступа, если функция попытается прочитать «бесхозную» память, gets родом из преисподней. С ней вам никогда не создать безопасного приложе ния, поскольку gets не проверяет размер копируемого буфера. Откажитесь от нее раз и навсегда! Взамен рекомендуется /gets. Или по крайней мере вызывайте getc в цикле и постоянно проверяйте диапазон, scanf("%s",...), _tscanf& wscanf — как и в случае с gets, трудно корректно ис пользовать scan/, _tscanf, и wscanf со спецификатором %$, поскольку он ничем не ограничивается. Вы, конечно, вправе ограничить размер строки, применив кон струкцию вроде %32s, но лучше заменить эти функции HZ/gets.

Оператор потока (») библиотеки STL копирует данные из источника ввода в переменную. Если входные данные недостаточно надежны, то в принципе возмож но переполнение буфера. Например, следующий код принимает данные из stdin (cin) и записывает их в szTemp, но если пользователь введет больше 16 байт, бу фер переполнится.

(finclude "istream" void main(void) { char szTemp[16];

cln » szTemp;

Ситуация так же безнадежна, как и в случае с gets. Применяйте альтернатив ные функции или ограничивайте размер вводимых данных посредством cin.width, MultiByteToWideChar — последний аргумент функции, определяющий количество Unicode-символов в строке, а не число байт. Передав число байт, вы завысите размер буфера вдвое. Следующий код некорректен:

Приложение А Опасные API-функции WCHAR wBzName[NAME_LEH];

MultiByteToWideCharC sizeof(wszName));

Последний аргумент должен быть $izeof(wszName)/sizeqf(wszName[Q]) или просто NAMEJJEN, но не забывайте зарезервировать место для завершающего символа, если он необходим.

jnbsinc, _mbsdec, jnbsncat, jnbsncpy, _mbsnextc, _mbsnset, _mbsrev, _mbsset, _mbsstr, _mbstok, _mbccpy u^mbslen — эти функции работают с многобайтны ми (чаще всего) и двухбайтными символами и способны вызывать ошибки при обработке некорректных данных, например когда за старшим байтом следует нуль вместо нормального завершающего байта. Вы можете проверить наличие перво го и/или завершающего символа, используя функции isleadbyte, _ismbstead и _ismb$ trail. Также может быть полезна функция _mbbtype.

API-функции, ненадежные по отношению к манипулированию именами CreateDirectory, CreateEvent, CreateFile, CreateFileMapping, CreateHardLink, CreateJobObject, CreateMailslot, CreateMutex, CreateNamedPlpe, CreateSemap bore, CreateWaitableTimer, MoveFile и классы, инкапсулирующие эти фуи кции. Любой вызов API-функции, в ходе которого создается нечто, имеющее имя, подвержен атакам с манипулированием именами (name-squatting). У проблемы два аспекта. Во-первых, взломщик в состоянии угадать, какой файл или иной объект будет создан, и заблаговременно создать и «подсунуть* свои с таким же именем.

Например, если во время редактирования текстовый процессор создает файл в папке c:\temp с именем, которое легко предугадать, взломщик может заранее со здать такой файл с разрешениями на чтение и затем манипулировать моим фай лом. Возможна и другая атака, которая состоит в том, что взломщик создает ссылку на файл, на запись которого у него нет прав, и заставляет администратора уда лить файл или, того хуже, изменить разрешения. Большинство подобных атак удается избежать, предоставив каждому пользователю его «личное» временное пространство, в Microsoft Windows 2000 и более поздних это папка Documents and Settings. Если вам нужно создавать временные файлы или каталоги в общедоступ ной области, лучше всего генерировать действительно случайные имена. Еще одно решение (его применяют и совместно с предыдущим) — установить флаг СРЕА TE_NEWnpw создании файлов, который заставит функцию завершиться с ошиб кой, если файл уже существует.

Никогда не предполагайте, что файл или каталог не существуют, даже если проверили его наличие. Взломщик может воспользоваться временем между гро веркой существования и созданием файла. Может показаться, что промеж>ток слишком мал, и шансов успешной атаки практически нет, но не обольщайтесь!

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

Часть V Приложения Именованные каналы — еще один источник проблем, а все из-за того, что вла делец канала может олицетворять клиента, впрочем, все зависит от способа от крытия канала. Если в роли клиента выступает высокоуровневый процесс, есть вероятность самовольного повышения привилегий. Один из способов защитить ся от таких атак — открывать канал с флагом FILE_FLAG_FIRST_PIPE_1NSTANCE.

Имейте в виду: это возможно только в Windows 2000 SP1 и более поздних верси ях (см. главу 23).

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

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

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

CreateProcess(NUU,,.,.), CreateProcessAsUseruCreateProcessWitbLogon. Первый аргумент — путь к приложению, второй — командная строка. Если первый аргу мент null, а второй содержит пробел в пути к приложению, возможно выполне ние «не того» приложения. Например, если аргумент c:\Program Files\MyApp\My Арр.ехе, то при наличии соответствующего файла выполнится программа c:\Prog гат.ехе. Решение: указать путь к приложению в первом аргументе или заключить в двойные кавычки путь к приложению во втором.

WinExec и SbellExecute — эти функции ведут себя так же, как CreateProcess(NULL,...), и с ними надо быть особо осторожным.

LoadLibraty, LoadLibraryEx и SearcbPath — во многих версиях Windows при загрузке файлов поиск начинается с текущего каталога. Если попытаться загру зить DLL, указав неполный путь (например,//Уе.с#/ вместо c:\dir\dir\file.dl), програм ма сначала просмотрит текущий каталог, и если там окажется подложный файл, то загрузится именно он. В этих функциях рекомендуется всегда указывать пол ный путь.

Несколько советов: если ваши DLL располагаются в папке приложения, сохра ните путь к каталогу в реестре, чтобы обращаться к нему, когда требуется указать полный путь к библиотеке. Если DLL лежат в специальном каталоге операцией Опасные API-функции Приложение А ной системы, для поиска нужной DLL используйте функцию GetWindowsDirectary.

Pages:     | 1 |   ...   | 9 | 10 || 12 |



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

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