WWW.DISSERS.RU

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

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


Pages:     | 1 |   ...   | 4 | 5 || 7 | 8 |   ...   | 10 |

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

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

действительное в пределах домена независимо от того, какой это домен: Win dows NT 4, Windows 2000, Windows 2000 с Active Directory или Windows XP.

Для определения канонического имени пользователя можете вызывать функ цию как в этом фрагменте (см. папку ffinclude for (int i = NameUnknown ;

i <= NameServicePrincipal;

TCHAR DWORD dwLen = sizeof szName / sizeof TCHAR;

TCHAR = NULL;

case 0 enf = "NameUnknown";

break;

case 1 enf = break;

case 2 enf = break;

case 3 enf = break;

case 4 enf = break;

case 5 enf = break;

case 6 enf = break;

case 7 enf = case 8 enf = break;

default • "Unknown";

break;

: enf BOOL fRet = if (fRet) { в формате szName, else сбой enf, '• He удивляйтесь, если увидите ошибки;

некоторые расширенные форматы имен не относятся к пользователям.

ГЛАВА 11 Недостатки канонического И воздержитесь от принятия решений о предоставлении доступа основании имени пользователя. Если возможно, используйте Резюме Могу итог всему сказанному в этой главе одной фразой: й те решений, связанных с безопасностью, на основании какого бы то ни имени». Если не послушаетесь, наделаете ошибок и создадите дыры в защите. Если без подобных решений никак не обойтись, будьте предусмотрительны: четко сформулируйте критерий «правильности» запроса и принимайте только те, го удовлетворяют шаблону, а все остальные с негодованием отметайте.

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

И не говорите, что я вас не предупредил!

Ввод в базу данных приложения и Web-приложения в частности хранят постоянные дан ные в базах данных (БД). В таких Web-приложений и Web-серви сов так много, что практически невозможно говорить о них обособленно, не ка саясь баз данных. Поэтому в этой главе я расскажу о проблемах ввода данных в в основном на примере взаимодействующих с БД. (Глава полностью посвящена безопасности Web-приложений, не связанных с базами данных, но принимающих большие объемы данных.) Ключевой момент этой темы — доверие введенным данным и опасность атак с внедрением SQL-кода;

но прежде всего я расскажу историю.

В 2001 г. я делал две доклада на Microsoft Professional Developer's Con ference (Конференция профессиональных разработчиков на платформе Microsoft) в Лос-Анджелесе. Один из них был посвящен вопросам доверия в целом и про блемам ввода информации в БД и в в частности. Я обрадовал ся, обнаружив полную аудиторию уже за 15 минут до начала презентации. К на чалу выступления в аудитории яблоку негде было упасть, люди столпились в ко ридоре, пожарный их не разогнал, но сейчас не об этом. Полчаса спустя после начала доклада об атаках с внедрением SQL-кода, человек, сидящий в пер вом ряду, покинул аудиторию и вернулся минут через десять. По оконча нии он подошел ко мне и сказал, что работает в крупной страховой компании на Восточном побережье и отлучался, чтобы позвонить команде разработчиков баз данных и дать им указания немедленно внести исправления в код приложений.

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

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



Многие приложения содержат код, который выглядит так тесь, вы сами писали подобное);

string = "select * client where name = + name + Значение name пользователь. в том, что он может подставить в переменную пате другое SQL-выражение. он в результате чего получилась вполне благопристойная SQL-команда:

select * from where name = А что, если ввести следующее: or 1 = 1 — ? Получится такая строка:

select * from client where name = 1=1 - Эта команда вернет все строки таблицы содержащие значение поле пате. Вдобавок будут возвращены все строки, удовлетворяющие условию а это уж кому как понравится: плохие новости для хороших парней и хорошие новости для плохих, поскольку 1=1 истинно для всех строк в таблице, так что хакер увидит строки. Вам кажется, в этом нет ничего плохого? Тогда представьте, что схема таблиц БД выглядит, как показано на рис. 12-1,.

SO f Type Number | Address Apartment City \ Рис. 12-1. Схема таблиц с данными о содержащая информацию о кредитных картах 344 Часть II Методы безопасного кодирования В конце запроса стоят символы Это оператор комментария, который уп рощает хакеру задачу построения корректного, но тем не менее злонамеренного SQL-оператора. Сделав свое черное дело, то есть соорудив хакер ставит в конце строки оператор чтобы ядро данных игнори ровало все, что по замыслу программиста должно добавляться к выражению.

Примечание Оператор комментария поддерживают многие в том числе Microsoft SQL Server, IBM DB2, Oracle, PostgreSQL и Описанная атака, называется внедрением SQL-кода (SQL injection). В подобной ситуации изменяется логика SQL-выражения, в данном случае раз ница в добавлении выражения, присоединенного оператором or. Подобным ме тодом удается изменять не только единичные SQL-выражения, но добавлять до полнительные вызывать функции и хранимые процедуры, По умолчанию некоторые СУБД позволяют клиентским приложениям выпол нять более одного SQL-выражения за раз. Например, разрешается направить на SQL Server такое выражение:

select * select * table и сервер выполнит оба SQL-оператора select.

Хакеры могут намного больше, чем просто запускать на исполнение подряд несколько SQL-запросов. Большинство ядер СУБД поддерживают операторы ма нипулирования данными, в частности создания, удаления и обновления объектов БД: хранимых процедур, правил и видов. Посмотрите на «имя», которое может ввести хакер:

table client Результат — SQL-запрос, возвращающий запись с именем Blake, а затем удаля таблицу клиентов.

Во время демонстрации манипуляций с базами данных методом внедрения SQL кода на Professional Developer's Conference в 2001 году я случайно удалил табли цу, на которой и происходила демонстрация. Хоть я и лишился демонстрацион ной но эффект, произведенный на того стоил!

Вы, наверное, недоумеваете, как простой смертный пользователь в Интерне те, подключаясь к СУБД через Web-приложение или Web-сервис, может удалить таблицу? Взгляните на этот код:

string Status = "No";

string sqlstring = try < SqlConnection sql= new SqlConnection( sql.0pen();

+ - detail + Id ;

= new if != 0} Status = "Yes";

ГЛАВА Ввод в базу данных } catch (SqlException se) { Status = + e in { Status += + } } catch (Exception e) { Status = • Вы увидели дыры в этом отрезке кода на очевидна: SQL-выраже ния создаются за счет конкатенации строк, что приводит к атакам с внедрением SQL-кода. Но это еще не все. Имя пользователя в строке подключения са к данных — то есть учетная запись системного администратора Никогда не создавайте подключения к БД с использованием такой опасной учетной записи: sa для SQL Server то же самое, что SYSTEM для Windows NT и более поздних ОС. Обе учетные записи обладают максимально возможными полномочиями и способны принести непоправимый ущерб. в Oracle — учетная запись internal.

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

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

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

Псевдосредство заключение вводимых данных в кавычки Этот метод часто предлагается как панацея, предотвращающая ввод опасных дан ных в БД, но он определенно не работает как надо. Посмотрим, как он исполь ется и почему он так плох, int age = // Возраст, введенный пользователем.

name = // Имя, введенное name =, );

sql= new + FROM client WHERE name= + name + + age;

= new Как видите, код удваивает все одинарные кавычки в данных, введенных пользо вателем. Таким образом, если хакер попытается в качестве имени ввести будь вроде or 1 одиночная кавычка (отделяющая имя) 346 Часть II Методы безопасного ется, лишив провести атаку, поскольку до оператора комментария получается некорректное select * client WHERE ID = 1=1 -- age= Но это не спугнет нашего коварного хакера — для атаки он воспользуется полем age, к которому одиночные кавычки не добавляются. Например, age по его мило сти может стать 35;

Никаких кавычек, и сервер остановится. Обрати те внимание, что точка с запятой (;

) не 35 shutdown даст тот же ре зультат, так что не думайте, что, выкидывая точки с запятыми, вы лишите осу ее жала!

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

подобная следующей:

declare char(20) select Будучи присоединенной к другому SQL-запросу, эта конструкция формирует команду Последовательность символов — это эк вивалент shutdown в ASCII.

К чему я веду? Простое добавление кавычек в SQL-операторы в по могает, но далеко не всегда!

Внимание! Удаление определенных символов (в том числе кавычек) не тит от атак с внедрением Псевдосредство №2: хранимые процедуры Многие разработчики наивно что, вызывая хранимые процедуры из приложения, они атаки с внедрением SQL. Чушь! Эта мера пре дотвращает лишь некоторые виды атак, но бессильна перед остальными. Перед вами пример вызывающий хранимую процедуру string name // Имя, пользователем.

SqlConnection new sql.0pen();

+ name + ;

= new Попытка ввести or закончится неудачей, поскольку нельзя выпол нять соединение (join) между вызовами хранимых процедур. Следующий SQL синтаксис некорректен:

exec 1=1 -- ' Однако вот такое манипулирование данными абсолютно легально:

exec insert into client Эта SQL-команда получит данные о клиенте с именем Blake и вставит новую запись в таблицу клиентов! Как хранимые процедуры не сделают ваш код неуязвимым для атак с внедрением SQL-кода.

ГЛАВА в базу данных Я должен признать, что самый ужасный пример хранимой процедуры, приме няемой в целях безопасности, таков:

CREATE PROCEDURE AS Поняли, что делает этот код? Он просто выполняет то, что ввел Вот вам и вызов хранимой процедуры. К счастью, такие перлы мне встречались всего несколько раз.

К чему я все это рассказал? Вам следует знать о псевдосредствах — они помогают, но ни одно не защищает «на все сто». А теперь посмотрим гарантированные Средство никаких подключений к СУБД под учетной записью администратора Я уже указывал на ошибку создания подключения к SQL Server или любому друго му серверу БД от имени системного администратора из приложений вроде Web-сервисов или Web-страниц. Заметив такую строку подключения, д рапортуйте об ошибке и добивайтесь исправления. к из под администраторской учетной записью — вопиющее на рушение принципов наименьших привилегий и защиты на каждом этапе.

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

• удаление любой базы данных или отдельной таблицы;

• удаление любых данных из любых таблиц;

• модификация любых данных из любых таблиц;

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

• удаление журналов;

• добавление новых пользователей базы данных;

• вызов любых административных или расширенных хранимых процедур.

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

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

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

348 Часть II Методы безопасного кодирования Наверное, наибольшая опасность использования администраторской учетной записи заключается в возможности вызывать любые административные хранимые процедуры. Например, в SQL Server есть хранимая процедура позво ляющая хакеру запускать на исполнение команды оболочки. В Oracle имеется процедура предоставляющая возможность читать и писать в файловую систему, Примечание Создание подключения к БД от имени учетной записи — это не только ошибка. Это вопиющее нарушение принципа наименьших привилегий. Разработчики с удовольствием идут на это, так как при та ком подходе все работает само по себе и никаких дополнительных уси лий на конфигурирование сервера не требуется. Но не забывайте, что взламывается такая система тоже легко!

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

Средство №2: построение безопасных SQL-выражений Построение SQL-выражений программным путем довольно проблематично, впро я уже это продемонстрировал. Самый простой способ избежать проблем — переложить построение SQL-выражений на базу данных и не пытаться конструи ровать их в коде приложения. Следует использовать символы подстановки (place holder), которые часто называют параметризованными командами command). При написании запроса вы сами определяете, какие части SQL-выраже должны быть параметрами. Вот параметризованная версия запроса:

SELECT FROM client AND Затем следует присвоить конкретные значения параметрам, которые переда ются в БД вместе с SQL-запросом. Следующая функция на VBScript демонстриру ет использование символов подстановки;

Function ' Обратите внимание, я создаю доверенное к SQL Server, ' Никогда не используйте = + + + Set = strConn Set = = = "select client where name=? and означает ГЛАВА Ввод в базу данных = true Комментарии к числовым параметрам:

' тип данных - 200 строка переменной длины);

' - 1 (входной параметр);

' длина строки - 32 символа.

Set = 200, 1, 32, parml Set = 200, 1, 32, cmd. Append = Set rs = false If = 1 Then = true Function прочего, параметризованные запросы выполняются быстрее, чем скон в коде приложения SQL-запросы. Это тот редкий случай, удастся убить зайцев за раз: такие запросы и быстрее, и безопаснее!

Еще одно преимущество параметров — возможность указать для них тип дан ных. Например, если вы определите числовой то строгий контроль типов пресечет на корню множество SQL-атак, поскольку они невозможны с использо ванием одних только чисел, нужен еще и текст. Если приложение интерфейс ODBC и требуются применяйте функции и При с OLE DB задействуйте интерфейс Parameters. А если вы пишете управляемый код, то используйте класс Создание безопасных хранимых процедур Только что параметризованные запросы пригодны для доступа к БД из внешних приложений, таких как Web-сервисы. Однако иногда требуется выполнять те же действия в хранимых процедурах. Вам следует о двух простых механизмах, помогающих создавать безопасные выражения.

Во-первых, применяйте к именам объектов функцию выражение select top 3 name from превратится в select top 3 [name] from если вы выделите квадратными скобками пате и mytable. quotename это очень полезная встроенная функция (подробнее см.

цию SQL Server Books Online). Она выделяет имена объектов разделителями, ;

I.H неправильные символы. Результат ее работы можно запустив в SQL Analyzer приведенный далее пример. В этом примере также демонст что запрос обрабатывает ASCII-коды, о которых я говорил ранее в этой главе.

350 Часть II Методы безопасного кодирования declare set select set select set select set select Обратите внимание на значение переменной во втором блоке кода Она превратилась в безопасную строку, выделенную символами и Во-вторых, используйте sp_executesql для исполнения динамически созданных SQL-выражений, вместо того чтобы просто склеивать строки. Это не даст «нехо рошим* параметрам проникнуть в СУБД:

Попробуйте выполнить код с declare set = -- Выполняем работу.

exec sp_executesql N'select au_id where = Оба этих механизма поддерживаются в SQL Server, и разработчики, создающие хранимые процедуры, должны ими пользоваться, так как они обеспечивают до полнительный уровень защиты. Нельзя спрогнозировать, как ваши хранимые процедуры будут вызываться в будущем! Теперь по поводу защиты на всех уровнях:

давайте посмотрим, как следует писать код, удовлетворяющий этому принципу.

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

// // using System;

using using using using using ГЛАВА 12 Ввод в базу данных using using using static string Id) SqlCommand = null;

string Status = "Name Unknown";

try { // Проверить корректность переданного идентификатора (ID).

Regex r = new if throw new // Считать строку реестра.

SqlConnection new SqlConnection(ConnectionString);

// Добавить переданный ID-параметр.

string cmd = new = Status = catch (Exception e) { if == "127.0.0.1") Status = e.ToString();

else Status = "При обработке запроса произошла ошибка } finally // Закрыть даже в случае сбоя.

if (cmd != null) return Status;

// Получить строку internal static string ConnectionString 352 Часть II Методы безопасного кодирования get { return В этом примере несколько уровней защиты — несколько слов о каждом в от дельности.

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

• Приложению разрешено считывать только один определенный раздел реест ра;

другие операции с реестром запрещены.

• Код очень избирателен ко входным данным: от 4 до 10 цифр, и точка. Все ос тальное — в помойку.

• Строка подключения к БД хранится к реестре, а не в коде или в файлах Web сервиса (например, в файле конфигурации).

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

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

• Для построения запросов применяются а не конкатенация строк.

• Вводимые данные записываются в 64-разрядные целочисленные переменные (контроль типов).

• При сбое хакер не получает никакой информации кроме самого факта ошибки.

• Подключение к БД всегда закрывается, даже при сбое программы, Этот код кажется сложнее, чем есть на самом деле. Позвольте мне объяснить, почему этот код безопаснее, чем приведенный в первом примере. Я пока отложу объяснение атрибутов перед вызовом функции, Во-первых, код требует, чтобы введенный идентификационный номер пользо вателя (ID) содержал от 4 до 10 цифр. Это обеспечивается регулярным выраже нием которое пропускает только числа с количеством цифр от 4 до между началом и концом данных. Жестко определив входные данные и отклоняя все остальное, мы сильно обезопасили себя: хакеру просто не удастся добавить в идентификатор никаких SQL-выраже ний. Регулярные выражения в управляемом коде представлены в пространстве имен Код содержит также дополнительную защиту. Обратите внимание, что строка передаваемая объекту хранится в реестре. Посмотрите также па функцию доступа Чтобы узнать эту строку, хакеру не достаточно получить доступ к исходному коду Web-сервиса — потребуется доступ к соответствующему разделу реестра.

ГЛАВА 12 Ввод базу данных Данные раздела реестра представляют собой строку data initial Заметьте: база данных расположена на другом компьютере — Если хакеру удастся скомпрометировать Web-сервис, то даже в этом случае он не получит к SQL-данным. В придачу ко всему этот код не создает подключение от учетной записи напротив, для этого предназначена специальная учетная за пись с надежным (и страшным на вид) паролем, которой только право на чтение и исполнение соответствующих SQL-объектов в базе дан ных client. В случае компрометации подключения Web-сервиса к БД хакер жет запускать лишь несколько хранимых процедур и выполнять запросы к ным таблицам, ему не удастся повредить базу данных master или атаковать, уда ляя, вставляя или изменяя данные.

SQL-выражения не строятся помощи небезопасной техники конкатенации строк — для этого служат параметризованные запросы с вызовами хранимых хранимой процедуры быстрее и безопаснее, чем конкатенации строк, поскольку имена базы данных и таблиц не выставляются на всеобщее обозрение, а хранимые процедуры оптимизированы для работы с яд ром СУБД, Когда возникает ошибка, пользователю (а возможно, хакеру) не сообщается ничего, кроме типа запроса — локальный или с компьютера с кодом Получив физический доступ к компьютеру, на котором работает Web-сервис, в любом случае можете делать с ним все, что угодно! Неплохо добавить код, доставляющий доступ к детальному описанию ошибки только user = if { // Пользователь администратор, // поэтому ему сообщать подробности.

Далее, подключение к БД всегда закрывается в блоке finally. Если в теле try/catch инициируется будет выполнено корректное закрытие что предотвратит угрозу атак отказа в обслуживании, обычная причина — слишком много открытых подключений.

Все приведенные в этой главе рекомендации являются общими и справедли вы практически для любого языка программирования. Теперь я хочу заострить ваше внимание на особой защите, имеющейся только в Framework — атрибуты В начале оператора вызова функции имеются два атрибута защиты. Первый, позволяет провайдеру SQL Server Provider убедиться, что уровень безопасности пользователя достаточный для к источнику данных — в данном случае это выполняется присваиванием свойс 354 Часть II Методы false, то запретом пустого пароля. Программа инициирует исключение при подключиться к SQL Server от имени учет ной записи с пустым паролем.

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

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

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

• Никогда не доверяйте данным, которые ввел пользователь!

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

• Для построения запросов применяйте параметризацию, а не строк.

• с хакером, предоставляя ему слишком много информации.

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

Проблемы ввода в Web-среде теперь пришло обратить взор на, пожалуй, самую агрессивную среду — Я расскажу, как гарантировать защищенность приложений, использующих Web в качестве транспортного механизма. вы ознакомились с главами и а если в вашем Web-приложении используются базы данных, то следует про читать и главу Практически все Web-приложения выполняют определенные действия в ответ на запросы пользователей. Сказать по правде. Web-приложение, не принимающее пользовательских данных, попросту говоря, бесполезно. Не забывайте, что следу ет четко определиться с тем, что такое «правильные входные и отвер гать все остальное. Я понимаю, что вам хочется сказать: «смени пластинку», ничего не поделаешь — проверка данных является одной из важнейших лин, и ее понимание — ключ к успешной разработке защищенных Вы узнаете о проблеме сценариев (вам это пригодится, так сценарии весьма популярны) и проблемах доверия в HTTP, а также о том, от ких опасностей защищают протоколы SSL (Secure Sockets Layer) и TLS Layer Security). Итак, за работу!

сценарии: когда выходные данные превращаются в монстров Я часто что кросс-сайтовые сценарии (cross-site scripting, XSS) очень но объяснить и сравнительно просто реализовать. Думаю, что пользователи плохо понимают сам механизм взлома: клиент компрометируется из-за дефектов в од ной или нескольких Web-страницах. Года три назад о них никто и не а 356 Часть II Методы безопасного кодирования сегодня каждый день в Web появляются сообщения об одной-двух ках. Так в чем же проблема и почему она такая серьезная? Она зиждется на двух • Web-сайт доверяет данным, поступившим из внешнего ненадежного источника;

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

Держу что вам видеть такое:

Hello, Этот код выведет в браузере все, что передано в поле пате в на пример На первый взгляд — ничего страш ного, но что, если хакеру удастся убедить пользователя щелкнуть эту ссылку, на пример, на Web-странице, в новостной группе или в теле сообщения электрон ной почты? Вроде тоже, кажется, ничего страшного, но лишь до момента, когда вы поймете, что ссылка может оказаться такой:

<а Выиграй 000 000 где блок такой:

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

Выиграй $1 000 000 Кажется, что ссылка ведет на сайт но это не так! Здесь ис пользуется малоизвестный, но тем не менее корректный формат Он определен в RFC 1738, Resource Locators Вот выдержка из раз дела «3.1. Common Internet Scheme (Общий синтаксис схемы Интернета):

В то время как синтаксис конца URL-адреса может в зависимости от выбранной схемы, в схемах напрямую зующих основанный на протокол для указания хоста в Интер нете, применяется общий синтаксис: <паролъ Заметьте: ни одна из частей URL-адреса не является обязательной. Вернемся к нашему URL-адресу: ссылка www.microsofl.com — обманка. Это вообще не ссылка, а имя пользователя, за которым следует настоящее имя Web-сайта, в шестнадцатеричном виде, чтобы жертва не узнала, куда на самом деле она ГЛАВА Проблемы ввода в Web-среде ОК, вернемся к нашим баранам (в смысле к XSS). Проблема в параметре пате — не в а том, что в него внедряется HTML-текст с JavaScript, позволяющий обратиться к данным пользователя, например к cookie-файлам, через объект Как вы наверное знаете, cookie-файлы привязываются к домену.

cookie-файлы, созданные сайтом в домене contoso.com, только Web-стра ницам этого домена, но никак не Web-страницам с microsoft.com. А теперь >с на засыпку: в какого домена исполнится сценарий, когда пользователь щелкнет ссылку? Для ответа достаточно выяснить, откуда, собствен но, пришла эта страница — из домена contoso.com, поэтому у нее есть доступ к cookie-файлам Проблема в том, что для небезопасной обработки данных на клиентском компьютере, относящихся к определенному домену, дос таточно, чтобы лишь одна страница в домене имела подобную брешь.

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

Позвольте мне привести пример. В конце 2001 г. на Web-странице passport.com была обнаружена очень хитрая брешь, по сути похожая на ный выше пример. Отправив абоненту Hotmail специально оформленное пись мо, хакер мог заставить выполниться сценарий в домене поскольку служба Hotmail располагается в домене hotmail.passport.com. А это значит, что код получал доступ к cookie-файлам, сгенерированным сервисом Passport и приме няемым для аутентификации клиента. Воспроизводя эти cookie-файлы — ведь э всего-навсего заголовки — хакер получал возможность выдавать себя за того самого абонента и получал доступ к его частным данным, сценарии позволяют читать или изменять cookie-файлы. Э го обычно отравлением (poisoning). Подключаемые модули бра узера или «родной» (native) код, связанный с доменом (например, использующий ActiveX-шаблон описанный в главе 16), можно загрузить и нариями со зловредными данными, а введенные пользователем данные — пере хватить. Короче говоря, хакер получает бесконтрольный доступ к объектной дели браузера в контексте безопасности скомпрометированного домена.

Атаки подмены сетевых объектов (spoofing) выполняются похитрее.

что новостной сайт имеет Воспользовавшись этим, хакер получит пол ный доступ к объектной модели браузера в контексте безопасности новостного сайта. И если он убедит жертву зайти на этот сайт, то сможет подсунуть под дом статей с новостного сайта свои собственные (рис. 13-1).

Примечание Подлинная причина существования XSS-атак — смешение кода и данных. Подробнее о неудачных проектах с подобными брешами рас сказывается в разделе «Разделяйте код и данные» главы 3.

Любой поддерживающий выполнение сценариев Web-браузер в принципе уяз вим. Более того — данные, собранные злонамеренным сценарием, попасть к хакеру. Например, если в сценарии задействована объектная модель Dynamic HTML (DHTML) для извлечения данных со страницы, то в результате с сценарием эти данные могут направляться хакеру. Вот нагляд ный пример.

Часть II Методы кодирования <а

> Щелкни здесь!

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

Внимание! Использование SSL/TLS не спасает от сценариев.

Защищенные брандмауэром компьютеры также уязвимы для XSS-атак. Большин ство корпоративных ЛВС сконфигурированы так, что клиентские компьютеры доверяют внутренним серверам сети и не доверяют (расположенным в Интернете). Тем не менее внешний сервер, находящийся по ту сторону брандма уэра и направивший клиенту запрос на исполнение программы, может ввести клиента в заблуждение и заставить поверить, что запрос поступил от доверенно го внутреннего сервера. Все, что хакеру нужно. — имя Web-сервера, расположен ного за и не проверяющего данные на Web-странице. (Этот сер вер может использовать поля формы или Отыскать такой сервер не просто, если только хакер не владеет внутренней но вполне ре ально.

Отправка по электронной почте сообщения со ссылкой на • ссылку, которую «подсунул» хакер Пользователь переходит на Web-сайт Ответ сервера содержит злонамеренные данные, которые отображаются (и/или исполняются) Сценарий выполняется в браузере пользователя в контексте Web-сайта жертвы Рис. 13-1. Схема ГЛАВА 13 Проблемы ввода в Web-среде Благодаря cookie-файлам могут выполняться постоянно, если выводящий данные из имеет дефект. Хакер делает свое про сто инфицируя cookie-файлы злонамеренным сценарием, и всякий раз, когда жертва заходит на этот сайт, сценарий выполняется. Атака повторяется, пока пользователь не удалит cookie-файлы, Примечание Прекрасный обзор XSS-атак вы найдете статье «Cross-Site Scripting Overview» (Обзор сценариев) на странице за мечательный ресурс — посвященный безопасности сайт Open Web Appli cation Security Project Иногда взломщик обходится без тэга .

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

<а Обратите внимание на кавычки, которыми выделено значение атри бута href. Если взломщик попытается подсунуть свое значение для id, то у него ничего не получится, страница рассматривает всю строку как значение id, а не только первое значение, которое и есть id. Например, превратится в:

<а Сильно сомневаюсь, что у Сотою наличествует продукт А почему двойные кавычки, а не одинарные? А потому, что в HTML одинарные не применяются для управляющих символов — только двойные.

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

id=spnTestx/span>

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

378 Часть II Методы безопасного кодирования Золотые правила безопасной реализации Создавая приложения с поддержкой старайтесь следовать двум правилам:

• применяйте Unicode;

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

В таком случае вы избавитесь от большинства брешей защиты, связанных с поддержкой языков. По сути, те из вас, кто уже применяют эти правила при со здании своих приложений, могут смело пропустить эту главу! Остальным реко мендуем познакомиться с I18N поближе, Применение Unicode В наборах изображениям символов (А, и других) ставится в соответствие дво ичные (обычно длиной от одного до четырех байт), которые называ ются кодовыми позициями (code point). Сегодня применяются сотни a Microsoft Windows поддерживает несколько десятков. У каждого набора симво лов, и не исключение, есть свои особые проблемы главным об разом из-за преобразования символов. Однако Unicode — единый общемировой поэтому эксперты по безопасности изучили его особенно Большая часть данных Microsoft Windows и Microsoft Office хранится в Unicode, и у вас возникнет меньше проблем преобразования, а значит, и брешей в защите, если вы также станете использовать Unicode. В среде CLR и каркасе Framework применяется только Unicode.

Примечание Существуют три базовых двоичных представления кода Unicode:

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

Компонент поддержки языков в Windows (National Langu age NLS) предоставляет преобразования между UTF-8 и который содержит две функции: и Формат IJTF-32 не очень популярен, и нет особых причин его применять.

Предотвращение переполнения буфера из-за 8N Чтобы избежать переполнения всегда выделяйте для него достаточно па мяти и каждый раз проверяйте возвращаемый функцией результат. Вот пример корректного преобразования строки.

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

ГЛАВА Проблемы поддержки других языков // Не забываем о завершающем символе \0.

= -1, NULL, // Если функция терпит сбой, отменяем преобразование!

if (nLen == 0) { // не получилось!

// Выделяем буфер для строки.

= nLen);

// Если операция выделения терпит сбой, // отменяем преобразование!

if (IpszNew == NULL) { // Ой, не получилось!

// Преобразуем строку.

nLen = IpszNew, // Операция преобразования потерпела сбой, // результат неопределенный.

if == 0) { // Ой, не получилось!

;

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

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

Слова и байты Несмотря на название и описание, большинство функций Win32 не обрабатыва ет символы. Многие из них (например обрабатывают данные по байтово, поэтому двухбайтовый символ Unicode считается за байта, а с конце (например тывают 16-разрядные слова, поэтому пару суррогатных символов за два слова вместо одного символа. Ошибки чреваты переполнением буфера или выделением излишней памяти.

380 Часть II Методы безопасного кодирования Многие разработчики понятия не имеют о существовании А- и фун кций в Windows. Следующий отрывок кода от winbase.h поможет вам в этом, ftdefine CreateProcess ftdefine CreateProcess ffendif // Что такое символы в Unicode В Unicode считается один абстрактный представленный двух кодовых позиций Unicode. Первая половина суррогатной или — это 16-разрядный код из диапазона Второе значение пары, или содержит значение из В стандарте Unicode определены составные (combining character) как основного символа и одного или более дополнительных.

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

В дополнительной Unicode уже определено много важных символов.

Проверка корректности несколько вариантов «некорректности» и Unicode не исключе ние. Например, строка может двоичные которые не соответ ствуют никакому символу, или символы с семантикой, несовместимой с логикой прикладной программы, например символы в URL-адресе. Такие некорректные строки бывают если программа не обрабатывает их должным образом.

В Microsoft. Windows Server 2003 появилась функция которая состоит ли строка только из действительных символов Unicode, Если True, будьте уверены: в строке нет кодовых игнорируемых (таких, как неопределенные символы или некорректные суррогатные пары). Но это не избавляет от необходимости прове рить на предмет характерных для конкретной программы исключений.

Визуальная проверка Даже после нормализации многие Unicode будут казаться пользователю идентичными. Например. 3.log — это на самом деле два символа Unicode и log).

а не пять ASCII-символов. Нет универсального средства, отличить ГЛАВА 14 Проблемы поддержки других языков подобные символы «на глаз». Поэтому не поручайте пользователю визуально про верять, содержит ли строка запрещенные символы. Устраните визуальную или предоставьте пользователю дополнительные средства (например инструмент отображения двоичных значений).

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

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

управляющий символ в формате ISO 8859-8-Е (двунаправленный иврит) теряет всякий смысл при переходе в а символ частного применения в таблице 950 (Big5, традиционная кодировка китайского языка) выглядит совер шенно по-другому в UTF-16.

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

Для преобразования в формат UTF-8 и из него при работе в ОС Windows XP и последующих применяйте и зо между UTF-8 и выполняется безопасно и без потерь, но только при соблюдении должной осторожности. Для подобного преобразования те только самые последние утилиты, прошедшие проверку на безопасность. Во многих пакетах приложений и некоторых компонентах Windows встроены бо лее ранние и опасные версии преобразователей — избегайте их. За прошедшие годы специалисты Microsoft настроили таблицы функций и 382 Часть II Методы безопасного кодирования для обеспечения максимальной безопасности и совместимо сти приложений. Не стоит создавать собственный преобразователь, даже если кажется, что он выполняет задачу более качественно.

Вызов MultiByteToWideChar с флагами и MB_ERR_INVALID_CHARS При вызове MultiByteToWideChar всегда устанавливайте флаг Это сокращает (но не устраняет совсем) появление составных символов и ускоряет нормализацию. Он устанавливается по умолчанию. Работая с кодовыми страни цами с номерами меньше 50000, устанавливайте флаг — он позволяет выявить неопределенные символы в исходной строке. стра ницы с номерами выше 50000 преобразует, исполь зуя алгоритмы, а не таблицы. В этом случае порядок обработки запрещенных символов и возможность применения флага определяет ся алгоритмом. Подробное его описание для таких кодовых страниц вы найдете в библиотеке Примечание Начиная с Windows XP, флаг поддержи вается для (кодовая страница 65001, или Вызов WideCharToMultiByte с флагом При обработке строк, которые требуют проверки корректности (например, имен файлов, ресурсов или пользователей), всегда устанавливайте флаг Он не позволяет функции преобразовать символы в похожие, но с совершенно другой семантикой. Иногда семантика изменяется самым ным образом. в некоторых кодовых страницах символ «я» (знак «бес конечность») соответствует цифре «8» (восемь)!

Флаг доступен только в Microsoft Windows 2000/XP и Microsoft Windows Server 2003. Если программа должна работать на устарев шей ОС, того же результата добиваются преобразованием готовой строки в ис ходный формат, то есть вызывая чтобы получить строку 16, и затем это позволяет возвратить строку в исходный формат. Некоторые кодовые позиции не выдерживают такого кругового преоб разования (они пропадают), поэтому их заменяют другими, наиболее подходящими в конкретной ситуации. Вот пример правильного выполнения кругового преоб разования.

Л : Определяет входа в приложение.

ГЛАВА 14 Проблемы поддержки других языков Функция Возвращает TRUE если строка выдерживает круговое между Unicode и данной кодовой страницей, В противном возвращается FALSE.

BOOL DWORD BOOL fStatus = TRUE;

BYTE = NULL;

*pwcTemp = NULL;

try { // не превышает ли длина строки // Корректная обработка нулевых строк const MAX_STRING_LEN = 200;

size_t = 0;

if throw FALSE;

= new = new if Недостаток throw FALSE;

* * // Преобразование Unicode в кодовую страницу, int гс = uiCodePage, О, -1, NULL, NULL };

if { ошибка = CodePage = String = uiCodePage, wszString);

throw FALSE;

384 Часть Методы безопасного кодирования // Преобразование из данной кодовой страницы в Unicode.

гс = О, -1, / );

if { ошибка = Xd, CodePage = Xd, String = uiCodePage, throw FALSE;

// длину исходной Unicode-строки, // и равна ли она строке.

size_t Length = 0;

if != { != Length, throw FALSE;

// Сравниваем исходную Unicode-строку и строку // и обеспечиваем их (size_t ctr = 0;

ctr < Length;

ctr++) { if != throw FALSE;

} } catch (BOOL iErr) { fStatus = iErr;

if delete [] if (pwcTemp) delete [] pwcTemp;

return (fStatus);

int _cdecl int argc, char* argv[]J s1 = // Copyright s2 = // Infinity Знак "авторское право" = Знак "авторское право" = Знак "бесконечность" = Знак "бесконечность" = ГЛАВА 14 Проблемы поддержки других языков return Вы что некоторые символы в определенных кодовых страницах не выдерживают кругового Например, знаки авторского и бесконечности в кодировках 1252 (кодовая страница Windows Latin I.

применяется западноевропейских языках) и 437 (исходная кодовая страница MS DOS): знак авторского права есть в но в 437, а в 437, но не существует в Сравнение и сортировка Если результат сравнения не пользователю, например, при генерации ренней хеш-таблицы на строки, рекомендуем воспользоваться упорядочиванием. Это быстро и надежно. Если результат ния не виден пользователю, но двоичное упорядочивание применить нельзя [на более популярная причина — игнорирование регистра используйте регион в dows ХР или invariant culture в приложении на управляемом коде.

nResult = | | -1 );

Если программа работать на платформах, предшествующих Windows используйте регион US English. В этом случае в Windows XP результаты работы будут такие же, как с но Microsoft не гарантиру ет, что это окажется верно в следующих версиях ОС.

int nResult = | I IpStM, -1, lpStr2, -1 );

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

• порядок букв из диапазона А — 2 не всегда совпадает с в ском языке;

• при игнорировании регистра «I» не всегда совпадает с • «А» следует после • латинские символы не всегда предшествуют символам других азбук.

В скором времении Windows будет поддерживать регионы с существенно боль шими отличиями (или исключениями). Если ваша программа при нении регион пользователя, следует учитывать, что результат может оказаться непредсказуемым. Если подобная ситуация недопустима, настоятельно дуем применять нейтральный регион, 386 Часть Методы безопасного кодирования Свойства символов Unicode В Unicode огромное количество символов, поэтому очень опасно делать какие то предположения относительно наличия (или отсутствия) определенных свойств у одного ограниченного диапазона. ошибочно думать, что диапазон цифр ограничивается кодовыми позициями от («О») до U+0039 В Unicode масса диапазонов цифр. При определенных обстоятельствах симво лы со скрытыми свойствами способны создавать проблемы с безопасностью.

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

Однако во многих компонентах Windows эти свойства применяются, поэтому при взаимодействии с ними разумно использовать GetStringTypeEx.

В табл. 14-1 перечислены свойства GetStringTypeEx и их аналоги в Unicode для кодовых позиций с номерами, превышающими U+0080. Коды меньше не имеют аналогов в Unicode, Таблица Свойства Unicode Свойство Unicode Элемент алфавита или идеограмма Верхний регистр или с заглавной Нижний регистр или с Десятичная цифра Пробел Знак Элемент управления — двунаправленный, форматирования или игнорируемый цифра Несамостоятельные символы Символ Символ Символ или узкий символ Идеограмма Нормализация Во многих кодировках, и особенно в Unicode, одна и та же строка может иметь несколько двоичных представлений. Например, если много различных строк ото и — таблицы знаков японской слоговой азбуки- — Прим.

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

несколько форм нормализации, • Консорциум Unicode Consortium определил четыре формы нор мализации. Особенно популярна нормализация Form С. Ее рекомендуют при создании новых Это наиболее популярный и простой в ции метод. Большинство форм нормализации, в Интернете, представляют собой разновидности Form С. (Подробнее — на сайте • Нормализация URL-адресов — активно обсуждаемая тема в группах IETF Engineering Task Force) и За подробностями отсылаю вас к и сайту • В каждой файловой системе — NTFS, FAT32, NFS, High Sierra и — уникальная форма нормализации.

• Определено несколько нормализации в протоколах Интернета За более подробной информацией в своей прикладной области обращайтесь к соответствующим RFC, поддерживает ряд полезных по нор мализации строк. К сожалению, она не охватывает весь диапазон символов Unicode.

и ее таблицы соответствия не всегда совпадают с одной из форм Используя не поленитесь проверить свою программу на всем наборе символов Unicode. вызов FoldString с флагом нормализует многие, но не все числовые символы Unicode.

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

Хотя связанные с I18N проблемы защиты зачастую оказываются очень слож ными, это не что для создания надежного ПО с поддержкой многих языков вам обязательно говорить на 12 языках и на зубок помнить таблицу символов Unicode. Применения тех принципов, что описаны в этой гла и нескольких консультаций со специалистами обычно вполне достаточно, Чтобы яснее понять и разобраться в сути проблемы I18N, почитать материалы сайтов и Unicode www.unicode.org). На последнем также есть активный список рассылки Ну и, наконец, неплохой источник по стандартам языков — новостная группа ДОПОЛНИТЕЛЬНЫЕ МЕТОДЫ СОЗДАНИЯ ЗАЩИЩЕННОГО КОДА Безопасность сокетов (sockets) — основа любого приложения, в котором для передачи данных применяется протокол TCP/IP. Создатели протокола IP и тесно связанных с ним TCP и никак не рассчитывали на то, что им придется тать в нынешней исключительно агрессивной среде, Однако ожидается, что по сле перехода на протокол IPv6 (Internet Protocol version 6) многие из существую щих ныне проблем исчезнут. В этой главе речь пойдет о создании привязки к порту так, чтобы предупредить его перехват локальными пользователями;

о написании серверного приложения, прослушивающего только выбранные сетевые интерфей сы;

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

Предполагаю, что читатель знаком с основами программирования сокетов. Если вы новичок в этом деле, рекомендую книгу Боба (Bob и Дэви да (David «Windows Sockets Network Publishing Co., 1995). Примеры на языке С с небольшими ми C++. Я предпочитаю расширение чтобы компилятор выполнял более стро гую проверку кода и отображал но приложения вполне понятны любому разбирающемуся в С. Отдельные параметры сокетов и некото рые функции управления интерфейсами только системах Microsoft, но общие принципы применимы при программировании для любой платформы.

кто интересуется встроенными в Windows возможностями аутентифика ции клиентов и серверов, а также секретности и целостности данных (в том чис ле SSL/TLS) советую документацию по API-интерфейсу (Secu rity Support Provider Interface). Хотя этот API-интерфейс поддерживает довольно много полезных возможностей, хочу предупредить: его применение — для креп ких духом. Как я уже упоминал в главе 4, лучший источник информации о SSPI — 15 Безопасность сокетов книга Джеффри Рихтера (Jeffrey и Кларка (Jason Clark) ramming Server-Side Applications for Windows 2000» (Microsoft Press, 2000) (Рихтер Кларк Д. Программирование серверных приложений для Windows 2000. 2001), Как предотвратить подмену сервера Подмена сервера hijacking) подразумевает нелегальный и мани пулирование для сервера. Как ная ситуация? При запуске серверное приложение в первую очередь создает и привязку к в соответствии с используемыми протоколами. В колах TCP или сокет привязывается к порту. У других, менее распростране протоколов отличные схемы адресации. Номер порта в виде числа типа беззнакового целого (unsigned short) (то есть 16-битным) в язы ке С или C++. Переменная этого типа принимает значения в диапазоне У функции привязки bind следующий прототип:

bind ( SOCKET s, const struct FAR int namelen ):

Эта функция поддерживает взаимодействие широкого спектра протоколов. При разработке программы на основе IPv4* (Internet version 4) структура struct short sin_family;

short sin_port;

struct ' Примечание На момент выхода в свет первого издания этой книги протокол IPv6 не получил еще широкого распространения. И сейчас он все еще не очень популярен, но его поддержка предполагается в Microsoft и в Service Pack 1 для Microsoft Windows XP. В конце этой главы описаны различия между IPv6 и Примеры этой главы совместимы с IPv4, но.

если не указано особо, излагаемые принципы применимы к обоим про токолам.

В процессе привязки сокета к IP-адресу и порту главную роль инфор мация полей и Номер порта для прослушивания на серверном приложении указывается практически всегда, а вот с не так просто. В документации по bind сказано, что, если указать для этого поля То есть широко распространенной и незащищенной версии протокол:

IP. — Прим.

392 Часть Дополнительные методы создания защищенного кода ние (истинное значение 0), сервер станет прослушивать все имею щиеся сетевые интерфейсы. Если же к определенному IP-адресу, при нимаются только пакеты, направленные именно на него. Получаем интересный опасный) вывод: к одному порту можно При конкуренции библиотеки сокетов выделяют пакет с максимально конкретизированными параметрами. Сокет с привязкой к «проигры вает» сокету с к конкретному Пусть у два IP-адреса:

и 172.101.92.44. Программа управления сокетами станет передавать приходящие на данные приложению с привязкой к адресу но не приложению с: привязкой Проблему решает выявление и стро гая привязка всех на сервере IP-адресов, но это утомительно. Если вы боитесь, что сетевые интерфейсы будут появляться и на лету, то придется написать существенно больше кода. К счастью, есть другой выход из положения, который я проиллюстрирую примером. Проблема при помощи параметра впервые появившегося в Microsoft Windows NT 4 SP Одна из причин, по которой Microsoft добавила этот параметр, — действия хакера Криса (Chris (псевдоним — Weld Pond). перенес программу Netcat (автор — хакер с псевдонимом Hobbit) в Windows и в процессе тестирования обнаружил уязвимое место ОС: у нескольких серверов под управ лением Windows NT обнаружилась описанная проблема с привязкой к Стоит что Крис и Hobbit в то время входили в известную группу (сейчас часть компании Я написал специальную программу (см. папку для демонстрации проблемы и способа ее ре шения.

/* ftinclude tfinclude // В случае, если у вас версия ffifndef tfendif Это приложение работу Сервер слушает порт 8391. Если этот порт уже используется, номер порта и не забудьте сделать то же на стороне клиента.

char* { SOCKET sock;

sockaddr_in DWORD packets;

ГЛАВА 15 Безопасность сокетов = false;

= false;

if(argc < 2 > 3) вызова [адрес для return -1;

I == 3) { // Проверяем, какой // или == { hijack = true;

else == 0) •;

nohijack = else { параметр return -1;

.

return -1;

// Создаем сокет.

sock = if(sock == удается создать сокет - err = return -1;

// Создаем привязку созданного // Сперва sockaddr_in.

// Для этого я выбрал случайный порт, // который скорее всего не используется.

argv[1], < удается инициализировать sockaddr_in 394 Часть III Дополнительные методы создания защищенного кода return // Продемонстрируем два варианта: с перехватом сеанса и без.

-:

BOOL = TRUE;

== 0) { < инициализировать SO_REUSEADDR - = return -1;

), else I val = TRUE;

== 0) { вход else { удается инициализировать - = return -1;

== 0) { привязан к ГЛАВА Безопасность сокетов else < if(hijack) { Наше хакерсков ПО обвели вокруг пальца!\ удается создать код ошибки = closesocket(sock);

return -1;

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

for{packets = 0;

packets < 10;

I from;

int = sizeof(sockaddr_in);

// Помните: функция имеет три возможных результата;

// если больше 0, возвращаются данные;

// если значение равно 0, выполняется корректное завершение данном случае неприменимо);

// значение меньше 0, сообщение об ошибке, buf, 512, 0, 0) { от на порту // Если удалось перехватить сеанс, подменяем сообщение и // переправляем на настоящий сервер.

•;

sockaddr_tn local;

"127,0.0.1", { = "Вас siz eof(buf) -1);

buf, + 1, 0, < 1) 396 Часть III Дополнительные методы создания кода ("Не удается отправить сообщение на - = // Я не понимаю, как сюда можно попасть, но даже в этом случае, // работу корректно.

мерзопакостная ошибка GetLastErrorO };

break;

return 0;

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

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

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

0.0.0. Затем активизируем атакующий код (только замените адрес 192.168.0.1 IP-ад ресом вашего компьютера):

BindDemo.exe 192.168.0.1 -hijack Наконец, отправим сообщение с помощью клиентской программы:

Вот что выдаст атакующий код:

ГЛАВА Безопасность инициализирован привязан к 192.168.0. Сообщение от 192.168.0.1 на порту 4081:

Привет!

Со стороны жертвы это так:

Сокет привязан к 0.0.0. Сообщение от 192.168.0.1 на порту Вас взломали!

Если приложение регистрирует события (например, записывая для всех запросов дату, IP-адрес клиента и номер порта в текстовый файл, за щищенный с помощью составленного списка ACL), то вы атакующий код действует немного неаккуратно и оставляет за собой следы.

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

Теперь пришло время пойти путем. Запустите сервер (теперь это уже не несчастная жертва) таким образом:

0.0.0, Активизируйте атакующий код тем же способом, что и раньше:

BindDemo.exe 192.168.0.1 -hijack Сервер отреагирует так:

инициализирован - перехватам вход Сокет к 0.0.0. Атакующий код выразит недовольство:

инициализирован - Оп-ля-ля Проклятье! Наше ПО обвели вокруг пальца!

Не удается создать привязку сокета - код ошибки = В этом случае, если клиент посылает сообщение, сервер получает правильный экземпляр:

Сообщение от 192.168.0.1 на порту 4097:

Привет!

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

398 Часть III Дополнительные методы создания защищенного кода После выхода Server 2003 в большинстве случаев удается отка заться от использования — в этой ОС назначается надлежащая разрешающая доступ к сокету только текущему пользо вателю и администраторам. Такой подход полностью устранит только что опи санную проблему и предотвратит перехват чужих сеансов.

Атаки с применением окон на прием в протоколе TCP Документы RFC, регламентирующие работу протокола TCP, допускают возможность чрезвычайно опасной атаки, основанной на поддержке окон приема. Для обеспе чения скорости передачи данных сервером, при которой клиент будет успевать их принимать, в процессе создания TCP-подключения в АСК-пакетах объявляет ся размер окна приема. Если приемный буфер клиента переполнен, клиент мо жет обнулить окно приема, что вынудит сервер приостановить передачу данных.

Этот процесс подробно описан в книге Дугласа Камера (Douglas Comer) «Internet working with TCP/IP Vol. 1: Principles, Protocols, and Architectures (4th (Pren tice Hall, 2000) (Камер Д. Сети TCP/IP. Т. 1. Принципы, протоколы и структура.

Вильяме», 2003).

Атака выполняется следующим образом: создает подключе ние и объявляет окно очень маленького размера (или равным нулю), заставляя сервер передавать данные чрезвычайно медленно и с очень большим дополни тельным расходом ресурсов. На каждую пару-тройку байт полезных данных при этом приходится около 40 байт заголовков TCP и IP. Неудачно написанное сер верное приложение блокирует ресурсы при попытке отправки а на обслуживание дополнительных рабочих потоков и переключений контекста рас ходуется масса процессорного времени. До реализации поддержки окон приема не было нужды волноваться о подобных проблемах — стеки TCP/IP согласовали передачу данных без нашего вмешательства, и при стандартном использовании практически не приходилось менять принципы их работы. Но, к сожале нию, созданы специализированные приложения, доставившие всем массу неудобств.

Защита от такой атаки заключается в обязательной проверке откликов на зап росы отсылки данных. Подобный подход не только полезен, но считается при знаком хорошего стиля. Я очень часто сталкивался с ситуациями, в которых под ключения закрывались до начала передачи данных, но после создания. Иногда и в обычных условиях возможна когда от сервера требуется передавать данные медленно. Например, передача данных системе с модемным доступом от высокопроизводительного Web-сервера, подключенного к гигабитному каналу связи. Если клиент слишком долго обрабатывает переданные ему данные, лучше всего закрыть вызовами close и Выбор интерфейсов сервера При конфигурировании которую предполагается публиковать в Интер нете, одна из первоочередных задач — свести к минимуму число сервисов, до ступных извне. Если у системы только один IP-адрес и один сетевой интерфейс, сделать это довольно просто: достаточно отключить ненужные сервисы, чтобы не ГЛАВА Безопасность прослушивать лишние порты. Если система входит в крупный га она, скорее — то есть имеет по крайней мере две сетевых карты. Это усложняет дело. Б большинстве случаев нельзя просто лючить» сервис — он может оказаться необходимым для работы >й сети. Если нельзя управлять тем, какие сетевые интерфейсы или IP-адреса про слушивает сервис, для обеспечения защиты придется применить какой-нибудь тип фильтрации на хосте или маршрутизаторе/брандмауэре. Но ведь возможны туации, когда IP-фильтры настроены неправильно, маршрутизаторы по той та иной причине вышли из строя;

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

• прослушиваемый сетевой интерфейс;

• прослушиваемый предпочтительно с до отдельных портов;

• перечень клиентов, которым разрешено обращаться к сервису, Перечисление всех интерфейсов и привязка к ним IP-адресов довольно мительна в Windows NT. Приходится сперва просматривать реестр, чтобы найти адаптеры с привязкой, а затем обращаться к в другим разделам реестра, ным с адаптером.

Порядок обработки запросов на создание подключения API-интерфейс Windows Sockets 2.0 поддерживает несколько обработки поступивших от того или иного клиента. При работе с про токолом, не поддерживающим подключений (например, все просто: опре деляем IP-адрес и порт клиента и на основании этой информации решаем, стоит ли обрабатывать запрос. Если не хотите принимать запрос, обычно пакет отбрасывается и клиенту никакого ответа не отправляется. На создание и отправ ление отклика расходуются ресурсы, и, атакующий получает дополни тельную информацию.

При работе с поддерживающим подключения протоколом (например, TCP) ситуация усложняется. Для начала я как выглядит процесс создания подключения с точки зрения сервера. На первом этапе клиент инициирует под направляя па сервер пакет SYN. Если тот готов «общаться» с этим ентом (предполагается, что порт прослушивается), он отправляет в ответ пакет после чего клиент завершает процесс создания подключения передачей пакета Теперь данные передавать в обоих направлениях. Чтобы рыть подключение, клиент отправляет на сервер пакет FIN. Сервер отвечает па кетом FIN-ACK и уведомляет приложение о закрытии подключения. Дальше сер вер обычно передает оставшиеся данные, отправляет клиенту пакет FIN и ждет ответа с в течение интервала, равного двум максимальным периодам жи пакета в сегменте (maximum lifetime, 400 Часть Ml методы создания защищенного кода Примечание — это период времени, в течение которого пакету разреша ется существовать в сегменте, после чего он отбрасывается.

Вот как выглядел процесс создания подключения в старом стиле, с примене нием функции (полную версию приложения вы найдете в файле папка void sock) { // Привязка создана. Прослушиваем порт.

// Используем эту переменную как счетчик int conns = 0;

// Будем поддерживать максимально число подключений.

if(listen(sock, SOHAXCONN) == 0) { SOCKET sock2;

int size;

// Кто-то пытается подключиться - вызываем accept, // чтобы идентифицировать клиента.

conns++;

size = = accept(sock, &size);

if(sock2 == !

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

запрос на подключение от // Теперь решаем, что делать с подключением;

// выберем простейший критерий обработки // принимаем каждое второе % 2 == 0) !

клиент нам Здесь что-то делаем.

} else 15 Безопасность else // Ошибка попытка прослушивания код ошибки = break;

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

if(conns > 10) { break;

• Я привел стандартный код для работы с который проверен и выглядит довольно привлекательно. Что же в нем плохого? даже если немедленно сбросить подключение, взломщик узнает, что запрошенный порт прослушивается. Неважно, что сервис не отвечает на запросы взломщика, порт все таки «живой». Во-вторых, за время процедуры отказа в создании подключения удается обменяться в общей сложности семью пакетами. В конце концов, е< ли по-настоящему хочет нанести вред, он может изменить свой ЕР стек так, чтобы тот отправлял в ответ на пакет FIN с сервера. В этом слу чае придется ждать отклика в течение двух Даже если нормаль сервер несколько сотен подключений в секунду, несложно уви деть, каким образом удастся загрузить даже самый большой рабочих потоков. Частично проблема решается вызовом функции для присвоения параметру нулевого или очень маленького значения пе ред вызовом В этом случае ОС будет быстрее освобождать сокеты Есть и другой способ установить подключение — средствами функции Эта функция в сочетании с установкой параметра позволяет перед ответом принять решение, необходимо ли то или иное подклю чение.

int CALLBACK AcceptCondition( IN IN LPWSABUF IN OUT LPQOS IN OUT LPQOS IN LPWSABUF OUT LPWSABUF GROUP FAR 402 Часть III Дополнительные методы создания защищенного кода IN pCaller = pCallee = создать подключение с // Если требуется, чтобы работала в Windows 98, // прочитайте статью l= NULL) // Здесь условия использования // Здесь принимается решение, что клиенту // от самих себя принимать не будем.

== ', return CF_REJECT;

I else { return CF_ACCEPT;

// Примечание: мы также можем вернуть CF_DEFER // эта функция должна выполняться в том же потоке, // что и программа.

// Для этого сперва можно выяснить DNS-имя клиента, // а затем попытаться снова, уже зная, кто он, void NewStyleListen(SOCKET sock) • // создана. Прослушиваем порт.

// Используем эту переменную как счетчик подключений, int conns 0;

// Сперва установим значение параметра.

BOOL = TRUE;

SO_CONDITIONAL_ACCEPT, != 0) ГЛАВА Безопасность сокетов I удается установить код ошибки return;

i { // Используем максимальное разрешенное число подключений.

0) SOCKET sock2;

from;

int size;

// Кто-то подключиться - вызываем accept, // идентифицировать клиента, conns++;

size = // Здесь начинаются sock2 = conns);

// conns для обратного вызова.

if(sock2 == { приема GetLastErrorO);

:

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

запрос на подключение от // какие-то операции.

closesocket(sock2);

else !

// Ошибка попытка прослушивания ошибки = GetLastErrorO);

404 Часть III Дополнительные методы создания защищенного кода break;

// Здесь размещается код, где принимается решение // при каких условиях завершить работу приложения.

> 10) break;

!

!

Как вы видите, код почти совпадает с начальной версией;

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

-p 8765 192.168.0. timed out Теперь взглянем на происходящее со стороны сервера:

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

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

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

• для работы только одно подключение;

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

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

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

А теперь я поясню каждое из перечисленных правил.

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

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

406 Часть III Дополнительные методы создания защищенного кода Не создавайте обратных подключений от сервера к клиенту Показательный пример по отношению к брандмауэру» при ложения — Он прослушивает порт протокола а при подклю чении клиент сообщает серверу о необходимости обратного подключения с TCP порта 20 на порт с более высоким номером (больше 1024). Если администратор брандмауэра достаточно безрассуден, чтобы такие действия, злоумыш ленник сможет установить на своей системе порт 20 источника и атаковать лю бой сервер, прослушивающий порт с более высоким номером. Самые известные серверы, доступные для атаки таким способом, — Microsoft SQL Server, работаю щий через порт 1433, Microsoft Terminal Server (порт 3389), клиенты X Window (в системе роли клиента и сервера распределены с точностью до наобо рот относительно общепринятых) (порт 6000). Если администратор заблокирует на брандмауэре подключения именно к этим серверам, впоследствии не избежно другие серверы с другими портами, что при ведет к проблемам с безопасностью. Сервер никогда не должен сам подключать ся к клиенту. Не говоря уже о том, что это усложняет одноранговое взаимодей ствие между хостами. Если в системе, на которой выполняется приложение, запу щен персональный брандмауэр, сложно обеспечить двухстороннюю передачу данных. Лучше, когда приложение единственный порт, к которому подключаются другие системы.

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

Allow internal UDP high port to external UDP Allow external UDP port 53 to internal UDP high port Оно позволяет злоумышленнику установить на источнике порт под номером 53 и атаковать любые внутренней сети, работающие на непривиле гированных портах. Администратор брандмауэра может решить эту проблему двумя способами. Первый — настроить брандмауэр так, чтобы он выполнял функцию прокси для выбранного протокола, а второй — использовать брандмауэры с под держкой состояний. Как ясно из названия, брандмауэры такого типа отслежива ют состояния подключений. Обнаружив запрос, отправленный из внутренней сети, такой брандмауэр ожидает ответа от конкретного сервера и с конкретного порта и передает обратно во сеть только ожидаемые ответы. иногда веские причины заставляют использовать не поддерживающие подключения про токолы (они обеспечивают большую производительность), но если есть то лучше применять протоколы с подключениями.

ГЛАВА 15 Не используйте в приложениях передачу данных поверх другого протокола Если приложение использует другой протокол для передачи данных, сложно го ворить о высоком уровне безопасности. В этом случае приложением трудно уп равлять, к тому же появляются проблемы с безопасностью (причем как на стор< не клиента, так и так как сильно усложняется взаимодействие с существующим ПО. Обычно мультиплексирование применяют из-за того, что администраторы брандмауэра отказываются открывать дополнительные порты и разработчики пытаются обойти эти ограничения, пустив данные поверх како го-нибудь разрешенного протокола прикладного уровня. Что можно на это зать — прежде всего, хороший администратор все равно заблокирует подобное приложение при помощи наполнения (content filters). Скоро вы убедитесь в что брандмауэр в большинстве случаев не ме шает работе должным образом написанного приложения. Если приве денным правилам, вам не придется использовать передачу данных поверх уже существующего протокола. Это не значит, что такой подход вообще неприемлем.

Например, для связи двух Web-серверов абсолютно естественно порт 80 протокола TCP.

Не размещайте IP-адреса хостов в данных прикладного уровня Пока протокол IPv6 не получил широкого распространения, популярность пре образования сетевых адресов (network address translation, NAT) и ров не снизится, а даже особенно из-за обострения проблемы нехват ки адресов. Если в приложении данные прикладного уровня содержат ля об IP-адресах, оно не будет работать на расположенных за пределами сегмента, обслуживаемого NAT-сервером или прокси. очевиден: данные не должны содержать информацию IP-адресах хостов. Еще одна веская по которой не стоит включать информацию транспортного уровня в данные прикладного уровня — перестанет работать при переходе на Создавайте настраиваемые приложения Клиентам требуется изменить стандартный номер порта, на котором работает приложение, по различным Возможность настройки сервера и та предоставляет вашим клиентам дополнительную гибкость при развертывании, Бывает и такое, что параметры порта по умолчанию конфликтуют с другими Некоторые полагают, что можно обеспечить защиту, утаивая ности реализации (хотя это обычно не приносит большой пользы — вкупе с утаиванием намного лучше);

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

408 Часть III Дополнительные методы создания кода Подмена сетевых объектов и доверие хостам и портам Подмена сетевых объектов предусматривает участие трех хостов:

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

взлом щику достаточно выбрать в качестве стороннего подходящий хост, подменить в пакетах поле с адресом источника и переправить пакеты жертве, Пример протокола, уязвимого для подмены сетевых — Этот стандартный протокол применяется в UNIX и UNIX-подобных системах и иногда встречается в Windows. Для передачи данных в этом протоколе применяется кроме того, syslog поддерживает настройку на прием данных журналов только с заданных избранных хостов. Злоумышленнику достаточно узнать адрес хотя бы одного из их, чтобы подменить его и заполнить файлы журналов любой инфор по своему выбору, Протоколы с поддержкой подключений также в некоторой степени подвержены подмене сетевых объектов. Широко известен пример, когда Кевин (Kevin Mitnick) использовал утилиту с подменой IP-адреса для вторжения на компь ютер Несмотря то, что большинство современных операционных систем намного лучше от атак с TCP подменой, полностью доверять ориентируясь только по адресу ис точника, не стоит. Еще один вариант подмены хостов — искажение базы данных DNS. Такую атаку не очень сложно организовать, но если информация DNS изме нена, может оказаться, что, к «правильному» somebost.nicwguys.org, приложение будет работать с хакерским хостом, реальный адрес которого org.

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

С этим связана и проблема доверенных портов. Хорошая иллюстрация — ути лита она предполагает, что в UNIX-системах только привилегированные пользо ватели (обычно только root) вправе использовать порты с номерами ниже 1024.

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

К сожалению, подобные опасности грозят не только устаревшим и уже неис пользуемым протоколам. Во множестве современных приложений, работающих 15 Безопасность сокетов с важными данными, возможны (и не в единственном числе) ошибки, описанные в этом разделе. Не наступайте на эти грабли! Важно знать, кем на самом деле яв ляются ваши клиенты или серверы, так что позаботьтесь о взаимной проверке подлинности в приложении, IPv6 наступает!

IPv6 — это новая версия протокола IP, в которой устранено недо статков исходной реализации IP — IPv4. Самая заметная особенность IPv6 — разрядная адресация, которая позволяет присвоить индивидуальные IP-адреса всем имеющимся ныне сетевым устройствам, при этом еще остается масса не занятых адресов. IPv6 предоставляет множество интересных и этой теме посвящено достаточно книг, поэтому я расскажу лишь о самых интересных. В так и не решены многие из описанных в этой главе проблем. Этот протокол пре доставляет адресное пространство, достаточно обширное для того, чтобы предо ставить глобальные IP-адреса всем имеющимся сетевым устройствам. Подробный рассказ о возможностях IPv6 выходит за рамки этой книги, поэтому если вы уже хорошо знакомы с IPv4, советую проштудировать книгу Кристиана The New Internet Protocol, Second Edition» (IPv6:

протокол Интернета) (Prentice 1998). Кристиан занимал пост главы Internet Activities Board в организации IETF, а теперь работает в компа нии Microsoft. Поддержка протокола IPv6 предусмотрена в Microsoft Windows Server 2003 и уже включена в Service Pack 1 для Windows XP. А теперь немного о некоторых интересных особенностях IPv6.

У может быть несколько IP-адресов. В IPv6 появилось анонимных IP-адресов, которые вводятся на а затем удаляются. Таким разом, в мире IPv6 не стоит основываться на доверенных IP-адресах.

Область действия ограничивается одной из трех областей: локаль ной (link local), локальной в пределах сайта (site local) или глобальной В приложениях, предназначенных для только из подсети, при меняется локальный IP-адреса, локальные в пределах сайта, предназна чены для маршрутизации только в данном сайте или корпоративной сети, но не для глобальной маршрутизации. Есть новинки и в сокетах: теперь разрешается устанавливать область действия сокета с привязкой;

и это действительно Все реализации IPv6 обязаны поддерживать протокол (Internet Protocol Security). При работе с IPv6 всегда можно рассчитывать на его наличие. При лизации IPv6, как и прежде, придется решать организационные вопросы исполь зования имеющейся инфраструктуры (например, как договариваться о но вместо того чтобы создавать собственную систему обеспечения секретности и целостности допустимо во время установки системы настроить образом протокол IPSec. Кристиан упоминает в своей книге, что производителям предоставлено право добавлять в протокол возможность включать IPv6 на «на в период исполнения. Я что это хорошая но у меня нет сведений о каких-либо планах Microsoft или другой компании на этот счет — х< все может и измениться.

IPv6 затрудняет задачу для злоумышленников. В настоящее время, ровать все устройства Интернета (на основе IPv4) — дело нескольких дней, Часть III Дополнительные методы создания защищенного кода если в вашем распоряжении немного систем. Просканировать даже нижнюю 64 битную часть за разумное время при нынешних скоро стях и других ограничениях на пакеты не представляется возможным.

Резюме Вы узнали, как создавать привязку сокетов так, чтобы избежать локальных атак подмены серверного приложения. Ожидается, что с появлением Windows Server 2003 подобных проблем станет меньше. При проектировании серверных приложений тщательно подумайте, каким образом пользователи будут определять прослушиваемые сетевые интерфейсы и при каких условиях принимать запросы на создание подключений, Важнейшая тема этой главы — создание приложений, поддерживающих взаи модействие через брандмауэры. Мой прогноз: R ближайшее время ожидается ла винообразный рост числа установленных брандмауэров, особенно персональных.

Если у приложения не возникает проблем при работе через значит, оно полностью готово к этому «нашествию брандмауэров».

Защита RPC, ActiveX-элементов и объектов DCOM удаленного вызова процедур (Remote Procedure RPC) является новным средством взаимодействия со времен выхода ОС Microsoft Windows NT (то есть с 1993 две основных версии механизма DCE Computing Environment) RPC и ONC (Open Network Computing) RPC. Обе в открытого стандарта и реализованы на ряде платформ. В системах корпорации Microsoft применяется DCE RPC, хотя во используется ONC RPC. Стоит заметить, что DCE RPC называют «Microsoft RPC», a ONC RPC — «Sun RPC». В этой главе под термином RPC подразумевается вариант DCE RPC, реализованный Microsoft, хотя некоторые утвер ждения верны для обеих версий RPC.

Работа огромного числа приложений для Windows NT/2000/XP в значитель ной степени зависит от механизма RPC. безопасности а ет укрепление всех компонентов системы, поэтому жизненно важно создавать и устойчивые к атакам Об этом и пойдет речь в главе. Кроме того, вы узнаете о и ActiveX-элементах. Причи на в том, что используется в модели DCOM (Distributed COM) в качестве ме ханизма взаимодействия а технология ставляет собой особый вариант СОМ, При проектировании и создании защищенных приложений стоит учиться на прошлых ошибках, поэтому я познакомлю вам с тремя брешами в RPC, правда, уже устраненными компанией Microsoft. Первая обеспечивала успех атаки, в котор ж злоумышленник отправлял диспетчеру LSA некорректные данные, приводившие Часть III методы создания защищенного кода к его зависанию. На первый взгляд казалось, что причина в API;

однако виновни ком оказалась API-функция которая пересылала в LSA средствами RPC. Подробнее об этой дыре в защите рассказывается в бюлле тене Security Identifier («Некорректный запрос идентифика тора на странице Вторая брешь позволяла путем передачи «мусорных* данных на порт ком пьютера под Windows NT /NT 4 заставить вающим на этом порту, вызвать 100-процентную загрузку процессора, практически заблокировав доступ пользователей к серверу. Чаще всего злоумышленник под ключался к порту передавал десяток-другой случайных сим волов и обрывал связь. Эта брешь подробно описана в статье Telnet to Port Causes 100 Percent CPU Telnet к порту 135 вызывает 100-процент ную загрузку в базе знаний Microsoft Knowledge Base Последняя брешь, описанная в выпущенном Microsoft в июле 2001 г. бюллете не «Malformed RPC Request Can Cause Service Failure* («Некорректный RPC-запрос способен вызвать сбой службы»), связана с серверными ми (stubs), которые перед перенаправлением запросов другим сервисам не выполняли их не предмет корректности, делая систему уязвимой для DoS-атак. Статья опубликова на на странице Азы RPC Цель этого раздела — рассказать о ключевых понятиях и терминах Если вы хорошо знаете переходите к разделу «Проверенные методы обеспечения безопасности Однако новичкам не стоит его игнорировать — первое зна комство с RPC способно привести в замешательство, Что такое RPC (Remote Procedure Call) — это механизм взаимодействия клиентского и сер верного приложений, в котором клиенты вызывают функции сервера. Для клиен та это выглядит как вызов локальной функции, но на самом деле вызов передает ся средой исполнения RPC runtime) серверу, который исполняет функцию и возвращает результаты клиенту.

Примечание — основная технология для языков программирования С и C++. Несмотря на наличие соответствующих оболочек, в других языках (таких, как Perl, Microsoft JScript или Microsoft Visual Basic) RPC проще использовать COM или Встроенный в системы Microsoft Windows вариант механизма RPC основан на OSF RPC (Open Software Foundation RPC), что позволяет ему взаимодействовать с другими операционными системами, например UNIX и Apple.

Большинство системных служб Windows [в том числе Print Spooler (Диспетчер очереди печати), Event Log (Журнал событий), Remote Registry (Служба удаленно ГЛАВА 16 Защита RPC, ActiveX-элементов и DCOM го управления реестром), Secondary Logon (Вторичный как и сотни при ложений сторонних производителей, хотя бы в некоторой степени используют К тому же, многие приложения, располагающиеся на одном компьютере, взаимодействуют посредством локальной версии — LRPC, Создание Создание поначалу может показаться сложной задачей. Исполь зование рекомендуется запланировать уже на этапе проектирования при жения, а не добавлять поддержку вдогонку. При создании применяются следующие компоненты:

• код клиента;

• код сервера;

• файл на языке описания интерфейсов (с • необязательный файл с параметрами приложения (с расширением Код клиента обычно пишется на C/C++. В нем вызываются различные функ ции: конфигурирования локальные, а также RPC. Код сервера также содержит код запуска но интереснее всего то, что он содержит реальные функции, к которым обращаются Чрезвычайно важен В нем определяются сигнатуры функций удаленного интерфейса (то имя, гументы и возвращаемые значения), что позволяет разработчику функции по простым в управлении интерфейсам. позволяет поведение RPC-приложения, не вмешиваясь в сетевое представление данных.

Компиляция кода Компиляция RPC-приложения выполняется в несколько этапов.

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

5. Компоновка кода серверной части с соответствующей исполнения (обычно Rpcrt4.1ib).

Вот и все! Посмотрим на примере, как это все работает (рис. 16-1). Пусть при ложение (работающее по принципу телефона) называется Phone, код содержится в файле код сервера — в a IDL- и на соответственно и Phone.acf. В результате компиляции с помощью Midl.exe образуются три файлы: заголовочный файл и клиент ская и серверная — Phone_c.c и Phone_s.c. Затем Phonec.c и c.c компилируются и компонуются с библиотекой Ppcrt4.1ib, а в результате получает ся клиентская часть приложения — Наконец, путем компиляции Часть III Дополнительные методы защищенного кода и Phone_s.c и компоновки с библиотекой создается серверная часть Phones.exe.

Phone.acf h Phones.exe Рис 16-1. Процесс разработки Это не так сложно, как кажется на первый взгляд! Исходный код приложения Phone вы найдете в папке Как взаимодействуют RPC-приложения При взаимодействии клиента и сервера первый вызывает клиентскую которая, в свою очередь, выполняет предназначенных серверу данных. Под подразумевается упаковка информации о фун кции и ее параметров в формат, понятный любому на любой плат форме. После упаковки клиентский запрос отправляется на сервер, где серверная заглушка распаковывает его и передает данные серверному коду. Выполнив за прошенные операции сервер передает данные обратно клиенту, также применив инг.

Для связи между клиентом и сервером в RPC-приложениях используются раз личные сетевые транспортные протоколы, в том числе именованные каналы и TCP/IP. Могу обрадовать: вам, как не нужно разбираться в деталях работы сетевых протоколов — всю работу выполнит механизм Для связи с сервером клиент создает (bind) к нему, что подразумева ет создание описателя привязки на основе строки привязки. Последняя состоит из нескольких частей, причем в первой содержится информация о ности, протоколов (protocol sequences), то есть о применяемых протоколах. У каждого протокола свое характерное имя. В табл. 16-1 перечислены наиболее часто используемые последовательности протоколов.

ГЛАВА 16 Защита и объектов Таблица 16-1. Примеры последовательностей протоколов Последовательность протоколов Примечание Именованные каналы Локальное (в отличие от удаленного) взаимодействие между процессами Протокол TCP/IP Затем следует адрес сервера, обычно это имя сервера в формате, понятном для используемого протокола. Дальше указывается конечная точка, которая ляет требуемый сетевой ресурс на хосте. Есть специальная функция для ления необходимой строки — Например, следующий код создает строку привязки = LPBYTE = LPBYTE pszNetworkAddress = LPBYTE = LPBYTE = LPBYTE = status = pszProtocolSequence, pszNetworkAddress, pszEndpoint, После создания описателя привязки клиент готов вызывать Описатели контекста и состояние подключений С формальной точки зрения механизм RPC не поддерживает состояние подклю чения: никакой информации о пользовательских подключениях не сохраняет. Однако некоторым приложениям необходимо, чтобы сервер сохранял состояние между клиентскими вызовами информации о клиентах;

в этом случае серверу приходится хранить информацию о состоянии всех и каждого клиента.

Для этого используются описатели контекста — сложные «непрозрачные» туры выдаваемые клиенту сервером. При каждом запросе клиент посы лает серверу описатель контекста, роль которого в данной ситуации cookie-файлы в Web, Запомните: в RPC два основных типа описателей: привязки и контекста. Первые необходимы для идентификации логического соединения клиентом и сервером. Они схожи с описателями файлов. Вторые позволяют сер ру хранить информацию о состоянии клиентов в промежутке между функций.

Часть методы защищенного кода Проверенные методы обеспечения безопасности RPC Л сейчас о ряде методов обеспечения — они проверены опытным путем и хорошо себя RPC грозит:

• опасность время которых злоумышленник направляет специаль ным образом измененные данные точке RPC, a не спо правильно обработать данные и «падает»;

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

• опасность модификации и подмены данных: пересылаемые по сети незащи щенные данные легко перехватить и изменить.

Pages:     | 1 |   ...   | 4 | 5 || 7 | 8 |   ...   | 10 |





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

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