Создайте фильтр вирусов для своего сервера Exchange

.

После атаки вируса SoBig нам пришлось вручную фильтровать примерно 1 Гбайт почты в день. Большая часть почты появлялась из-за вируса и постоянных сообщений с предупреждением о вирусе, которые проникали на наш сервер. Наш сервер должен был не только обрабатывать каждое полученное почтовое сообщение, но и жертвовать дисковым пространством для его сохранения и пропускной способностью сети - для его перемещения в папки Inbox клиентов Microsoft Outlook. После этого фильтры Outlook тратили время и поглощали ресурсы, чтобы удалить сообщение из папки Inbox и дать серверу команду для удаления сообщения из пользовательского почтового ящика Exchange. Мы решили написать сценарий на Perl, предназначенный для запуска на нашем сервере Exchange. Он должен был предотвращать попадание на сервер входящих сообщений, которые могут оказаться вирусами.

Написать сценарий оказалось на удивление просто, благодаря объектам Microsoft Collaboration Data Objects (CDO). Код исполняется на любом компьютере с системой Windows, использующей службу SMTP, в том числе на системах Windows Server 2003 и Windows XP. Так как Exchange Server 2003 и Exchange 2000 Server используют в качестве основы службу SMTP, решение с тем же успехом работает и с ними.

Служба Windows SMTP

Windows 2000 и более новые операционные системы содержат службу SMTP (электронная почта), которую Web-страницы и приложения используют для отправки электронных сообщений. Когда на системе запущена служба SMTP, Web-страницы и приложения могут просто передавать службе исходящие сообщения, которые она в свою очередь отправляет на соответствующие почтовые серверы. Среди набора объектов COM содержатся объекты CDO, которые предоставляют простой способ доступа к службам пересылки сообщений в Windows, в том числе к сообщениям SMTP. Объекты CDO сглаживают множество шероховатостей при работе с технологиями создания соединений, упрощая взаимодействие разработчиков с этими службами. Чтобы получить подробную информацию об объектах CDO, следует просмотреть документ по адресу http://msdn.microsoft.com/library/en-us/cdo/html/_olemsg_overview_of_cdo.asp.

Обработчики пересылки CDO

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

Обработчики пересылки могут выполнять действия на основе содержимого сообщения. Обработчики пересылки SMTP обрабатывают события, возникающие при получении службой SMTP сообщения электронной почты. Когда входящее сообщение попадает на сервер (инициируя событие OnArrival()), обработчик пересылки может вызвать сценарий Windows Script Host (WSH), загрузить его и вызвать процедуру сценария ISMTPOnArrival_OnArrival(), если таковая существует. Более подробно об этом можно узнать по адресу http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_smtp_nntp_transport_event_sinks_with_cdo.asp.

Принцип работы сценария пересылки

В Листинге 1 представлен сценарий MessageFilter.pl, используемый обработчиком пересылки. Необходимо разместить код сценария между тэгами XML, которые сообщают обработчику пересылки, какой язык написания сценариев надо использовать. Код во фрагментах A и J в Листинге 1 содержит тэги, которые определяют использование механизма PerlScript. Эти тэги позволяют сценарию задействовать любое расширение файла (или не использовать их совсем). Символ комментария (#) языка Perl в начале каждого тэга дает возможность запускать сценарий и из обработчика, и из командной строки (например, для тестирования сценария) без возникновения ошибок компиляции.

Когда обработчик пересылки исполняет сценарий, он сначала исполняет весь код в заданном по умолчанию пространстве имен или в пространстве имен main::. Далее обработчик ищет в сценарии процедуру с именем ISMTPOnArrival_OnArrival() и вызывает эту процедуру, если она существует. Процедура получает два параметра, как мы видим в коде фрагмента E - объекты $Message (объект сообщения) и $EventStatus (значение статуса события). Сценарий может запрашивать свойства объекта сообщения, чтобы получить информацию, такую как имя отправителя сообщения, список адресатов, тема сообщения. Список всех свойств объекта сообщения можно найти на странице http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_imessage_interface.asp.

Предполагается, что сценарий устанавливает поле CdoEventStatus в значение, информирующее о состоянии обработки сообщения сценарием. Например, если сценарий определяет, что сообщение содержит вирус и должно быть отбраковано, он должен иметь возможность установить поле CdoEventStatus в значение cdoSkipRemainingSinks (1), чтобы показать, что в ходе работы последующих обработчиков не требуется обработка сообщения. По умолчанию поле статуса события устанавливается в значение cdoRunNextSink (0), которое указывает, что сообщение безопасно и последующие обработчики должны проводить его обработку.

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

После загрузки сценария обработчик пересылки, основанный на объектах CDO, помещает результирующий объект WSH в память. Чтобы оптимизировать производительность, обработчик пересылки использует размещенный в памяти объект всякий раз, когда необходимо вызвать сценарий. Другими словами, сценарий Perl компилируется только один раз, но выполняется неоднократно. Если вы изменяете сценарий, обработчик пересылки определяет время изменения файла и перезагружает сценарий. В результате вы получаете повышение производительности за счет процесса размещения сценария в памяти, без обращения к диску при каждом его использовании. Информацию об использовании языков сценариев для реализации обработчиков событий и о том, каким образом обработчик размещает сценарий в памяти, можно найти на странице http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_implementing_sinks_with_scripting_languages.asp.

MessageFilter.pl

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

В коде фрагмента B сценарий MessageFilter.pl устанавливает переменную $LOG_PATH, которая хранит путь к файлам журнала, содержащим дату, время, тему и имя отправителя для каждого забракованного почтового сообщения. Код фрагмента C содержит список нежелательных тем сообщений и расширений файлов. Если сообщение имеет тему или расширение прикрепленного файла, указанные в списке, сценарий отбраковывает данное сообщение. Можно добавить собственные темы и расширения в соответствующий массив.

Для создания массива @UNWANTED_SUBJECTS_REGEX сценарий использует команду отображения языка Perl, чтобы обработать каждую строку перед добавлением в массив. При обработке используется оператор запроса стандартного расширения qr//, который возвращает скомпилированное регулярное расширение. Применение предварительно скомпилированного регулярного расширения не только упрощает сценарий, но и до некоторой степени увеличивает его производительность. Так как темы, содержащиеся в массиве @UNWANTED_SUBJECTS_REGEX, являются подстроками, сценарий MessageFilter.pl отбраковывает сообщения, если их тема содержит строку, занесенную в список.

Массив @UNWANTED_EXTENSIONS включает список расширений файла, которые сценарий сравнивает с любым файлом, прикрепленным к входящему почтовому сообщению. Если расширение прикрепленного файла совпадает с расширением из списка, сценарий отбраковывает сообщение. В отличие от массива нежелательных тем, массив @UNWANTED_EXTENSIONS - это обычный массив строк. Сценарий использует символ (|), который в регулярном расширении выполняет роль оператора ИЛИ, чтобы присоединить все элементы массива. Далее сценарий использует оператор запроса qr// для создания переменной $UNWANTED_EXTENSIONS_REGEX, которая содержит скомпилированное регулярное расширение, состоящее из расширений присоединенных файлов.

Для каждого почтового сообщения, которое получает Exchange, обработчик пересылки сначала исполняет код фрагмента A, используя код фрагмента D. Код фрагмента D устанавливает некоторые константы объектов CDO, которые сценарий будет применять в дальнейшем. Затем обработчик пересылки вызывает процедуру ISMTPOnArrival_OnArrival(). Все глобальные переменные, созданные в заданном по умолчанию пространстве имен, остаются доступными.

Процедуры

Процедура ISMTPOnArrival_OnArrival() сначала устанавливает переменные $Message и $EventStatus в значения, которые обработчик пересылки передает сценарию. Переменная $Message - это объект COM, который предоставляет доступ к интерфейсу IMessage. Этот объект COM содержит всю доступную информацию о почтовом сообщении (например, имя отправителя, время получения). Процедура всегда устанавливает переменную $EventStatus в значение 0 (эквивалент переменной $cdoRunNextSink). Однако по причинам, описанным выше, вы можете игнорировать данную переменную.

Код фрагмента F - это реальный механизм сценария. Сначала он вызывает процедуры IsSubjectExcluded() и IsExtensionExcluded(), которые вместе определяют, должно ли сообщение быть отбраковано. Если это так, сценарий устанавливает поле messagestatus объекта EnvelopeFields, который является элементом набора, таким образом, чтобы сообщить службе SMTP о том, что данное сообщение надо отклонить.

Интерфейс IMessage имеет свойство, названное EnvelopeFields, которое возвращает объект EnvelopeFields. Набор EnvelopeFields определяет множество полей, которые описывают сообщение при передаче через службу SMTP. В поле messagestatus можно указать, нужно ли поместить сообщение в почтовый ящик пользователя, отбраковано ли оно или помещено в почтовый ящик нежелательной почты.

Сценарий MessageFilter.pl присваивает полю messagestatus значение, соответствующее отбраковке сообщения. Для этого сценарий обращается к Uniform Resource Identifier (URI) с именем http://schemas.microsoft.com/cdo/smtpenvelope/messagestatus. Как показано во фрагменте F, сценарий создает переменную $Fields, связывает поле messagestatus набора EnvelopeFields с этой переменной и присваивает полю значение $cdoStatAbortDelivery (2). Это неудобный способ установки значения, но сценарий делает это только один раз.

Далее, код фрагмента F вызывает метод Update() набора EnvelopeFields, чтобы гарантировать, что статус сообщения обновлен. Объект CDO помещает набор EnvelopeFields в память, чтобы увеличить производительность, а вызов метод Update() переносит изменения с сохраненного в памяти объекта на реальное сообщение. После этого сценарий устанавливает код результата (переменная $Result) в значение $cdoSkipRemainingSinks (1). Наконец, сценарий заносит в журнал запись о том, что сообщение было отбраковано.

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

Процедура IsExtensionExcluded() возвращает значение 1, если сообщение должно быть отбраковано на основании расширения присоединенного файла. Однако, как показывает код фрагмента H, эта процедура использует другую логику. Процедура проверяет свойства коллекции Attachments объекта сообщения. Когда сообщение содержит прикрепленный файл, процедура рассматривает каждый присоединенный файл и сравнивает его имя с предварительно скомпилированным регулярным расширением $UNWANTED_EXTENSIONS_REGEX. Когда процедура находит прикрепленный файл, который имеет одно из расширений, указанных в массиве нежелательных расширений, она возвращает значение 1, указывающее, что сообщение должно быть отбраковано.

Наконец, когда сценарий отправляет данные в файл журнала, он исполняет код фрагмента I. Этот код сначала проверяет, доступен ли дескриптор журнала, чтобы определить, открыт ли файл. Если дескриптор недоступен, процедура пытается открыть файл журнала и устанавливает флаг автозаполнения в значение 1 (включено). Журнал открывается в этот момент, вместо того, чтобы открываться ранее по сценарию, для того чтобы повысить производительность; если в журнал ничего не записывается, нет причины открывать файл журнала. Я включал флаг автозаполнения, чтобы упростить управление журналом во время тестирования. Запуская сценарий в работу, вы можете установить флаг автозаполнения в значение 0 (отключено). При однократной записи в журнал между значениями 0 и 1 флага нет существенной разницы в производительности.

Установка и настройка службы SMTP

Чтобы установить службу SMTP, следует открыть приложение Add/Remove Programs из меню Control Panel. В левой панели нужно выбрать режим Select Add/Remove Windows Components, указать компонент Internet Information Services (IIS) и нажать кнопку Details. Выберите службу SMTP, нажмите кнопку OK, потом нажмите Next, и Windows установит службу.

Можно использовать оснастку IIS консоли Microsoft Management Console (MMC) для настройки службы SMTP и отслеживания подсоединенных пользователей. По умолчанию служба SMTP перенаправляет почту на другие серверы SMTP и принимает почту только для полного DNS-имени локальной машины. Таким образом, служба принимает всю входящую почту, адреса которой оканчиваются полным именем домена компьютера. Например, если имя моего компьютера - MyMachine, а имя домена - roth.net, служба SMTP принимает сообщения, отправленные на любой адрес, заканчивающийся фразой @MyMachine.roth.net. Сервер DNS должен содержать запись, которая отображает полное имя DNS вашего компьютера на IP-адрес, или сервер DNS должен иметь, по крайней мере, запись MX.

Установка PerlScript

Для того чтобы корректно исполнить сценарий MessageFilter.pl, необходимо зарегистрировать PerlScript WSH. После того как вы корректно установите пакет ActivePerl от ActiveState, ActivePerl зарегистрирует механизм WSH. Чтобы проверить, зарегистрирован ли механизм PerlScript, введите в командной строке следующее выражение:

cscript /e:PerlScript C:AnyFilename

где под фразой C:AnyFilename подразумевается любое имя файла, причем файл необязательно должен существовать. Хотя эта команда приводится здесь, разбитая на несколько строк, вы вводите ее одной строкой в окне командной оболочки. Это справедливо и для других многостроковых команд, приведенных в данной статье. Если механизм PerlScript не регистрируется, команда вернет сообщение об ошибке: can't find the script engine 'PerlScript'. После регистрации механизма PerlScript команда пытается загрузить указанный файл. Если имя файла указывает на существующий файл типа Perl, он запускается; в противном случае система выдаст сообщение об ошибке. Если механизм PerlScript не регистрируется, следует зарегистрировать его, перейдя в папку исполняемых файлов Perl (где находится файл perl.exe) и введя в командной строке следующую фразу:

regsvr32 PerlSE.dll

Установка сценария

Установка сценария MessageFilter.pl, возможно, является самой сложной частью работы с ним. Подробная информация о том, как установить сценарий обработчика пересылки, выходит за рамки нашей статьи; однако простое средство от компании Microsoft, названное SMTPReg.vbs, значительно упрощает работу. Вы можете загрузить сценарий SMTPReg.vbsс на странице http://msdn.microsoft.com/library/en-us/smtpevt/html/_smtpevt_smtpreg_vbs_event_management_script.asp. Информацию об этом средстве можно найти по адресу http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_enabling_or_disabling_a_binding.asp.

Для установки сценария MessageFilter.pl следует первым делом передать управление обработчику пересылки, основанному на объектах CDO, чтобы создать отображение между определенным событием (в данном случае событием OnArrival(), которое инициируется при получении сообщения службой SMTP) и определенным именем. Имя - это случайное имя, которое вводится для идентификации отображения. Я предпочитаю использовать имя, которое отображает суть сценария. Вы будете использовать это имя, если со временем захотите отключить или удалить сценарий. Вы указываете несколько параметров, когда создаете соединение, но в большинстве случаев будет достаточно изменить лишь имя, для остальных параметров можно использовать значения, заданные по умолчанию. Для каждого сценария, который вы добавляете (каждого соединения, которое создаете), необходимо указывать собственное имя, отличное от других. Для создания соединения под названием MessageFilter нужно ввести в командную строку следующую команду:

cscript.exe smtpreg.vbs
/add 1 onarrival
MessageFilter
CDO.SS_SMTPOnArrivalSink
"MAIL FROM=*"

Затем вы настраиваете данное соединение, связывая его со сценарием (указывая на сценарий):

cscript.exe smtpreg.vbs
/setprop 1 onarrival
MessageFilter Sink
ScriptName
"C:MessageFilter.pl"

Теперь любое новое сообщение, которое получит служба SMTP, вызовет исполнение сценария MessageFilter.pl. Остается только убедиться в том, что служба SMTP работает.

Для удаления сценария нужно набрать

cscript.exe smtpreg.vbs /remove
1 onarrival MessageFilter

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

cscript.exe smtpreg.vbs /enum

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

Тестирование и отладка

Для тестирования сценария отладчика пересылки зарегистрируйте его и отправьте почтовое сообщение на тот компьютер, где работает служба SMTP. Например, вы могли бы запустить Outlook Express и послать сообщение любому пользователю в домене LocalHost (например, test@localhost). Для настройки службы таким образом, чтобы для нее существовал домен LocalHost, нужно открыть оснастку IIS. Расширьте дерево SMTP Server, предложенное по умолчанию, и выберите узел Domains. Щелкните правой кнопкой на узле и выберите New, Domain. Мастер New SMTP Domain Wizard спросит, домен какого типа требуется создать: удаленный (Remote) или локальный (Alias). Создайте локальный домен с именем localhost. После этого вы сможете использовать этот домен для получения сообщений, отправленных с компьютера.

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

Привлекательное решение

Исходя из собственного опыта, могу сказать, что пакеты Perl 5.8 и Perl 5.6 работают одинаково хорошо. Однако, по-видимому, служба Perl 5.5 вызывает периодические сбои в работе оснастки IIS. Я рекомендую использовать последнюю версию пакета ActivePerl для сценария MessageFilter.pl.

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

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

Кроме того, можно написать некоторые интересные вариации сценария MessageFilter.pl. Например, вы могли бы добавить сценарии, чтобы проводить фильтрацию спама (для выполнения этой задачи существуют бесплатно распространяемые программы, и даже написанные на языке Perl библиотеки), разумную маршрутизацию сообщений, проверку на вирусы, удаление HTML-кода из почты (или удаление привязки к рисункам и ссылкам). А когда появится новый вирус «du jour», вы сможете легко обезопасить свой Exchange-сервер, добавив несколько строк в сценарий MessageFilter.pl.


ЛИСТИНГ 1. Сценарий "MessageFilter.pl"
# Начало блока Callout A
#
# Конец блока Callout J