Оригинальный адрес статьи: http:// amsand.narod.ru / articles / dspam.html

Настраиваем DSPAM - ваш личный спам-фильтр

Опубликована в журнале "Системный администратор", Август 2005 года

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

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

Сегодняшняя статья посвящена второму эшелону спам-обороны, который будем строить на базе DSPAM (разработчик Jonathan Zdziarski, www.nuclearelephant.com). Данная обучаемая статистическая система обрабатывает сообщения, благополучно прошедшие через MTA и направляющиеся в ящик пользователя. Основным ее достоинством является возможность персональной настройки для каждого пользователя.

Как происходит классификация писем

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


P= S / (S + G)                          	       (1), 

где 	P - вероятность того, что сообщение окажется спамом,
	S - суммарный коэффициент "спамности" сообщения,
	G - суммарный коэффициент "неспамности" сообщения.

Sи G рассчитываются по следующим формулам:

S = p(w1)*p(w2)*:*p(wn) (2) G = (1 - p(w1))*(1 - p(w2))*:*(1 - p(wn)) .

Здесь p(w1) и другие - коэффициенты "спамности" отдельных слов, входящих в анализируемое сообщение, полученные на основе ранее классифицированных писем. Так, если в прошлом 9 писем со словом "английский" было спамом и одно - не спамом, то p('английский') = 9 / (9 + 1) = 0.9.

В качестве примера проанализируем такое короткое сообщение:

Привет! Купи меня!

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

Слово	Спам	Не спам
Привет	35	64
Купи	187	19
меня	9	11

p('Привет') = 35 / (35 + 64) = 0,35
p('Купи') = 187 / (187 + 19) = 0,91
p('меня') = 9 / (9 + 11) = 0,45
S= 0,35 * 0,91 * 0,45 = 0,14
G= (1 - 0,35) * (1 - 0,91) * (1 - 0,45) = 0,03
P= 0,14 / (0,14 + 0,03) = 0,82

Таким образом, приведенный выше пример будет с вероятностью 82% нежелательным сообщением, в основном за счет высокой спамности слова "Купи".

В алгоритме, предложенном Полом Грэмом (Paul Graham), для расчета применяется приведенная выше методика с использованием следующих правил:

Алгоритм Бартона (Brian Burton) работает аналогично, но использует для анализа не 15, а 27 наиболее ярких слов, а также допускает "удвоенное" использование слова, если оно встречается в сообщении несколько раз. Это несколько повышает эффективность при ограниченных данных. Кроме того, поддерживаются цепочки "токенов", когда два стоящих рядом слова рассматриваются вместе. Так же некоторые отличия от подхода Грэма имеются в наборе символов, которые считаются составной частью слова (такие как $, ! и т.д.).

Следующий популярный алгоритм, разработанный Гари Робинсоном (Gary Robinson), модернизирует формулу Грэма таким образом, чтобы решить проблему недостаточных исторических данных:

f(w) = (0,5 + n(w) * p(w)) / (1 + n(w))                   (3)

где 	p(w) - вероятность для слова, рассчитанная на основе исторических данных,
	n(w) - количество ранее обработанных сообщений со словом w.

Таким образом, если анализируемое слово ранее не встречалось, оно автоматически получит коэффициент 0,5, а по мере накопления статистики это значение будет выходить на свой естественный уровень.

В дальнейшем в формулах (2) вместо величин p(w) используется f(w).

Для анализа по алгоритму Робинсона используется выборка из 25-ти слов.

На базе алгоритма Робинсона был разработан улучшенный алгоритм Фишера-Робинсона, известный также как Chi-Square (переводить на русский язык не рискну). Помимо расчета "спамности" сообщения вычисляется также вероятность его "неспамности" по формуле Фишера, и в дальнейшем рассматривается интегральная вероятность.

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

Способы интеграции DSPAM с почтовой системой

Система DSPAM поддерживает два способа взаимодействия с почтовым сервером. В первом случае он может быть настроен как локальный агент доставки (LDA - local delivery agent). При этом сообщения анализируются по пути от MTA к почтовому ящику. После обработки фильтром почта отдается на обработку реальному LDA, который и завершает доставку.

Второй способ - работа DSPAM в сотрудничестве с POP3-proxy. При этом спам отсеивается в то время, когда пользователь выкачивает корреспонденцию из своего почтового ящика по протоколу POP3.

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

Устанавливаем DSPAM из коллекции портов

Для конкретизации, в данной статье будет рассматриваться работа DSPAM на системе со следующим версиями программного обеспечения:

Наиболее удобный способ инсталляции ПО в системе FreeBSD (естественно, на мой взгляд - навязываться никому не буду) - использование коллекции портов.

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

root# cd /usr/ports/mail/dspam
root# vi Makefile
root# make
root# make install

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

Я выполнил только одну правку (серым показана исключенная строка, зеленым - добавленная):

DSPAM_MODE?=    4510
DSPAM_OWNER?=   root
DSPAM_GROUP?=   mail

DSPAM_HOME?=    ${_VAR_DIR}/db/dspam
#DSPAM_HOME_OWNER?=     ${DSPAM_OWNER}
DSPAM_HOME_OWNER?=      dspam
DSPAM_HOME_GROUP?=      ${DSPAM_GROUP}
DSPAM_HOME_MODE?=       

Этой настройкой владельцем домашнего каталога программы dspam, в котором будут храниться файлы настроек пользователей, их ящики-карантины, лог-файлы и т.д., мы объявляем созданного пользователя dspam. В дальнейшем это существенно упростит нам жизнь при настройке CGI-клиента. Сам же демон dspam будет работать с правами root, что определяется второй строкой приведенного выше фрагмента (см. следующий раздел про права доступа). Если вам удобнее работать с ключами команды make, то же самое можно сделать, задав ключ DSPAM_HOME_OWNER=dspam.

После ввода команды make, вам будет предложено диалоговое окно (рисунок 1), в котором следует отметить необходимые опции. Обратите внимание на то, что должен быть отмечен только один драйвер СУБД. Так же отметьте опцию "Install CGI (pulls in apache)", если планируете использовать CGI-модуль. Еще следует указать используемый вами MTA.

Некоторые другие полезные опции приведены ниже:

После сборки (необходимые зависимости, такие как библиотека GD, будут удовлетворены автоматически) переходим к конфигурации.

Несколько слов о правах доступа

Для нормальной работы DSPAM большое значение играют правильно установленные права доступа, особенно если используется CGI-модуль. Как было показано выше, в процессе сборки порта можно задать пользователя, отличного от root. С одной стороны, это способствует повышению безопасности, но в то же время порождает массу дополнительных сложностей.

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

Во-вторых, dspam должен иметь достаточно прав, чтобы создать pid-файл при запуске в режиме демона, а также быть способным создать сокет на привилегированном порту 24 (LMTP), что опять-таки требует прав суперпользователя.

Так, у меня попытка запустить dspam в режиме демона после сборки с пользователем dspam, указанным как владелец, завершилась такими ошибками:

root# /usr/local/etc/rc.d/dspam.sh start
Starting dspam.
root# 486: [7/26/2005 9:10:17] Daemon process starting
486: [7/26/2005 9:10:18] Unable to open file for writing: /var/run/dspam.pid: Permission denied
486: [7/26/2005 9:10:18] Could not bind to :24 (Permission denied)
486: [7/26/2005 9:10:18] daemon_listen() failed
486: [7/26/2005 9:10:18] Daemon process exiting

Учитывая вышеизложенное, я решил оставить владельцем dspam пользователя root, как это определено по умолчанию. Хотя, при наличии огромного желания и крепких нервов, можно добиться работы и от имени непривилегированного пользователя.

Основные настройки в dspam.conf

Перед первым запуском необходимо переименовать файл /usr/local/etc/dspam.conf.sample в dspam.conf, и произвести в нем нужные изменения. Прежде всего, введите правильные настройки для взаимодействия с СУБД. DSPAM умеет использовать для хранения рабочей информации такие СУБД как MySQL, PostgreSQL, SQLite, Oracle. Для слабо нагруженных систем можно использовать DB3 или DB4, но разработчики это не рекомендуют. Например, мои значения для PostgreSQL выглядят следующим образом:

PgSQLServer     127.0.0.1
PgSQLPort       5432
PgSQLUser       dspam
PgSQLPass       wj30sh3hs32
PgSQLDb         dspam

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

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

# Most operating system defaults:
#TrustedDeliveryAgent "/usr/bin/procmail"       # Linux
#TrustedDeliveryAgent "/usr/bin/mail"           # Solaris
TrustedDeliveryAgent "/usr/libexec/mail.local" # FreeBSD
#TrustedDeliveryAgent "/usr/bin/procmail"       # Cygwin
#
# Other popular configurations:
#TrustedDeliveryAgent "/usr/cyrus/bin/deliver"  # Cyrus
#TrustedDeliveryAgent "/bin/maildrop"           # Maildrop
#TrustedDeliveryAgent "/usr/local/sbin/exim -oMr spam-scanned" # Exim

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

Trust root
#Trust mail
#Trust mailnull
Trust smmsp
Trust daemon
Trust dspam

Режим обучения (TrainingMode), используемые алгоритмы и т.д. можно оставить по умолчанию. Если же вам захочется поэкспериментировать, или работа с текущими настройками будет показывать неудовлетворительные результаты, в файле /usr/local/share/doc/dspam/README можно найти достаточно подробное описание доступных режимов (см. также раздел "Обучаем фильтр" далее в этой статье).

Среди параметров Feature отметим две следующие:

Featurechained
Featurewhitelist

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

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

Группы строк Preference задают параметры по умолчанию:

Preference "spamAction=quarantine"		# 'quarantine' or 'tag'
Preference "signatureLocation=message" 	# 'message' or 'headers'
Preference "showFactors=off"
Preference "spamSubject=SPAM"

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

AllowOverridetrainingMode
AllowOverride whitelistThreshold

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

Настраиваем СУБД для работы с DSPAM

Примеры настройки взаимодействия с конкретной СУБД можно найти в соответствующих README-файлах. В данной статье рассмотрим работу с PostgreSQL.

В /usr/local/share/examples/dspam/pgsql располагаются sql-файлы, содержащие необходимые для работы команды. Сейчас нас интересует файл pgsql_objects.sql, который поможет создать все нужные таблицы, индексы и т.д. Но базу данных и пользователя придется создать самостоятельно (хотя вы можете использовать и уже существующие). Последовательность нужных шагов представлена на следующем листинге:

root# cd /usr/local/share/examples/dspam/pgsql
root# psql -U pgsql template1
Добро пожаловать в psql 8.0.2 - Интерактивный Терминал PostgreSQL.

Наберите:  \copyright для условий распространения
           \h для подсказки по SQL командам
           \? для подсказки по командам psql
           \g или наберите ";" для завершения запроса и его выполнения
           \q для выхода

template1=# create user dspam nocreatedb nocreateuser password 'wj30sh3hs32';
CREATE USER
template1=# create database dspam owner dspam;
CREATE DATABASE
template1=# \c dspam dspam
Вы подсоединились к базе данных "dspam" как пользователь "dspam".
dspam=> \! ls
pgsql_objects.sql       purge.sql               virtual_users.sql
dspam=> \i pgsql_objects.sql
psql:pgsql_objects.sql:10: NOTICE:  CREATE TABLE / UNIQUE 
создаст подразумеваемый индекс "dspam_token_data_token_key" 
для таблицы "dspam_token_data"
CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
psql:pgsql_objects.sql:24: NOTICE:  CREATE TABLE / UNIQUE 
создаст подразумеваемый индекс "dspam_signature_data_signature_key" 
для таблицы "dspam_signature_data"
CREATE TABLE
psql:pgsql_objects.sql:36: NOTICE:  CREATE TABLE / PRIMARY KEY 
создаст подразумеваемый индекс "dspam_stats_pkey" 
для таблицы "dspam_stats"
CREATE TABLE
psql:pgsql_objects.sql:44: NOTICE:  CREATE TABLE / UNIQUE 
создаст подразумеваемый индекс "dspam_neural_data_node_key" 
для таблицы "dspam_neural_data"
CREATE TABLE
CREATE INDEX
psql:pgsql_objects.sql:55: NOTICE:  CREATE TABLE / UNIQUE 
создаст подразумеваемый индекс "dspam_neural_decisions_signature_key" 
для таблицы "dspam_neural_decisions"
CREATE TABLE
psql:pgsql_objects.sql:62: NOTICE:  CREATE TABLE / UNIQUE 
создаст подразумеваемый индекс "dspam_preferences_preference_key" 
для таблицы "dspam_preferences"
CREATE TABLE
dspam=>

Здесь мы создали пользователя dspam и одноименную базу данных (должны соответствовать настройкам в dspam.conf). Затем выполнили команды из внешнего файла. Теперь осталось убедиться, что в файле pg_hga.conf содержатся разрешающие строки для локальных подключений к этой базе от имени соответствующего пользователя, например, такие:

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# "local" is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
host    all         all         127.0.0.1/32          trust

Все. База данных к работе готова.

Настраиваем DSPAM для работы как LDA

В этом режиме почтовый сервер (MTA) конфигурируется таким образом, чтобы в качестве локального агента доставки выступал dspam. Способы "прикручивания" DSPAM к конкретному MTA подробно описываются в соответствующих документах:

serg$ ls /usr/local/share/doc/dspam/*
/usr/local/share/doc/dspam/courier.txt
/usr/local/share/doc/dspam/exim.txt
/usr/local/share/doc/dspam/postfix.txt
/usr/local/share/doc/dspam/qmail.txt
/usr/local/share/doc/dspam/sendmail.txt
Например, для sendmail следует указать в mc-файле следующие строки:
define(`LOCAL_MAILER_PATH', `/usr/local/bin/dspam')dnl
define(`LOCAL_MAILER_ARGS', `dspam "--deliver=innocent,spam" --user $u -d %u')dnl

Они должны быть добавлены до строки "MAILER(local)". Здесь объявляется путь до агента доставки и его параметры запуска. Параметр --deliver указывает, что должны доставляться как "хорошие" письма (innocent), так и спам (spam). Чтобы на реальный LDA письма, признанные спамом, не передавались, удалите соответствующее упоминание из строки параметров.

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

Настраиваем в режиме POP3-proxy

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

Скачиваем последний архив с pop3filter.sourceforge.net (в портах он отсутствует):

root# tar -xvzf pop3filter-0.5.5.tar.gz
root# cd pop3filter-0.5.5
root#./configure
root# make

Вот здесь поджидала еще одна неприятность (вторая после отсутствия приложения в коллекции портов) - сборка окончилась ошибкой:

if gcc -DHAVE_CONFIG_H -I. -I. -I..      -pedantic -Wall -pedantic-errors -MT 
newopt.o -MD -MP -MF ".deps/newopt.Tpo"  -c -o newopt.o `test -f 'newopt.c' || 
echo './'`newopt.c;  then mv -f ".deps/newopt.Tpo" ".deps/newopt.Po";  else r
m -f ".deps/newopt.Tpo"; exit 1;  fi
newopt.c: In function `process':
newopt.c:464: error: ISO C forbids conversion of object pointer to function pointer type
newopt.c: At top level:
newopt.c:146: warning: 'clone_argv' defined but not used
*** Error code 1

Поверхностный анализ исходного кода показал, что проблемные строки (464-я в файле newopt.c и еще несколько в main.c) используются только для обеспечения работы ключей --help и --version. Поскольку данными функциями вполне можно пренебречь, было принято решение о небольшом хирургическом вмешательстве в указанные два файла (показаны различия в исходном и полученном файлах):

serg$ diff src/main.c.old src/main.c
117,126c117,123
<       {/*00*/ {"help",        OPT_NORMAL, 0,  OPT_T_FUNCT, (void *) help },
<        /*01*/ {"h",           OPT_NORMAL, 1,  OPT_T_FUNCT, (void *) help },
<        /*02*/ {"version",     OPT_NORMAL, 0,  OPT_T_FUNCT, (void *) version},
<        /*03*/ {"V",           OPT_NORMAL, 1,  OPT_T_FUNCT, (void *) version},
<        /*04*/ {"fork",        OPT_NORMAL, 0,  OPT_T_FLAG,  NULL },
<        /*05*/ {"f",           OPT_NORMAL, 1,  OPT_T_FLAG,  NULL },
<        /*06*/ {"e",           OPT_NORMAL, 1,  OPT_T_GENER, NULL },
<        /*07*/ {"listen",      OPT_NORMAL, 0,  OPT_T_GENER, NULL },
<        /*08*/ {"user",        OPT_NORMAL, 0,  OPT_T_GENER, NULL },
<        /*09*/ {"group",       OPT_NORMAL, 0,  OPT_T_GENER, NULL },
---
>       {
>        /*04-0*/       {"fork",        OPT_NORMAL, 0,  OPT_T_FLAG,  NULL },
>        /*05-1*/       {"f",           OPT_NORMAL, 1,  OPT_T_FLAG,  NULL },
>        /*06-2*/       {"e",           OPT_NORMAL, 1,  OPT_T_GENER, NULL },
>        /*07-3*/       {"listen",      OPT_NORMAL, 0,  OPT_T_GENER, NULL },
>        /*08-4*/       {"user",        OPT_NORMAL, 0,  OPT_T_GENER, NULL },
>        /*09-5*/       {"group",       OPT_NORMAL, 0,  OPT_T_GENER, NULL },
128,132c125,129
<       };       lopt[4].data = lopt[5].data = (void *)  &(opt->fork);
<                lopt[6].data = (void *) &(opt->fstderr);
<                lopt[7].data = &(opt->listen_addr);
<                lopt[8].data = &(opt->username);
<                lopt[9].data = &(opt->groupname);
---
>       };       lopt[0].data = lopt[1].data = (void *)  &(opt->fork);
>                lopt[2].data = (void *) &(opt->fstderr);
>                lopt[3].data = &(opt->listen_addr);
>                lopt[4].data = &(opt->username);
>                lopt[5].data = &(opt->groupname);

serg$ diff lib/newopt.c.old lib/newopt.c
463,465c463,465
<               case OPT_T_FUNCT:
<                       (*(callbackT)table->data);
<                       break;
---
> /*            case OPT_T_FUNCT:
>                       (*table->data);
>    

То есть были удалены или закомментированы строки, в которых упоминается OPT_T_FUNC, и соответственно исправлены индексы массива, используемые в дальнейшем. После этой "операции" сборка прошла успешно, а вслед за ней и установка:

root# make install

Запуск pop3filter можно выполнить такой командой:

root# pop3filter --fork 127.0.0.1 110 7110 \
"dspam --user \$pop3_USERNAME --stdout --deliver=innocement,spam "

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

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

Запуск DSPAM в режиме демона

По умолчанию dspam запускается как автономная программа. Однако при интенсивной нагрузке в этом случае тратится много ресурсов на такие операции как установка соединения с СУБД. Более эффективным выглядит запуск в режиме демона, когда серверный процесс dspam находится в памяти, поддерживая несколько постоянных соединений с СУБД. Для обработки же пользовательских соединений dspam запускается как клиент, общающийся с сервером либо по протоколу LMTP, либо через Unix-socket.

Для работы в режиме демона нужно настроить параметры сервера и клиента в конфигурационном файле. Возможны два режима работы - через локальные сокеты Unix либо по протоколу LMTP (используется 24-й TCP-порт). Для первого случая внесите в конфигурацию следующие строки:

ServerDomainSocketPath "/var/run/dspam.sock"
ClientHost      "/var/run/dspam.sock"

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

#ServerPort             24
#ServerPass.Relay1      "secret"
#ServerPass.Relay2      "password"

#ClientHost     127.0.0.1
#ClientPort     24
#ClientIdent    "secret@Relay1"

Строки Server* должны присутствовать в конфигурационном файле сервера, Client* - соответственно клиента. Заметьте, что если хотя бы одна строка ServerPass.RelayX будет раскомментирована, то dspam запустится для работы по 24-му порту, даже если присутствуют строки, задающие Unix-сокеты.

Далее установите в файле /etc/rc.conf переменную dspam_enable в "YES", что обеспечит автоматический запуск демона с помощью сценария /usr/local/etc/rc.d/dspam.sh. Этот скрипт добавляется автоматически при установке из портов, вам останется лишь проконтролировать его наличие и "исполняемость".

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

Если теперь выполнить следующую команду, то можно наблюдать основной процесс dspam и несколько процессов для связи с базой данных (рекомендуется использовать MySQL или PostgreSQL):

root# ps -ax  |grep dspam
 4843  ??  I      0:00,03 postmaster: dspam dspam 127.0.0.1(63076) idle (postgr
 4844  ??  I      0:00,12 postmaster: dspam dspam 127.0.0.1(58646) idle (postgr
 4845  ??  I      0:00,03 postmaster: dspam dspam 127.0.0.1(54366) idle (postgr
 4842  p0  S      0:00,25 /usr/local/bin/dspam -daemon

В результате, благодаря постоянным подключениям к СУБД, нагрузка на систему несколько снижается.

Подключаем CGI-модуль

Этот модуль позволяет пользователям работать со своими настройками, получать статистические данные о работе фильтра, а также просматривать сообщения, помещенные в карантин, и при необходимости инициировать переобучение. В процессе инсталляции необходимые для работы модуля файлы будут помещены в /usr/local/www/vhosts/dspam. Поскольку пользователь, от имени которого будут исполняться данные cgi-скрипты, должен иметь доступ и к иерархии файлов в /var/db/dspam, нужно либо дать соответствующие разрешения на домашний каталог dspam, либо запускать веб-сервер от имени пользователя, имеющего необходимые привилегии.

Наиболее удобным мне показалось запустить для организации веб-интерфейса отдельный виртуальный хост от имени пользователя dspam. Для этого Apache должен быть собран с поддержкой suexec. Проверить выполнение данного требования можно таким образом:

serg$ /usr/local/sbin/httpd -l
.. .. .. .. часть вывода удалена .. .. .. ..
  mod_setenvif.c
  mod_ssl.c
suexec: enabled; valid wrapper /usr/local/sbin/suexec

В дальнейшем, конфигурируем Apache следующим образом (естественно, далеко не единственным):

NameVirtualHost 10.10.10.80
<VirtualHost 10.10.10.80>
    ServerName dspam.test.ru
    DocumentRoot /usr/local/www/vhosts/dspam
    User dspam
    Group dspam
    <Directory "/usr/local/www/vhosts/dspam">
        Options Indexes FollowSymLinks ExecCGI
        AllowOverride All
        Order allow,deny
        Allow from all
        DirectoryIndex index.html
        AddHandler cgi-script .cgi
        <IfModule mod_perl.c>
            PerlSendHeader On
            AddHandler perl-script .cgi
            PerlHandler Apache::Registry
        </IfModule>
    </Directory>
</VirtualHost>

Домашним каталогом виртуального хоста оставляем /usr/local/www/vhosts/dspam, при этом suexec должен быть собран таким образом, чтобы директория dspam находилась внутри директории, определенной как suexec_docroot (задается при компиляции Apache с помощью переменной APACHE_SUEXEC_DOCROOT, либо правкой Makefile).

Далее, для работы suexec требуется, чтобы права на каталог dspam и размещенные в нем скрипты принадлежали пользователю и группе dspam, от имени которого будет работать наш виртуальный хост. Именно несоответствие прав является наиболее частой причиной ошибок при работе с suexec (которые можно будет найти в файле /var/log/httpd-suexec.log, если вы не меняли соответствующий параметр при компиляции).

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

Обратите внимание, что CGI-модуль не может быть использован, если данные пользователей хранятся в их домашних каталогах (был установлен параметр USER_HOMEDIR). Конечно, запустив виртуальный хост с правами суперпользователя, можно разом решить все возможные проблемы доступа, но вряд ли в здравом уме можно пойти на подобный шаг.

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

Для доступа к веб-интерфейсу пользователь должен пройти аутентификацию (используется Basic-аутентификация, по умолчанию проверка выполняется в файле паролей /usr/local/etc/apache/passwd, но вы можете перенастроить это в файле .htaccess). В зависимости от введенного имени (используется переменная $REMOTE_USER) становится доступным интерфейс пользователя или администратора. Роль администратора может выполнять любой аутентифицированный пользователь, имя которого присутствует в файле admins (здесь и далее речь идет о файлах, расположенных в каталоге виртуального хоста, в моем случае это /usr/local/www/vhosts/dspam).

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

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

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

Поскольку по умолчанию доступ возможен ко всем файлам, расположенным в каталоге виртуального хоста (например, можно получить содержимое файла admins), имеет смысл несколько ужесточить требования, внеся дополнительные настройки в .htaccess. Естественно, чтобы они имели силу, конфигурация Apache должна позволять переопределение базовых настроек; также можно указать эти строки непосредственно в httpd.conf, в секции VirtualHost:

root# cat /usr/local/www/vhosts/dspam/.htaccess
AuthName dspam.test.ru 
AuthType Basic
AuthUserFile /usr/local/etc/apache/passwd
<Limit GET POST>
    require valid-user
</Limit>
<FilesMatch "(cgi|css|gif|html)$">
    order deny,allow
    allow from all
</FilesMatch>
order deny,allow
deny from all

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

Обучаем фильтр

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

root# dspam_corpus --addspam sergei /var/db/dspam/data/gorod/gorod.mbox
command: '/usr/local/bin/dspam' --class=spam --source=corpus  --user 'sergei' --mode=teft --feature=chained,noise
/usr/local/bin/dspam_corpus: 3 messages, 00:00:57 elapsed,  0.05 msgs./sec.

В данном примере я обучил фильтр для sergei на основе спама, собранного в карантине пользователя gorod. Обучение "хорошими" сообщениями выполняется аналогично, но без ключа -addspam. Для получения адекватных результатов, при обучении необходимо соблюдать баланс между "хорошими" сообщениями и спамом, в идеале их количество должно быть (примерно) одинаково. Также по умолчанию dspam настраивается на постоянное обучение в процессе работы (режим TEFT). То есть им обрабатываются все входящие сообщения, и значения спамности для каждого встречающегося в них слова пересчитываются в БД. Это увеличивает нагрузку на систему, но позволяет быстро реагировать на изменение характера рассылок.

Если режим TEFT для вас не приемлем из-за слишком высокой нагрузки, можно использовать другие (параметр TrainingMode конфигурационного файла или ключ запуска):

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

В первом случае пользователь имеет возможность в списке своей истории щелчком мыши инициировать переобучение для сообщений, которые, по его мнению, были обработаны ошибочно (используя ссылки "Retrain as Spam" и "Retrain as Innocent" соответственно). Также переобучение происходит, если пользователь возвращает сообщение из карантина.

Для реализации второго механизма обучения в файле /etc/mail/aliases должны быть созданы псевдонимы следующего вида:

# DSPAM aliases
spam-gorod:     "|/usr/local/bin/dspam --user gorod --class=spam --source=error"

Имя псевдонима, в принципе, может быть любым (роль играет значение ключа --user при вызове dspam), но рекомендуется формировать его как spam-<имя_пользователя>. Теперь, если пользователь перенаправит спам, который попал в его ящик, на этот адрес, будет инициировано переобучение.

Нужно сказать, что каждое обработанное письмо помечается сигнатурой вида "!DSPAM:42df44f092281550917839!", которая обычно добавляется в тело сообщения. Когда письмо перенаправляется для исправления ошибки, dspam ищет в нем эту сигнатуру, и "откатывает" те изменения в базе, которые были сделаны во время первоначальной обработки этого сообщения.

Вспомогательная утилита dspam_genaliases автоматически формирует список псевдонимов на основе файла /etc/passwd.

Несколько слов о "вакцинации"

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

inoc-gorod:     "|/usr/local/bin/dspam --user gorod --class=spam --source=inoculation"

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

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

Группы

Чтобы придать работе с пользователями большую гибкость, а также "обобществлять" информацию о спаме, накопленную отдельными пользователями, в системе DSPAM имеется поддержка групп. Так же группы используются и для реализации идеи "вакцинации".

Фильтром поддерживаются следующие типы групп:

Для того чтобы включить пользователя в ту или иную группу, используется файл /var/db/dspam/group:
group1:shared:user1,user2,user3
group2:inoculation:user4,user5,user6

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

Вспомогательные утилиты

В состав пакета DSPAM входит ряд служебных утилит, назначение которых - выполнение ряда сервисных функций:

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

root# dspam_admin
syntax: dspam_admin [function] [arguments] [--profile=PROFILE]
        add preference [user] [attrib] [value]
        change preference [user] [attrib] [value]
        delete preference [user] [attrib] [value]
        list preference [user] [attrib] [value]
        aggregate preference [user]

Например, так можно отключить использование автоматически заполняемого "белого" списка для пользователя gorod:

root# dspam_admin change preference gorod enableWhitelist off
operation successful.

Файл с настройками будет размещаться в директории dspam, в подкаталоге, соответствующем пользователю - /var/db/dspam/data/gorod, в СУБД либо в домашнем каталоге пользователя. Это можно настроить в процессе инсталляции фильтра (см. выше).


dspam_clean: Выполняет очистку базы. В процессе работы база маркеров может достигать значительных размеров. Очистка служит для того, чтобы удалить бесполезные (или малополезные) записи. В частности, могут быть удалены токены, коэффициент спамности которых близок к 0,5, то есть нейтральные слова, а также устаревшие сигнатуры (которые фильтр хранит на случай переобучения). Очистка служит не только для оптимизации размера БД, но и для поддержания ее в актуальном состоянии: удаление устаревших токенов позволяет более точно реагировать на изменение характера рассылки. Например, для удаления сигнатур старше 7 дней для всех пользователей служит команда:

root# dspam_clean -s7

Удаление всех (в том числе и самых последних) нейтральных токенов из пространства пользователя gorod:

root# dspam_clean -p0 gorod

Подробности по использованию утилиты см. на страницах man dspam_cleanup.

Говоря об очистке базы, следует также упомянуть удаление малоэффективных и устаревших данных силами СУБД. Например, для PostgreSQL cоответствующий sql-файл можно найти в /usr/local/share/examples/dspam/pgsql под именем purge.sql.

Для регулярного автоматического запуска процедур очистки можно использовать crontab.


dspam_stats: Выводит статистику работы dspam по всем или указанным пользователям (количество спама, "хороших" писем, ошибок):

root# dspam_stats serg gorod alex
serg              TS:     0 TI:    12 SM:     0 IM:     0 SC:     0 IC:     0
gorod             TS:     1 TI:    44 SM:    11 IM:     0 SC:     0 IC:     0
alex              TS:     0 TI:    20 SM:     0 IM:     0 SC:     0 IC:     0
С ключом -H утилита выдает более "читабельную" информацию:
root# dspam_stats -H gorod
gorod:
                TS Total Spam:                  1
                TI Total Innocent:             44
                SM Spam Misclassified:         11
                IM Innocent Misclassified:      0
                SC Spam Corpusfed:              0
                IC Innocent Corpusfed:          0
                TL Training Left:            2456
                SR Spam Catch Rate:         8.33%
                IR Innocent Catch Rate:   100.00%
                OR Overall Rate/Accuracy:  80.36%


dspam_corpus: Данная утилита позволяет указать фильтру файл в формате mbox, содержимое которого следует "изучить". Будучи выполненной без дополнительных аргументов, команда выведет на экран подсказку по синтаксису. Также имеется man-страница.


dspam_genaliases: С помощью этой команды можно автоматически добавить в файл /etc/mail/aliases нужные псевдонимы, для генерации которых используется список пользователей из файла /etc/passwd.


dspam_logrotate: Лог-файлы имеют привычку разрастаться до немыслимых размеров. С помощью этой утилиты, помещенной в crontab, можно организовать периодическую очистку логов, скажем, таким образом (пример из README):

0 0 * * * dspam_logrotate -a 30 /var/db/dspam/system.log `find /var/db/dspam/data -name "*.log"`
Преимущества этого способа перед другими способами ротации (например, newsyslog) в том, что можно обработать сразу все лог-файлы. В приведенном выше примере с помощью find формируется список всех файлов с расширением log, найденных в каталоге data и его подкаталогах. Ключ -а задает возраст файлов в днях, которые должны быть подвержены очистке.


dspam_merge: Данная команда объединяет метаданные нескольких пользователей, имена которых задаются как аргументы командной строки, и сохраняет их в пространство другого пользователя, заданного ключом -o. Частное применение утилиты - формирование "стартового" наполнения для вновь создаваемого пользователя на основе некоторого существующего, уже прошедшего "цикл обучения". Подробности см. в man dspam_merge.


dspam_dump: Выводит на экран токены и характеризующие их значения для указанного пользователя:

root# dspam_dump gorod
2382717757724374224  S: 00007  I: 00000  P: 0.9998 LH: Wed Jul 27 00:00:00 2005
2180264270330443047  S: 00004  I: 00000  P: 0.4000 LH: Mon Jul 25 00:00:00 2005
4180468462601491382  S: 00004  I: 00000  P: 0.4000 LH: Mon Jul 25 00:00:00 2005
.. .. .. ..

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

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


dspam_2sql: Формирует SQL-команды, которые могут быть использованы для заполнения таблиц данными практически в любой СУБД:

root# dspam_2sql
insert into dspam_token_data (uid, token, spam_hits, innocent_hits, last_hit) values(1002, "16628239873585525635", 0, 3, 1121889600);
insert into dspam_token_data (uid, token, spam_hits, innocent_hits, last_hit) values(1002, "3386138115020307445", 0, 3, 1121889600);
.. .. .. ..

Может использоваться при переносе данных на другую систему управления БД, для резервного копирования (хотя и гораздо менее эффективного, чем силами самой СУБД), и т.д.


dspam_crc: Эта служебная программа рассчитывает цифровой "отпечаток" для того или иного слова (как оно будет храниться в базе):

root# dspam_crc "viagra"
TOKEN: 'viagra' CRC: 6625426497525293056

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

Итоги

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

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

Дополнительная информация:
1.http://dspam.nuclearelephant.com/ - домашняя страница проекта DSPAM.
2.http://www.paulgraham.com/spam.html - "A Plan for Spam" by Paul Graham.
3.http://www.paulgraham.com/better.html - "Better Bayesian Filtering" by Paul Graham.
4.http://radio.weblogs.com/0101454/stories/2002/09/16/spamDetection.html - "Spam Detection" by Gary Robinson.
5.http://linuxjournal.com/article/6467 - "A Statistical Approach to the Spam Problem" by Gary Robinson.

Hosted by uCoz