Большие данные

Защищайте свои онлайновые сервисы с большими данными, применяя машинное обучение

Элиссон Сол
Дон Энкни
Юджин Бобук

Исходный код можно скачать по ссылке

Продукты и технологии:

Microsoft Bing, Microsoft Azure, Windows PowerShell

В статье рассматриваются:

  • защита онлайновых сервисов от атак;
  • анализ данных использования с целью определения природы атак;
  • выполнение тестовых атак на области, доступные для атак (attack surface).

В настоящее время существует несколько методов защиты онлайновых сервисов — от Security Development Lifecycle до эксплуатационных процессов с быстрой реакцией на инциденты. Один из основных ресурсов онлайновых сервисов обычно не замечают: большие данные (Big Data), создаваемые журналами запросов и результатами мониторингом операционных событий. В этой статье исследуются обработка данных использования и методы машинного обучения (machine learning, ML) для повышения безопасности на основе опыта защиты онлайновых ресурсов в Microsoft Applications & Services Group (ASG), в том числе таких сервисов, как Bing, Bing Ads и MSN.

Большинство онлайновых сервисов создает несколько потоков протоколируемых данных. Хотя стандартной классификации для такого рода метрик о работе сервиса нет, при изучении того, какие данные имеют уязвимости в защите, вы можете классифицировать их в широком смысле как данные использования или эксплуатационные данные operational data. Данные использования включают любое запротоколированное значение, относящееся к применению сервиса целевой аудиторией. Распространенный пример — запись журнала для запросов, выданных веб-сайту:

#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2014-10-27 20:46:57 127.0.0.1 GET /search q=election+results&form=PRUSEN&mkt=en-us 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+6.4;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko - 200 0 0 5265

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

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

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

Атака на конечные точки

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

Почти в конце 2014 года сервисы Microsoft Bing ежедневно генерировали сотни терабайт данных использования, протоколируя сотни миллиардов запросов. Можно с уверенностью предположить, что некоторые из этих запросов были на самом деле атаками, с помощью которых пытались найти или эксплуатировать уязвимости. Типичный запрос к Bing выдается отправкой сервису URL запроса:

https://www.bing.com/search?q=election+results&form=PRUSEN&mkt=en-us

В этом примере пользователь ищет «election results». В URL есть другие два параметра, первый из которых идентифицирует веб-форму, откуда исходит запрос, а второй — так называемый рынок (market) (в данном случае он указывает, что язык пользователя английский и что он находится в США). Вы можете рассматривать это как вызов приложения «search» внутри домена Bing с параметрами q, form и mkt. Все такие запросы выражаются в канонической форме, например:

https://www.bing.com/search?q=[]&form=[]&mkt=[]

В домене Bing есть и другие приложения, отвечающие на аналогичные запросы. Запрос «election results» в формате видео выглядел бы так:

https://www.bing.com/videos?q=election+results&form=PRUSEN&mkt=en-us

По мере роста онлайновых сервисов динамически добавляются новые приложения и средства — некоторые для удобства, а другие для совместимости. Для одного и того же запроса зачастую допустимы разные форматы. Bing-сервис videos принял бы и такой запрос:

http://videos.bing.com/?q=election+results&form=PRUSEN&mkt=en-us

Предполагая, что из журналов использования можно извлечь список со всеми каноническими запросами к сервису, вы могли бы выполнить проверку на уязвимости, пытаясь встраивать в значения параметров известные вредоносные данные. Например, взломщик мог бы использовать следующий запрос, чтобы удостовериться, уязвимо ли Bing-приложение videos к атакам с кросс-сайтовыми скриптами (cross-site scripting, XSS) в параметре запроса:

https://www.bing.com/videos?q=<script>alert("XSS")
</script>&form=PRUSEN&mkt=en-us

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

https://www.bing.com/videos?&form=PRUSEN&mkt=en-us&q=%3CscRipt%3Ealert(%22XSS%22)%3C%2FScriPT%3E

Вы можете написать приложение, которое принимает список канонических запросов для сервиса как ввод, встраивает вредоносные данные для каждого типа возможной уязвимости и обнаруживает ответ от сервиса в случае успешной атаки. Вы можете найти в сети код индивидуальных «детекторов» для нескольких видов уязвимостей (XSS, встраивание SQL-кода и открытое перенаправление). В этой статье мы сосредоточимся на обнаружении области, доступной для атак (attack surface), в онлайновых сервисах на основе журналов с данными использования.

Среда обработки

Сетевые журналы (Weblogs) обычно распределяются между несколькими машинами, что делает чрезвычайно эффективным последовательное чтение файла журнала (еще эффективнее, если файлы разбиваются на разделы между разными устройствами хранения в распределенной файловой системе). Таким образом, обработка сетевых журналов — хорошее применение для инфраструктуры MapReduce.

Для этого примера мы поместим Weblogs в Microsoft Azure Blobs под один и тот же контейнер InputContainer. В качестве платформы обработки мы задействуем задания Azure HDInsight Streaming MapReduce. В сети уже доступно немало информации о том, как подготовить и сконфигурировать кластеры HDInsight. Код, объясняемый в этой статье, будет генерировать двоичные файлы, которые должны помещаться в контейнер ClusterBinariesContainer, доступный кластеру HDInsight. По мере выполнения кода и обработки ввода он будет передавать вывод в другой контейнер — ClusterOutputContainer, а информация о состоянии будет сохраняться в ClusterStatusContainer. Схема конфигурации обработки в Azure HDInsight показана на рис. 1.

Среда обработки Azure HDInsight
Рис. 1. Среда обработки Azure HDInsight

Azure HDInsight Processing Конфигурация обработки в Azure HDInsight
Input Ввод
InputContainer InputContainer
InputStorageAccount InputStorageAccount
ClusterName ClusterName
Binaries Двоичные файлы
ClusterBinariesContainer ClusterBinariesContainer
Output  Вывод 
ClusterOutputContainer ClusterOutputContainer
Status  Состояние
ClusterStatusContainer ClusterStatusContainer
ClusterStorageAccount ClusterStorageAccount

Вам нужно заменить имена-заполнители (placeholder names) на рис. 1 значениями, специфичными для вашей конфигурации. Их можно задать в конфигурационном файле. Скрипт на Windows PowerShell, который будет создавать и выполнять задание HDInsight, будет считывать конфигурационный XML-файл, показанный на рис. 2. После настройки этого файла вы скорее всего запустите скрипт для анализа данных использования из командной строки Azure PowerShell — при условии, что вы должным образом сконфигурировали свою учетную запись Azure на авторизацию доступа к сервисам хранения и вычислений (см. справочную информацию по командлетам Get-AzureAccount и Add-AzureAccount).

Рис. 2. Конфигурационный XML-файл для скрипта Windows PowerShell

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
  <SubscriptionName>Your-SubscriptionName</SubscriptionName>
  <ClusterName>Your-ClusterName</ClusterName>
  <ClusterStorageAccountName>Your-ClusterStorageAccountName
    </ClusterStorageAccountName>
  <ClusterBinariesContainer>Your-ClusterBinariesContainer
    </ClusterBinariesContainer>
  <MapperBinary>UsageDataMapper.exe</MapperBinary>
  <ReducerBinary>UsageDataReducer.exe</ReducerBinary>
  <ClusterOutputContainer>Your-ClusterOutputContainer</ClusterOutputContainer>
  <ClusterStatusContainer>Your-ClusterStatusContainer</ClusterStatusContainer>
  <InputStorageAccountName>Your-InputStorageAccountName
    </InputStorageAccountName>
  <InputStorageAccountKey>Your-InputStorageAccountKey</InputStorageAccountKey>
  <InputContainer>Your-InputContainer</InputContainer>
  <DeployBinaries>true</DeployBinaries>
  <DeployFlavor>Release</DeployFlavor>
  <JobTimeOut>3600</JobTimeOut>
</Configuration>

Преобразование в канонические запросы

Чтобы получить доступную для атак область онлайновых сервисов, используя среду обработки MapReduce, создается приложение-мэппер (mapper application) для извлечения URL из Weblogs и их преобразования в каноническую форму. Это значение становится ключом для преобразователя, редуцирующего данные (reducer), который потом исключает дубликаты. Этот пример работает по тому же принципу, что и приложение-пример для подсчета слов, доступное для HDInsight. Следующий код (из которого удалены комментарии и проверки) демонстрирует главную точку входа для приложения-мэппера:

public static void Main(string[] args)
{
  Console.SetIn(new StreamReader(args[0]));
  string inputLogLine;
  while ((inputLogLine = Console.ReadLine()) != null)
  {
    string outputKeyAndValues =
      ExtractKeyAndValuesFromLogLine(inputLogLine);
    Console.WriteLine(outputKeyAndValues);
  }
}

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

#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2014-10-27 20:46:57 127.0.0.1 GET /search q=election+results&form=PRUSEN&mkt=en-us 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+6.4;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko - 200 0 0 5265

Столбцы cs-uri-stem и cs-uri-query содержат релевантную информацию, необходимую для разбора с целью получения канонической формы запроса (в код примера не включена обработка на нескольких хостах). Функция для извлечения ключа и значений из каждой строки журнала схематично показана на рис. 3.

Рис. 3. Функция для извлечения ключа и значений из строки журнала

private static string ExtractKeyAndValuesFromLogLine(string inputLogLine)
{
  StringBuilder keyAndValues = new StringBuilder();
  string[] inputColumns = inputLogLine.Split(DataFormat.MapperInputColumnSeparator);
  string uriReference = inputColumns[DataFormat.MapperInputUriReferenceColumn];
  string uriQuery = inputColumns[DataFormat.MapperInputUriQueryColumn];
  string parameterNames = ExtractParameterNamesFromQuery(uriQuery);
  // Key = uriReference + separator + parameterNames
  keyAndValues.Append(uriReference);
  keyAndValues.Append(DataFormat.ReferenceFromQuerySeparator);
  keyAndValues.Append(parameterNames);
  keyAndValues.Append(DataFormat.MapperOutputColumnSeparator);
  keyAndValues.Append(DataFormat.OneOccurrence);
  return keyAndValues.ToString();
}

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

q=election+results&form=PRUSEN&mkt=en-us

Рис. 4. Функция для получения из запроса только имен параметров

private static string ExtractParameterNamesFromQuery(string query)
{
  StringBuilder sb = new StringBuilder();
  // Проходим по каждому параметру, добавляя в строку вывода
  string[] nameValuePairs = query.Split(DataFormat.ParametersSeparator);
  Array.Sort(nameValuePairs, StringComparer.InvariantCultureIgnoreCase);
  List<string> uniqueParameterNames = new List<string>();
  foreach (string nameValuePair in nameValuePairs)
  {
    int indexOfSeparatorParameterNameFromValue =
      nameValuePair.IndexOf(DataFormat.ParameterNameFromValueSeparator);
    string paramName = nameValuePair;
    paramName = nameValuePair.Substring(0,
      indexOfSeparatorParameterNameFromValue);
    uniqueParameterNames.Add(paramName);
    sb.Append(paramName);
    sb.Append(DataFormat.ParameterNameFromValueSeparator);
    sb.Append(DataFormat.OneOccurrence);
    sb.Append(DataFormat.ParametersSeparator);
  }
  return sb.ToString();
}

Каноническая форма, используемая в примере кода, будет удалять значения параметров, сортировать имена параметров и преобразовывать их в по-прежнему допустимую строку запроса:

form=1&mkt=1&q=1&

Сортировка имен параметров помогает избежать дублирования, поскольку веб-запросы не зависят от порядка параметров. Символ подстановки для значения параметра — «1» вместо «[]», так как он короче. Это можно использовать и для других задач вроде подсчета того, сколько раз параметры встречаются во всех комбинациях параметров запросов, как показано на рис. 4.

Уменьшение области, доступной для атак

Код преобразования (mapping code) последовательно считывает строки веб-журнала, а затем выводит ключ и значение для каждой строки. В MapReduce есть стадия объединения («combine»), на которой все записи с одинаковым ключом собираются воедино для обработки кодом, редуцирующим данные. Если во входном журнале было несколько строк о выполнении запросов поиска, то к этому моменту это дает идентичный вывод:

search?form=1&mkt=1&q=1&         1
search?form=1&mkt=1&q=1&         1
search?form=1&mkt=1&q=1&         1

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

Рис. 5. Основной цикл кода, редуцирующего данные

public static void Main(string[] args)
{
  string currentKey, previousKey = null;
  int count = 0;
  Console.SetIn(new StreamReader(args[0]));
  string inputLine;
  while ((inputLine = Console.ReadLine()) != null)
  {
    string[] keyValuePair =
      inputLine.Split(DataFormat.ReducerInputColumnSeparator);
    currentKey = keyValuePair[0];
    if (currentKey != previousKey)
    {
      Console.WriteLine(DataFormat.ReducerOutputLineFormat, 
        previousKey, count);
      count = 1;
      previousKey = currentKey;
    }
    else count++;
  }
  Console.WriteLine(DataFormat.ReducerOutputLineFormat, 
    previousKey, count);
}

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

search?form=1&mkt=1&q=1&         3
video?form=1&mkt=1&q=1&           10

Вникаем в трафик сервиса

Область, доступная для атак, уже окажет неоценимую помощь в понимании того, что происходит с вашим сервисом, даже если вы не выполняли профилактическое тестирование возможностей проникновения для идентификации уязвимостей. Хотя частота запросов изменяется каждый час и зависит от конкретного дня недели и сезонных факторов, нормальное поведение за определенный период меняется при очередных выпусках или при скоординированных атаках. Например, Bing принимает сотни миллиардов запросов ежедневно. Список доступных для атак областей имеет сотни тысяч значений в день. Не все из таких путей считаются возможными. В табл. 1 суммировано, что было обнаружено в области, доступной для атак, за типичный день. В первой строке указывается, что десять самых частых канонических путей составляют 89,8% обычного трафика запросов. Следующие по частоте десять путей — это 6,3% от общего количества запросов (или 96,1% для 20 самых распространенных канонических путей). Это по-настоящему распространенные случаи применения сервиса. Все остальное составляет менее 4%. Такой шаблон запросов сильно отличается для сайта с контентом, объединенным в синдикаты (syndicated content), например для MSN.com.

Табл. 1. Типичное распределение путей запросов для Bing в 2013 г.

Канонические пути Доля
Первая десятка 89,8%
Первая двадцатка 96,1%
Пути с количеством запросов <= 1000 99,9%
Пути с количеством запросов <= 100 99,6%
Пути с количеством запросов <= 10 97,6%
Пути с количеством запросов = 1 67,5%

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

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

Обучение по данным сервиса

ML позволяет автоматизировать несколько процессов, которые было бы затруднительно реализовать прямым кодированием инструкций или правил. Например, было бы сложно понять код приложения машинного зрения (computer vision application), способного распознавать личность, которая находится в объективе камеры. Однако после включения информации о дальности (depth information) в тысячи изображений группа Kinect в Microsoft сумела «обучить» ML-модуль делать это с достаточной точностью. Такие изображения, указывающие не только на присутствие человека, но и на позицию тела, обеспечили процесс обучения.

Сервис атак, генерирующий запросы известных категорий (XSS, встраивание SQL-кода и т. д.), автоматизирует важную часть процесса, который использует ML-методы для оценки сетевого трафика. Он создает большой объем синтетических контрольных данных (ground truth, GT). Проверьте журналы использования и вы легко выявите все такие запросы-атаки, выполненные сервисом атак в определенное время. Теперь они смешаны с запросами пользователей, для которых еще нет известной классификации (нормальный или вредоносный запрос).

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

Предполагая, что у вас есть высококачественные контрольные данные (GT) и адекватные инструменты, итеративный цикл процесса обучения для ML-решения, который оценивает запросы пользователей, можно схематически представить так, как показано на рис. 6. Начиная с синтетических данных в GT, вы можете выполнять эксперименты и запускать процесс обучения в ML-модуле для классификации запросов (по таким категориям, как обычный, XSS, встраивание SQL-кода и т. д.) или регрессии (указывая достоверность запроса, относящегося к одной или более категориям). Затем вы могли бы развернуть этот ML-модуль как часть решения и начать прием запросов оценки (evaluation requests). Вывод передается процессу оценки результатов, который будет показывать корректно идентифицируемые ML-модулем запросы (истинно положительные и истинно негативные), пропущенные подозрительные запросы (ложно отрицательные) или вызывающие ложную тревогу (ложно положительные).

Цикл обучения для создания решения на основе ML
Рис. 6. Цикл обучения для создания решения на основе ML

Learning Cycle Цикл обучения
Scoring Результат
Action Действие
True Positive Истинно положительный
True Negative Истинно отрицательный
False Positive Ложно положительный
False Negative Ложно отрицательный
Boosting GT Увеличение GT
Ground Truth: “Training Data” (Log Labeled Data) Контрольные данные: «обучающие данные» (данные с меткой в журнале)
Feature Experiments Эксперименты по выявлению критериев
ML Training ML-обучение
Solution Решение
ML Module ML-модуль
Prepare Features Подготовка критериев
Classification or Regression Классификация или регрессия
Scoring Process Процесс оценки результата

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

Заключение

Хотя вы должны по-прежнему следовать четко определенным процессам разработки (включая Security Development Lifecycle), вы также должны исходить из того, что ваш онлайновый сервис в любой момент может быть атакован. Журналы использования могут предоставить глубокую информацию о том, как происходят атаки. Знание области, доступной для атак, поможет вам заранее проверить свой сервис на стойкость к атакам, чтобы выявить и закрыть бреши до того, как ими станут пользоваться. Создание такого сервиса атак позволяет создать синтетические контрольные данные, позволяющие применять методы ML для обучения ML-модуля, оценивающего запросы к сервису. Разработка сервиса атак — задача не из тривиальных, но моментальные и долгосрочные результаты для бизнеса с лихвой окупят вложения в такую разработку.


Элиссон Сол (Alisson Sol) — ведущий архитектор в Microsoft. Имеет многолетний опыт разработки ПО в области обработки изображений, их распознавания компьютером, ERP и бизнес-анализа, больших данных (Big Data), машинного обучения и распределенных систем. До перехода в Microsoft в 2000 году был соучредителем трех компаний, выпускавших ПО, опубликовал несколько технических статей и запатентовал несколько приложений. Читайте его блог AlissonSol.com/blog.

Дон Энкни (Don Ankney) — старший научный сотрудник в области безопасности в Microsoft Information Platform Group, где работает над применением знаний, накопленных Microsoft в машинном обучении, к защите сервисов. Был соучредителем Black Lodge Research, образовательной и некоммерческой организации, которая уделяла основное внимание безопасности и проводила регулярное обучение методам безопасной разработки на региональных семинарах, симпозиумах и конференциях под эгидой ООН.

Юджин Бобук (Eugene Bobukh) — старший менеджер программ по безопасности и данным в Microsoft. Основное внимание уделяет применению научных подходов к проблемам безопасности, руководил тестированием защиты и анализировал безопасность более 200 выпусков продуктов Microsoft с 2000 года, в том числе .NET, Silverlight и Internet Explorer. Часть своей работы описывает в блоге blogs.msdn.com/b/eugene_bobukh.

Выражаем благодарность за рецензирование статьи экспертам Microsoft Барри Марки (Barry Markey) и Вирешу Рамдатмисиеру (Viresh Ramdatmisier).