РНР не ограничивается созданием только HTML вывода. Вы можете создавать файлы изображений с помощью PHP.

Для этого просто необходимо установить GD library и вы можете создавать различные форматы изображения, такие как GIF, PNG, JPEG, WBMP, и XPM.

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

В этом посте вы узнаете , как установить PHP GD модуль на Ubuntu.

Введите следующую команду для установки этого модуля:

1
$sudo apt-getinstall php5-gd

Теперь перезагрузите сервер Apache:

1
# /etc/init.d/apache2 restart

Проверьте, работают ли установлен библиотека php5-GD или нет?

Введите следующую команду:

1
$ php5 -m |grep -i gd

Команда вернется «gd», если Graphics library установлен.

ИЛИ

Вы можете проверить статус установки GD library, запустив ниже показанный PHP код:

1
2
3
<?php
echo phpinfo();
?>

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

В этой статье: а) подводные камни при полностраничном кэшировании; б) кэширование с ротацией; в) создание динамического «окна» в закэшированной странице.

Я буду предполагать, что вы используете связку nginx+fastcgi_php. Если вы применяете nginx+apache+mod_php, просто замените имена директив с fastcgi_cache* на proxy_cache*

Если выбирать, кэшировать ли страницу на стороне PHP или на стороне nginx, я выбираю nginx. Во-первых, это позволяет отдавать 5-10 тыс. запросов в секунду без каких-либо сложностей и без умных разговоров о «высокой нагрузке». Во-вторых, nginx самостоятельно следит за размером кэша и чистит его как при устаревании, так и при вытеснении нечасто используемых данных.

Кэширование всей страницы целиком

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

Например, закэшировать главную страницу можно так:

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;
...
server {
  ...
  location / {
    ...
    fastcgi_pass 127.0.0.1:9000;
    ...
    # Включаем кэширование и тщательно выбираем ключ кэша.
    fastcgi_cache wholepage;
    fastcgi_cache_valid 200 301 302 304 5m;
    fastcgi_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
    # Гарантируем, что разные пользователи не получат одну и ту же сессионную Cookie.
    fastcgi_hide_header "Set-Cookie";
    # Заставляем nginx кэшировать страницу в любом случае, независимо от
    # заголовков кэширования, выставляемых в PHP.
    fastcgi_ignore_headers "Cache-Control" "Expires";
  }
}

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

fastcgi_cache_path: простота отладки тоже важна

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;

В директиве fastcgi_cache_path я выставляю «пустое» значение для levels. Хотя это немного снижает производительность (файлы будут напрямую создаваться в /var/cache/nginx, без разбиения по директориям), но зато на порядок облегчает отладку и диагностику проблем с кэшем. Поверьте, вам еще не раз придется руками залезать в /var/cache/nginx и смотреть, что там хранится.

fastcgi_cache_valid: кэшируем код ответа 304 тоже

fastcgi_cache_valid 200 301 302 304 5m;

В директиве fastcgi_cache_valid мы заставляем кэшировать не только стандартные коды 200 ОК, 301 Moved Permanently и 302 Found, но также и 304 Not Modified. Почему? Давайте вспомним, что означает 304. Он выдается с пустым телом ответа в двух случаях:

  • Если браузер послал заголовок «If-Modified-Since: date», в котором date больше либо равна значению заголовка ответа «Last-Modified: date». Т.е. клиент спрашивает: «Есть ли новая версия с момента date? Если нет, верни мне 304 и сэкономь трафик. Если есть, отдай мне тело страницы».
  • Если браузер послал заголовок «If-None-Match: hash», где hash совапдает со значением заголовка ответа «ETag: hash». Т.е. клиент спрашивает: «Отличается ли текущая версия страницы от той, что я запросил в прошлый раз? Если нет, верни мне 304 и сэкономь трафик. Если да, отдай тело страницы».

В обоих случаях Last-Modified или ETag будут взяты, скорее всего, из кэша nginx, и проверка пройдет очень быстро. Нам незачем «дергать» PHP только для того, чтобы скрипт выдал эти заголовки, особенно в свете того, что клиентам, которым уйдет ответ 200, он будет отдан из кэша.

fastcgi_cache_key: внимательно работаем с зависимостями

fastcgi_cache_key «$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri»;

Особого внимания заслуживает значение в директиве fastcgi_cache_key. Я привел минимальное рабочее значение этой директивы. Шаг вправо, шаг влево, и вы начнете в ряде случаев получать «неправильные» данные из кэша. Итак:

  • Зависимость от $request_method нам нужна, т.к. HEAD-запросы в Интернете довольно часты. Ответ на HEAD-запрос никогда не содержит тела. Если убрать зависимость от $request_method, то может так совпасть, что кто-то до вас запросил главную страницу HEAD-методом, а вам потом по GET отдастся пустой контент.
  • Зависимость от $http_if_modified_since нужна для того, чтобы кэш с ответом 304 Not Modified не был случайно отдан клиенту, делающему обычный GET-запрос. Иначе клиент может получить пустой ответ из кэша.
  • То же самое и с $http_if_none_match. Мы должны быть застрахованы от выдачи пустых страниц клиентам!
  • Наконец, зависимость от $host и $request_uri не требует комментариев.
fastcgi_hide_header: решаем проблемы с безопасностью

fastcgi_hide_header «Set-Cookie»;

Директива fastcgi_hide_header очень важна. Без нее вы серьезно рискуете безопасностью: пользователи могут получить чужие сессии через сессионную Cookie в кэше. (Правда, в последних версиях nginx что-то было сделано в сторону автоматического учета данного фактора.) Понимаете, как это происходит? На сайт зашел Вася Пупкин, ему выдалась сессия и сессионная Cookie. Пусть кэш на тот момент оказался пустым, и в него записалась Васина Cookie. Затем пришел другой пользователь, получил ответ из кэша, а в нем — и Cookie Васи. А значит, и его сессию тоже.

Можно, конечно, сказать: давайте не будем вызывать session_start () на главной странице, тогда и с Cookies проблем не будет. В теории это так, но на практике данный способ очень неустойчив. Сессии часто стартуют «отложено», и достаточно какой-либо части кода «случайно» вызвать функцию, требующую доступа к сессии, как мы получим дыру в безопасности. А безопасность — такая штука, что если в той или иной методике может возникнуть дыра по неосторожности, то эта методика считается «дырявой» по определению. К тому же есть и другие Cookies, кроме сессионной; их тоже не надо записывать в кэш.

fastcgi_ignore_headers: не даем сайту «лечь» от нагрузки при опечатке

fastcgi_ignore_headers «Cache-Control» «Expires»;

Сервер nginx обращает внимание на заголовки Cache-Control, Expires и Pragma, которые выдает PHP. Если в них сказано, что страницу не нужно кэшировать (либо что она уже устарела), то nginx не записывает ее в кэш-файл. Это поведение, хотя и кажется логичным, на практике порождает массу сложностей. Поэтому мы его блокируем: благодаря fastcgi_ignore_headers в кэш-файлы попадет содержимое любой страницы, независимо от ее заголовков.

Что же это за сложности? Они опять связаны с сессиями и функцией session_start (), которая в PHP по умолчанию выставляет заголовки «Cache-Control: no-cache» и «Pragma: no-cache». Здесь существует три решения проблемы:

  • Не пользоваться session_start () на странице, где предполагается кэширование. Один из минусов этого способа мы уже рассмотрели выше: достаточно одного неосторожного движения, и ваш сайт, принимающий тысячи запросов в секунду на закэшированную главную страницу, моментально «ляжет», когда кэш отключится. Второй минус — нам придется управлять логикой кэширования в двух местах: в конфиге nginx и в PHP-коде. Т.е. эта логика окажется «размазанной» по совершенно разным частям системы.
  • Выставить ini_set ('session.cache_limiter', ''). Это заставит PHP запретить вывод каких-либо заголовков, ограничивающих кэширование при работе с сессиями. Проблема здесь та же: «размазанность» логики кэширования, ведь в идеале мы бы хотели, чтобы все кэширование управлялось из единого места.
  • Игнорировать заголовки запрета кэширования при записи в кэш-файлы при помощи fastcgi_ignore_headers. Кажется, это беспроигрышное решение, поэтому я его и советую.

 

Кэширование с ротацией

Статическая главная страница — это не так уж и интересно. Что делать, если на сайте много материалов, а Главная выступает в роли своеобразной «витрины» для них? На такой «витрине» удобно отображать «случайные» материалы, чтобы разные пользователи видели разное (и даже один пользователь получал новый контент, перезагрузив страницу в браузере).

Решение задачи — кэширование с ротацией:

  1. Мы заставляем скрипт честно выдавать элементы главной странице в случайном порядке, выполняя необходимые запросы в базу данных (пусть это и медленно).
  2. Затем мы сохраняем в кэше не одну, а, скажем, 10 вариантов страницы.
  3. Когда пользователь заходит на сайт, мы показываем ему один из этих вариантов. При этом, если кэш пуст, то запускается скрипт, а если нет, то результат возвращается из кэша.
  4. Устанавливаем время устаревания кэша малым (например, 1 минута), чтобы за день разные пользователи «отсмотрели» все материалы сайта.

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

Вот кусочек конфига nginx, реализующий кэширование с ротацией:

fastcgi_cache_path /var/cache/nginx levels= keys_zone=wholepage:50m;
perl_set $rand 'sub { return int rand 10 }';
...
server {
  ...
  location / {
    ...
    fastcgi_pass 127.0.0.1:9000;
    ...
    # Включаем кэширование и тщательно выбираем ключ кэша.
    fastcgi_cache wholepage;
    fastcgi_cache_valid 200 301 302 304 1m;
    fastcgi_cache_key "$rand|$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri";
    # Гарантируем, что разные пользователи не получат одну и ту же сессионную Cookie.
    fastcgi_hide_header "Set-Cookie";
    # Заставляем nginx кэшировать страницу в любом случае, независимо от
    # заголовков кэширования, выставляемых в PHP.
    fastcgi_ignore_headers "Cache-Control" "Expires";

    # Заставляем браузер каждый раз перезагружать страницу (для ротации).
    fastcgi_hide_header "Cache-Control";
    add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
    fastcgi_hide_header "Pragma";
    add_header Pragma "no-cache";
    # Выдаем всегда свежий Last-Modified.
    expires -1; # Внимание!!! Эта строка expires необходима!
    add_header Last-Modified $sent_http_Expires;
  }
}

Вы можете заметить, что по сравнению с предыдущим примером мне пришлось добавить еще 6 директив в location. Они все очень важные! Но не будем забегать вперед, рассмотрим все по порядку.

perl_set: зависимость-рандомизатор

perl_set $rand 'sub { return int rand 10 }';

С директивой perl_set все просто. Мы создаем переменную, при использовании которой nginx будет вызывать функцию встроенного в него Perl-интерпретатора. По словам автора nginx, это достаточно быстрая операция, так что мы не будем «экономить на спичках». Переменная принимает случайное значение от 0 до 9 в каждом из HTTP-запросов.

fastcgi_cache_key: зависимость от рандомизатора

fastcgi_cache_key «$rand|$request_method|...»;

Теперь мы замешиваем переменную-рандомизатор в ключ кэша. В итоге получается 10 разных кэшей на один и тот же URL, что нам и требовалось. Благодаря тому, что скрипт, вызываемый при кэш-промахе, выдает элементы главной страницы в случайном порядке, мы получаем 10 разновидностей главной страницы, каждая из которой «живет» 1 минуту (см. fastcgi_cache_valid).

add_header: принудительно выключаем браузерный кэш

 

fastcgi_hide_header "Cache-Control";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
fastcgi_hide_header "Pragma";
add_header Pragma "no-cache";

Выше мы говорили, что nginx чувствителен к кэш-заголовкам, выдаваемым PHP-скриптом. Если PHP-скрипт возвращает заголовки «Pragma: no-cache» или «Cache-Control: no-store» (а также еще некоторые, например, «Cache-Control: не-сохранять, не-выдавать, меня-тут-не-было, я-этого-не-говорил, чья-это-шляпа»), то nginx не будет сохранять результат в кэш-файлах. Специально чтобы подавить такое его поведение, мы используем fastcgi_ignore_headers (см. выше).

Чем отличается «Pragma: no-cache» от «Cache-Control: no-cache»? Только тем, что Pragma — наследие HTTP/1.0 и сейчас поддерживается для совместимости со старыми браузерами. В HTTP/1.1 используется Cache-Control.

Однако есть еще кэш в браузере. И в некоторых случаях браузер может даже не пытаться делать запрос на сервер, чтобы отобразить страницу; вместо этого он достанет ее из собственного кэша. Т.к. у нас ротация, нам такое поведение неудобно: ведь каждый раз, заходя на страницу, пользователь должен видеть новые данные. (На самом деле, если вы все же хотите закэшировать какой-нибудь один вариант, то можно поэкспериментировать с заголовком Cache-Control.)

Директива add_header как раз и передает в браузер заголовок запрета кэширования. Ну а чтобы этот заголовок случайно не размножился, мы вначале убираем из HTTP-ответа то, что записал туда PHP-скрипт (и то, что записалось в nginx-кэш): директива fastcgi_hide_header. Ведь вы, когда пишете конфиг nginx-а, не знаете, что там надумает выводить PHP (а если используется session_start (), то он точно надумает). Вдруг он выставит свой собственный заголовок Cache-Control? Тогда их будет два: PHP-шный и добавленный нами через add_header.

expires и Last-Modified: гарантируем перезагрузку страницы

 

expires -1; # Внимание!!! Эта строка expires необходима!
add_header Last-Modified $sent_http_Expires;

Еще один трюк: мы должны выставить Last-Modified равным текущему времени. К сожалению, в nginx нет переменной, хранящей текущее время, однако она магическим образом появляется, если указать директиву expires -1.

Хотя это сейчас (октябрь 2009 г.) не задокументировано, nginx создает переменные вида $sent_http_XXX для каждого заголовка ответа XXX, отданного клиенту. Одной из них мы и пользуемся.

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

  1. Давайте представим, что PHP выдал заголовок «Last-Modified: некоторая_дата».
  2. Данный заголовок будет записан в кэш-файл nginx (можете проверить: в нашем примере файлы хранятся в /var/cache/nginx), а потом отдан в браузер клиенту.
  3. Браузер запомнит страницу и дату ее модификации...
  4. … поэтому при следующем заходе пользователя на сайт в HTTP-запросе будет заголовок-вопрос «If-Modified-Since: некоторая_дата».
  5. Что же сделает nginx? Он достанет страницу из своего кэша, разберет ее заголовки и сравнит Last-Modified с If-Modified-Since. Если значения совпадут (или первое окажется меньше второго), то nginx вернет ответ «304 Not Modified» с пустым телом. И пользователь не увидит никакой ротации: он получит то, что уже видел раньше.

На самом деле, большой вопрос, как поведет себя браузер при наличии одновременно Last-Modified и Cache-Control no-cache. Будет ли он делать запрос If-Modified-Since? Кажется, что разные браузеры ведут тут себя по-разному. Экспериментируйте.

Есть и еще один повод выставлять Last-Modified вручную. Дело в том, что PHP-функция session_start () принудительно выдает заголовок Last-Modified, но указывает в нем… время изменения PHP-файла, который первый получил управление. Следовательно, если у вас на сайте все запросы идут на один и тот же скрипт (Front Controller), то ваша Last-Modified будет почти всегда равна времени изменения этого единственного скрипта, что совершенно не верно.

Динамическое «окно» в закэшированной странице

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

В ту часть страницы, которая должна быть динамической, вставьте вот такой «HTML-комментарий»:

<!--# include virtual="/get_user_info/" -->

С точки зрения кэша nginx данный комментарий — обычный текст. Он будет сохранен в кэш-файле именно в виде комментария. Однако позже, при прочтения кэша, сработает модуль SSI nginx, который обратится к динамическому URL. Конечно, по адресу /get_user_info/ должен быть PHP-обработчик, который выдает содержимое данного блока. Более подробно данный способ описан в этой статье с Хабра.

Ну и, естественно, не забудьте включить SSI для этой страницы или даже для всего сервера:

ssi on;

Директива SSI include имеет еще одно, крайне важное свойство. Когда на странице встречаются несколько таких директив, то все они начинают обрабатываться одновременно, в параллельном режиме. Так что, если у вас на странице 4 блока, каждый из которых загружается 200мс, в сумме страница будет получена пользователем через 200мс, а не через 800.

Исходный текст данной статьи можно прочитать тут: http://dklab.ru/chicken/nablas/56.html

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

В секции «http» объявляем кеш-зону fastcgi_cache, с хранением кеша в папке /tmp/nginx с 2 уровнями вложенности, с максимальным размером 256Мб и кешем ключей 16Мб (неиспользуемые более 1 дня объекты будут автоматически удаляться):

fastcgi_cache_path /tmp/nginx/ levels=1:2 keys_zone=fastcgi_cache:16m max_size=256m inactive=1d;

Далее, в секции «server» правим соответствующий location:

location ~ .php$ {
            # Стандартная конфигурация для php
            fastcgi_pass   unix:/tmp/php-fcgi.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/local/www/somedir/$fastcgi_script_name;
            include        fastcgi_params;
            fastcgi_param  DOCUMENT_ROOT /usr/local/www/somedir/;

            fastcgi_pass_header Cookie; # Необходимо для передачи cookie в соответствующие переменные, например cookie с именем phpsessid будет находится в переменной $cookie_phpsessid

            fastcgi_ignore_headers Cache-Control Expires Set-Cookie; # Игнорируем заголовки, относящиеся к кешированию, полученные от FastCGI-сервера

            fastcgi_cache_key "$server_addr:$server_port$request_uri|$cookie_phpsessid"; # Формируем уникальный ключ; в данном случае различаем пользователей с помощью $cookie_phpsessid

            fastcgi_cache fastcgi_cache; # Говорим о том, что использовать надо вышеобъявленную кеш-зону fastcgi_cache

            fastcgi_temp_path  /tmp/nginx/temp 1 2; # Указываем папку для хранения временных файлов

            fastcgi_cache_use_stale updating error timeout invalid_header http_500; # Используем вариант из кеша (даже если он устарел) в случае ошибки

            fastcgi_cache_valid 10s; # Время жизни кеша для ответов 200, 301 & 302
            #fastcgi_cache_valid any 10s; # Таким образом можно закешировать любые ответы
            }

Конфиг опробован на nginx версии >= 0.7.60 (на => 0.8.1 должен работать, но не тестировался).

Документация: Директивы модуля ngx_http_fastcgi_module, Changelog.

upd: Если не игнорировать заголовки Cache-Control и Expires, nginx ведёт себя соответственно их содержанию (что, в принципе, логично).

upd/28.01.2011: добавлен параметр Set-Cookie к fastcgi_ignore_headers (начиная с nginx/0.8.44)

upd/07.02.2011: необходимо реализовать отделение поисковых краулеров, т.к. при игнорировании cookies могут выкинуть из выдачи

Установка VirtIO в FreeBSD.

Про паравиртуальные драйвера VirtIO я уже писал, поэтому повторно расписывать что это, не имеет смысла. Привожу пример установки virtio-драйверов в гостевую систему FreeBSD.
Обновляем систему
# freebsd-update fetch
# freebsd-update install

Устанавливаем пакет virtio-kmod. В диалогах везде принимаем настройки по умолчанию.
# cd /usr/ports/emulators/virtio-kmod
# make clean install

После установки копируем модули в каталог ядра
# cp -Rp /usr/local/modules/* /boot/kernel/
# kldxref /boot/kernel

Правим конфигурацию загрузчика
# vi /boot/loader.conf
virtio_load="YES"
virtio_pci_load="YES"
virtio_blk_load="YES"
if_vtnet_load="YES"
virtio_balloon_load="YES"

Правим /etc/fstab, использование virtio определяет другое именование блочных устройств
# vi /etc/fstab
# Device        Mountpoint      FStype  Options Dump    Pass#
/dev/vtbd0p2    /               ufs     rw      1       1
/dev/vtbd0p3    none            swap    sw      0       0

Имена сетевых карт также изменятся, поэтому следует отредактировать имена в rc.conf
# vi /etc/rc.conf
ifconfig_vtnet0="DHCP"

Выключаем гостя.
# shutdown -p now

Перед запуском меняем настрйоки виртуальной машины, менятем тип блочного устройства на virtio. После чего запускаем машину и проверяем что VirtIO включено и используется.
# kvm ... -drive file=/dev/vg00/k101-fbsd-root,if=none,index=0,id=disk101 -device virtio-blk-pci,drive=disk101
— netdev tap,ifname=itap101,id=itap101,script=no,downscript=no -device virtio-net-pci,netdev=itap101,mac=00:fc:44:d5:01:01
# kldstat
Id Refs Address            Size     Name
1   12 0xffffffff80200000 11cdab0  kernel
2    5 0xffffffff813ce000 4ca0     virtio.ko
3    1 0xffffffff813d3000 5880     virtio_pci.ko
4    1 0xffffffff813d9000 5010     virtio_blk.ko
5    1 0xffffffff813df000 aeb0     if_vtnet.ko
6    1 0xffffffff813ea000 3210     virtio_balloon.ko

Как сжать виртуальный жесткий диск qcow2

Имейте в виду! Не забывайте остановить виртуальную машину! Запуск этого команды при запущенной виртуальной машине категорически запрещено!

qemu-img convert  source_not_compressed_qcow2.img -O qcow2 -c  target_compressed_qcow2.img

Все, что вы хотели узнать о тонкостях настройки Spamassassin

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

Пакет Spamassassin – один из самых популярных инструментов для борьбы со спамом, свободно распространяемый под лицензией Apache. Будучи написанным на языке Perl, он имеет высокий уровень переносимости и наверняка будет работать на любой UNIX-подобной операционной системе. Этим же обусловлена и относительная медлительность этого фильтра. В данной статье будет рассмотрено использование Spamassassin на FreeBSD, однако основные принципы работы сохранятся неизменными и на других платформах.

Тактика и используемые системы вооружения

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

Таблица 1. Примеры характерных признаков спама

Правило Описание Балл
HEAD_LONG Заголовок сообщения слишком длинный 2,5
REPLY_TO_EMPTY Поле заголовка «Replay-To» пустое 1,274
SUBJ_YOUR_FAMILY Тема сообщения содержит фразу «Your Family» 1,648
ALL_TRUSTED Сообщение передавалось только через доверенные узлы -2,4

Spamassassin также может проверять принадлежность адреса отправителя одному или нескольким блок-листам реального времени (RBL). Опять-таки результат такой проверки лишь добавит баллы в общую копилку.

Рассматриваемый фильтр умеет взаимодействовать и с системами, основанными на сигнатурном анализе (Razor, Pyzor, DCC). По умолчанию включен только Pyzor, поскольку DCC не является открытой системой, а сервис Razor полностью бесплатен только в случае персонального использования.

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

Развертывание комплекса на местности

Установка выполняется традиционно: на FreeBSD лучше всего воспользоваться коллекцией портов; пользователи Linux могут установить Spamassassin из исходных кодов либо поискать в сети готовый прекомпилированный пакет для своего дистрибутива. Более того, поскольку Spamassassin разработан на Perl, его можно установить непосредственно из коллекции CPAN, как и любой другой Perl-модуль:

root# perl -MCPAN -e shell

cpan> o conf prerequisites_policy ask

cpan> install Mail::SpamAssassin

cpan> quit

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

# cd /usr/ports/mail/p5-Mail-SpamAssassin

# make

# make install

Вместе с командами make и make install вы можете указать ряд дополнительных параметров (см. таблицу 2).

Таблица 2. Некоторые опции, полезные при инсталляции

Назначение параметра Ключ для make
Отключить поддержку SSL -DWITHOUT_SSL
Включить поддержку MySQL -DWITH_MYSQL
Включить поддержку PostgreSQL -DWITH_PGSQL
Включить поддержку сигнатурного анализатора Vipul’s Razor -DWITH_RAZOR
Включить поддержку запросов SPF -DWITH_SPF_QUERY
Использовать Yahoo DomainKeys -DWITH_DOMAINKEYS
Использовать базу IP-адресов с географической привязкой -DWITH_RELAY_COUNTRY
Устанавливать вспомогательные инструменты -DWITH_TOOLS

Замечание: при первой установке из коллекции портов вы получите представленное на рис. 1 диалоговое окно, где сможете отметить нужные параметры визуально, без ввода дополнительных параметров в командной строке. Ваш выбор будет сохранен в /var/db/ports/p5-Mail-SpamAssassin/options, и при последующих установках (например, при обновлении версии пакета) вы уже не будете получать этот диалог.

Рисунок 1. Конфигурационный диалог

Поясню смысл приведенных выше опций.

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

Если вы планируете использовать байесовый анализатор, то поддержка MySQL или PostgreSQL позволит вам хранить статистические данные, накапливаемые анализатором, в базе данных. Кроме того, в БД могут храниться настройки пользователей и автоматически формируемый «белый» список. Если ни одна из СУБД не поддерживается, будут использоваться «плоские» файлы.

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

Запросы SPF (Sender Policy Framework, см. http://spf.pobox.com) позволяют использовать систему DNS для проверки того, является ли IP-адрес источника сообщения легитимным SMTP-сервером. Для SMTP-серверов администратор размещает в соответствующей зоне DNS запись типа TXT, информирующую о том, что с данного IP-адреса предусмотрена отправка сообщений электронной почты. Если для адреса источника такая TXT-запись отсутствует, то получатель вправе отклонить запрос на соединение.

Yahoo DomainKeys (см. http://antispam.yahoo.com/domainkeys) действует аналогично SPF, но вместо простой пометки хранит в соответствующей зоне публичный ключ SMTP-сервера, позволяющий верифицировать цифровые подписи получаемых электронных сообщений (которые подписываются автоматически при отправке).

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

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

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

Также не забудьте добавить следующую строчку в /etc/rc.conf:

spamd_enable="YES"

Это необходимо для того, чтобы демон Spamassassin мог запускаться из стартового сценария /usr/local/etc/rc.d/sa-spamd.sh.

Дислокация и приведение в полную боевую готовность

По умолчанию (установка из портов, prefix не используется) исполнимые файлы пакета размещаются в /usr/local/bin. Размещение и назначение основных конфигурационных файлов разъясняется в таблице 3.

Таблица 3. Размещение конфигурационных файлов

Файл Назначение
/usr/local/etc/mail/spamassassin/local.cf Основной файл конфигурации (общесистемный)
/usr/local/etc/mail/spamassassin/*.cf Прочие рабочие файлы конфигурации
/usr/local/etc/mail/spamassassin/init.pre Загружаемые модули (plugins),  совместимые с версией 3.0
/usr/local/etc/mail/spamassassin/v310.pre Загружаемые модули (plugins), совместимые с новой версией 3.1
/usr/local/share/spamassassin/*.cf Конфигурация по умолчанию
/.spamassassin/* Пользовательские настройки и файлы данных

Обратите внимание, что настоятельно не рекомендуется вносить изменения в файлы, размещаемые в каталоге /usr/local/share/spamassassin, поскольку они будут перезаписаны при обновлении версии пакета, и вы потеряете все свои настройки. Если вам нужно что-то изменить, просто укажите строку с нужными параметрами в рабочем конфигурационном файле в каталоге /usr/local/etc/mail/spamassassin.

Следующие подразделы описывают некоторые наиболее полезные параметры конфигурации.

Настройка набора тестов

  • required_score N – «Порог срабатывания» фильтра, то есть количество баллов, при достижении которого сообщение признается спамом. N – число с плавающей запятой. Значение по умолчанию – 5.0.
  • score <имя_теста> nL [nN nB nBN] – баллы, назначаемые тесту <имя_теста>. Может быть указано одно значение (общее) или четыре: nL – локальный балл, nN – при работающих сетевых тестах, nB – при включенном байесовом анализаторе, nBN – при работающих сетевых тестах и статистическом анализаторе.

Имена тестов и значения по умолчанию можно узнать в файле /usr/local/share/spamassassin/50_scores.cf. Чтобы полностью отключить какой-либо тест, присвойте ему значение 0.0.

Сами тесты (как правило – регулярные выражения) находятся в этом же каталоге в других cf-файлах. При желании вы можете создавать и свои проверки по аналогии с имеющимися. Как вы можете увидеть, для этого существует несколько групп правил (header, body, rawbody, meta, uri и др.).

Подробно синтаксис правил описывается на странице справки perldoc Mail::SpamAssassin::Conf.

Белые и черные списки

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

Для этого существует группа параметров, определяющих «белые» и «черные» списки:

  • whitelist_from <адрес_или_шаблон> – отправители, почтовый адрес которых соответствует шаблону, рассматриваются как доверенные, и почта от них не подвергается проверке на спам. Под шаблоном в данном случае понимается запись в стиле командной строки, где символ «*» обозначает любое количество символов, «?» – любой один символ. Например, «*@contora.ru» занесет в «белый» список всех пользователей домена contora.ru.
  • blacklist_from <адрес_или_шаблон> – аналогично «белому» списку, но теперь отправитель априори рассматривается как спамер, и все письма от него помечаются как спам без дальнейшего анализа.
  • whitelist_to <адрес_или_шаблон> – все сообщения на указанный адрес будут передаваться без фильтрации. Можно использовать, если владелец адреса желает получать всю почту, адресованную ему. Также рекомендуется устанавливать этот параметр для адреса abuse, чтобы даже в случае неправильной настройки фильтра с вами можно было связаться.
  • blacklist_to <адрес_или_шаблон> – все сообщения на указанный адрес будут рассматриваться как спам. Например, таким образом можно организовать «прививки» для статистического анализатора, создав специальный адрес для спама и максимально «засветив» его на просторах Интернета (при этом должно быть включено автообучение, см. ниже).

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

Опции сетевых проверок

Фильтр Spamassassin умеет проводить ряд сетевых тестов, таких как проверка на принадлежность адреса отправителя доверенной сети, поиск IP-адреса в списках RBL, и т. п.

Некоторые параметры, которые вы можете использовать в своем конфигурационном файле, приведены ниже:

  • trusted_networks <список_сетей> – перечисленные здесь сети (в формате CIDR, например: 12.34.56.78/24) будут рассматриваться как доверенные.
  • skip_rbl_checks 1 | 0 – этим правилом вы можете отключить (значение 1) проверку на принадлежность адреса отправителя спискам RBL. Это может быть полезно, если такие проверки вы предпочитаете выполнять другими средствами (например, с помощью spamd или непосредственно правилами MTA), а также если риск потери легальных сообщений для вас неприемлемо высок.

Параметры обучения статистического анализа

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

Некоторые параметры:

  • use_bayes 1 | 0 – включает использование статистического анализатора.
  • bayes_auto_learn 1 | 0 – разрешает автообучение фильтра, в ходе которого письма, признанные спамом либо набравшие минимальный балл, автоматически обрабатываются для обучения анализатора как спам (spam) или не спам (ham) соответственно.
  • bayes-ignore-header <тэг_заголовка> – не анализировать письма, содержащие указанный тэг в заголовке. Может оказаться полезным для отмены повторного анализа уже обработанных (например, вышестоящим провайдером) сообщений.
  • bayes_ignore_from <адрес> – не подвергать анализу письма от указанного адресата.
  • bayes_ignore_to <адрес> – не анализировать сообщения, предназначенные указанному пользователю.

Прочие параметры

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

ok_locales ru en

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

Параметр report_safe указывает на то, что следует делать с оригинальным сообщением, если оно будет признано спамом: либо оставить как есть (значение 0), либо приложить к отчету как вложение (значение 1), либо добавить к отчету как текст (значение 2).

Настройки администратора

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

  • bayes_path <путь_к_базе> – указывает путь к каталогу, в котором будут храниться данные, накапливаемые статистическим анализатором.
  • bayes_file_mode <права_доступа> – задаются права доступа для вновь создаваемых файлов данных анализатора.
  • bayes_sql_* – группа правил для настройки доступа к внешней БД в случае, если она используется для хранения данных анализатора. Подробнее взаимодействие с СУБД будет рассмотрено в одном из следующих разделов.
  • loadplugin <имя_модуля> [<путь_к_модулю>] – так можно подключить дополнительный модуль.

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

Если вы устанавливали вспомогательные инструменты, то найти их можно будет в каталоге /usr/local/share/spamassassin/tools. Все они снабжены подробными комментариями или POD-документацией в самом тексте сценария. Здесь я приведу лишь краткое описание некоторых скриптов:

  • sa-stats.pl – формирует статистику работы фильтра на основе почтового лог-файла (по умолчанию /var/log/maillog). Пример вывода сценария:

# ./sa-stats.pl -s 20051013

Report Title     : SpamAssassin — Spam StatisticsReport Date      : 2005-10-13

Period Beginning : четверг, 13 октября 2005 г. 00:00:00

Period Ending    : пятница, 14 октября 2005 г. 00:00:00

Reporting Period : 24.00 hrs

--------------------------------------------------

Note: «ham» = «nonspam»

Total spam detected    :      737 (  54.51%)

Total ham accepted     :      615 (  45.49%)

                        -------------------

Total emails processed :     1352 (   56/hr)

Average spam threshold :       12.00

Average spam score     :       17.85

Average ham score      :        4.66

Spam kbytes processed  :     5255   (  219 kb/hr)

Ham kbytes processed   :    10632   (  443 kb/hr)

Total kbytes processed :    15887   (  662 kb/hr)

Spam analysis time     :     2057 s (   86 s/hr)

Ham analysis time      :     1434 s (   60 s/hr)

Total analysis time    :     3491 s (  145 s/hr)

Statistics by Hour

----------------------------------------------------

Hour                          Spam               Ham

-------------    -----------------    --------------

2005-10-13 00            12 ( 27%)         32 ( 72%)

2005-10-13 01           102 ( 75%)         33 ( 24%)

... ... ... ...

2005-10-13 23             0 (  0%)          0 (  0%)

Done. Report generated in 25 sec by sa-stats.pl, version 6256.

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

  • check_whitelist – проверяет или очищает автоматически сформированный «белый» список, позволяя удалить из него редко используемые адреса.

# ./check_whitelist

-1.4        (-4.3/3)  --  user@myserver.ru|ip=none11.1        (22.2/2)  --  rrryyy@mail.ru|ip=8x.2yy

 0.0         (0.0/2)  --  security-advisories@freebsd.org|ip=216.136

-2.3    (-394.9/171)  --  mailer-daemon@myserver.ru|ip=none

... ... ... ...

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

  • convert_awl_dbm_to_sql – преобразует базу «белого» списка в SQL-команды для заливки данных во внешнюю БД.

Подразделение AWL

AWL (Auto White List) – система, используемая в Spamassassin по умолчанию, начиная с версии 3.0. Принцип работы AWL заключается в следующем: для всех отправителей ведется база данных, в которой сохраняется число обработанных сообщений и набранный в сумме балл. При получении письма с адреса, фигурирующего в базе AWL, рассчитывается его «чистый» балл (без учета AWL), а окончательный балл проставляется как производное значение от рассчитанного «чистого» и взятого из базы исторического значения.

Например, если ранее с адреса rrryyy@mail.ru было получено два сообщения, набравших в сумме 22.2 балла (см. листинг в предыдущем разделе, поясняющий работу утилиты check_whitelist), и приходит третье письмо с «чистым» баллом 1.8, то итоговый балл будет равняться:

St = (Th / Ch — Sc) * f + Sc = (22.2 / 2 — 1.8) * 1 + 1.8 = 11.1

где:

  • St – итоговый балл;
  • Th – суммарный «исторический» балл;
  • Ch – количество «исторических» писем;
  • Sc – «чистый» балл текущего письма (без учета AWL);
  • – весовой коэффициент системы AWL.

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

Отключить использование AWL можно, указав в конфигурационном файле следующую строку:

use_auto_whitelist 0

Кроме того, вы можете подстраивать работу системы, указывая весовой коэффициент для расчета итогового балла, отличный от 1:

auto_whitelist_factor 0.5

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

Взаимодействие с MTA

SpamAssassin может быть подключен практически ко всем популярным почтовым серверам: Sendmail, Postfix, Qmail, Exim, Courier-MTA, Communigate Pro и некоторым другим. Подробные инструкции можно получить на странице http://wiki.apache.org/spamassassin/IntegratedInMta.

Для работы с Sendmail Spamassassin обычно подключается через milter. В сети можно найти несколько «мильтеров» для работы со Spamassassin.

Мы будем использовать имеющийся в коллекции портов spamass-milter:

# cd /usr/ports/mail/spamass-milter-0.3.0

# make install

После установки нужно будет добавить в /etc/rc.conf строку для автоматического запуска spamass-milter при загрузке системы:

spamass_milter_enable="YES"

Наконец, добавляем поддержку этой программы в конфигурационный mc-файл Sendmail (обычно соответствует доменному имени сервера, например /etc/mail/myserver.ru.mc):

MAIL_FILTER (`spamassassin’, `S=local:/var/run/spamass-milter.sock, F=, T=C:15m;S:4m;R:4m;E:10m’) dnl

define (`confINPUT_MAIL_FILTERS’, `spamassassin’) dnl

Если вы используете и другие фильтры (например, clmilter из пакета ClamAV), то перечислите их в одной строке «confINPUT_MAIL_FILTERS», поскольку такая запись должна быть только одна.

Как вариант, вместо строк MAIL_FILTER можно использовать INPUT_MAIL_FILTER. В этом случае второе определение не потребуется.

Теперь осталось пересобрать cf-файл, запустить Spamassassin и spamass-milter и перезагрузить Sendmail:

# cd /etc/mail

# make

# make install

# /usr/local/etc/rc.d/sa-spamd.sh start

# /usr/local/etc/rc.d/spamass-milter.sh start

# make restart

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

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

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

# Отправляем все сообщения (до 256000 байт) на обработку

:0fw: spamassassin.lock

* < 256000

| spamassassin

# Все сообщения с X-Spam-Status = Yes помещаем в карантин

:0:

* ^X-Spam-Status: Yes

carantine

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

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

Дальнейшая участь спама

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

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

На странице http://wiki.apache.org/spamassassin/SpamQuarantine предлагается два других решения: использование веб-интерфейса Maia Mailguard и программы SpamAssassin Quarantine (SAQ). Чтобы не перегружать статью, оставлю их вам для самостоятельного изучения (возможно, об особенностях этих программ мы поговорим в другой раз).

На своем сервере я ограничился только пометкой спама, предоставив пользователям возможность самостоятельно решать, что делать с ним дальше.

Проверка боеготовности и обучение личного состава

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

X-Spam-Status: No, score=-0.7 required=12.0 tests=ALL_TRUSTED,AWL,    MAILTO_TO_SPAM_ADDR,NO_REAL_NAME autolearn=ham version=3.1.0

X-Spam-Checker-Version: SpamAssassin 3.1.0 (2005-09-13) on myserver.ru

Из этого заголовка видно следующее: сообщение было обработано фильтром Spamassassin, запущенным на вашем сервере (тэг X-Spam-Checker-Version). Письмо не было признано спамом (No), набрало -0.7 балла при необходимых 12.0, положительный результат был дан перечисленными после tests тестами. Автоматическое обучение статистического фильтра было выполнено для этого письма в режиме ham (не спам).

Таким образом, можно считать, что фильтр работает.

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

Рисунок 2. Так для пользователя выглядит спам

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

После того как будет накоплена достаточная база, в заголовках обработанных писем будет появляться и информация о выполнении тестов BAYES_xx:

X-Spam-Status: Yes, score=14.9 required=12.0 tests=BAYES_99,EXTRA_MPART_TYPE,    FORGED_OUTLOOK_TAGS,FORGED_RCVD_HELO,HTML_IMAGE_ONLY_16,HTML_MESSAGE,

    RCVD_IN_NJABL_DUL,RCVD_IN_SORBS_DUL,RCVD_NUMERIC_HELO,

    SUBJECT_ENCODED_TWICE autolearn=no version=3.1.0

X-Spam-Level: **************

X-Spam-Checker-Version: SpamAssassin 3.1.0 (2005-09-13) on myserver.ru

Как видите, для этого сообщения байесовый тест дал результат от 99 до 100% вероятности того, что письмо – спам. Совместно с другими тестами письмо набрало 14.9 баллов, что позволило отнести его к спаму, несмотря на достаточно высокий порог срабатывания.

Основываясь на личном опыте использования фильтра, могу сказать, что сразу после установки (поскольку дело было на работающем сервере, то необходимый порог срабатывания был на период тестирования установлен на достаточно высоком уровне – 12 баллов) Spamassassin стал отмечать примерно половину приходящего спама. Специального обучения статистического анализатора я не проводил, целиком полагаясь на самообучение. Спустя сутки фильтр накопил достаточную базу и стал учитывать результаты байесовой классификации. При этом точность срабатывания возросла примерно до 91%. Ложных срабатываний пока не наблюдалось.

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

# sa-learn --spam ~serg/sa/spams

Learned tokens from 20 message (s) (20 message (s) examined)

# sa-learn --ham ~serg/sa/hams

Learned tokens from 5 message (s) (5 message (s) examined)

Последним параметром указывается либо файл (в формате mailbox), либо каталог, содержащий примеры писем (например, в формате msg). Нужно заметить, что обучение может выполняться довольно долго (у меня обработка 25 сообщений заняла почти минуту).

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

После обучения вы можете просмотреть дамп базы:

# sa-learn –dump

0.000   0          3          0  non-token data: bayes db version0.000   0       2792          0  non-token data: nspam

0.000   0        623          0  non-token data: nham

0.000   0     131028          0  non-token data: ntokens

0.000   0 1010692073          0  non-token data: oldest atime

0.000   0 1129590682          0  non-token data: newest atime

0.000   0 1129530349          0  non-token data: last journal sync atime

0.000   0          0          0  non-token data: last expiry atime

0.000   0          0          0  non-token data: last expire atime delta

0.000   0          0          0  non-token data: last expire reduction count

0.049   0          1 1129026204  91a35b559c

0.958   1          0 1129026743  92485c309a

0.049   0          1 1129028552  f92317eba2

... ... ... ... ...

К процессу обучения можно приобщить и пользователей. Создайте специальные почтовые ящики для спама и не спама (например, sa-spam@myserver.ru и sa-ham@myserver.ru) и проинструктируйте своих пользователей на первый из них пересылать пропущенный спам (так называемый false negative), на второй – хорошие сообщения, ошибочно признанные спамом (false positive).

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

Второй путь – настроить procmail на обработку таких писем, что называется, на лету (пример взят со страницы http://wiki.apache.org/spamassassin/ProcmailToForwardMail):

:0

* ^To:.*spam@example.com

   {

   * < 256000

   :0c: spamassassin.spamlock

   | sa-learn --spam

   :0: spamassassin.filelock

   spam

   }

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

Подробнее о режимах обучения смотрите страницу справочного руководства man sa-learn и соответствующие Wiki-страницы.

Усиление за счет внешней СУБД

По умолчанию Spamassassin хранит данные (автоматически формируемый «белый» список, историю статистического анализатора) в отдельных файлах в формате DBM. Для повышения производительности можно перенести их во внешнюю базу данных. Spamassassin умеет работать с MySQL и PostgreSQL (поддержка СУБД должна быть включена на этапе установки пакета). Рассмотрим настройку для работы с базой PostgreSQL.

Сначала вам нужно будет подготовить базу данных для работы. Саму БД придется создать вручную, а заодно и пользователя, который будет владельцем нашей базы. А поскольку Spamassassin использует хранимые процедуры на языке PL/pgSQL, то также потребуется подключить и язык программирования к вновь созданной базе:

# createuser --no-adduser --no-createdb -U pgsql sauser

# createdb --owner sauser -U pgsql sabase

# createlang -U pgsql plpgsql sabase

Замечание: pgsql – имя администратора PostgreSQL, который имеет право создавать базы и пользователей, sauser – вновь создаваемый пользователь-владелец БД Spamassassin, sabase – база данных Spamassassin.

Далее нужно сформировать правильную структуру БД, для чего воспользуемся готовыми SQL-сценариями, которые можно будет найти в каталоге sql распакованного дистрибутива (при установке из портов это будет каталог /usr/ports/mail/p5-Mail-SpamAssassin/work/Mail-SpamAssassin-3.1.0/sql):

# psql -d sabase -U sauser -e < bayes_pg.sql

CREATE TABLE bayes_expire (

  id integer NOT NULL default «0»,

  runtime integer NOT NULL default «0»

) WITHOUT OIDS;

CREATE TABLE

CREATE INDEX bayes_expire_idx1 ON bayes_expire (id);

... ... много команд ... ...

CREATE FUNCTION

Этой командой мы создали нужные таблицы, индексы и функции в базе sabase для хранения данных статистического анализатора. Теперь осталось указать в конфигурационном файле local.cf соответствующие настройки и перезапустить фильтр:

bayes_store_module Mail::SpamAssassin::BayesStore::PgSQL

bayes_sql_dsn DBI:Pg:dbname=sabase;host=localhost

bayes_sql_username sauser

bayes_sql_password ""

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

# sa-learn --backup > sabase.back

После того как настройки будут изменены для работы с СУБД, восстановите данные из сформированной резервной копии:

# sa-learn --restore sabase.back

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

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

# psql -d sabase -U sauser -e < userpref_pg.sql

# psql -d sabase -U sauser -e < awl_pg.sq

А в конфигурационном файле указать аналогичные приведенным выше опции подключения к базе данных:

user_scores_dsn DBI:Pg:dbname=sabase;host=localhost

user_scores_sql_username sauser

user_scores_sql_password ""

user_awl_dsn DBI:Pg:dbname=sabase;host=localhost

user_awl_sql_username sauser

user_awl_sql_password ""

Дополнительные сведения можно получить из файлов README.* в указанном выше каталоге sql.

Индивидуальный защитный комплект

Spamassassin может быть установлен и для персонального использования без необходимости иметь права администратора системы. Например, если у вас есть учетная запись на сервере, то сможете установить Spamassassin в своем домашнем каталоге и настроить его на проверку почты с помощью procmail. В этом случае вы сможете настроить фильтр именно так, как хотите, не обращаясь к системному администратору сервера. Прежде чем вы установите Spamassassin в свой домашний каталог, вам потребуется указать в ваших переменных окружения пути к модулям и библиотекам Perl, если это не было сделано ранее. Должны быть определены переменные PATH, MANPATH, PER5LIB и LANG.

Прежде чем собрать пакет из исходников, сконфигурируйте его на установку в свой домашний каталог:

# perl Makefile.PL PREFIX=$HOME && make && make install

Далее внесите в ваш файл .forward такую строчку:

«|IFS=» « && exec /usr/bin/procmail -f- || exit 75 #user»

Это приведет к перенаправлению всей вашей почты на procmail, который должен быть настроен на обработку спама (пример см. выше, использовать следует пользовательский конфигурационный файл .procmailrc). Пример конфигурационного файла для procmail можно найти в дистрибутиве под именем procmailrc.example. Не забывайте теперь вызывать нужные программы, указывая путь к файлам, установленным в вашем домашнем каталоге (или укажите нужный каталог в вашей переменной окружения PATH). Подробности смотрите на странице http://wiki.apache.org/spamassassin/SingleUserUnixInstall.

Враг будет разбит!

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

Приложение

Справка

Пакет Spamassassin был разработан Джастином Мэйсоном (Justin Mason) на базе кода программы filter.plx. Весной 2001 года проект был выложен на сайте Sourceforge.net. В настоящее время Spamassassin разрабатывается силами Apache Software Foundation и начиная с версии 3.0 выпускается под лицензией Apache. Spamassassin лежит в основе ряда других антиспамовых решений, например McAfee SpamKiller.