Antispam IV – Adaptivní greylisting
Nejprve musím vysvětlit, co to ten „adaptivní gerylisting“ vlastně je a čím se od normálního greylistingu liší. Tradičně greylisting předstírá dočasnou chybu SMTP a nutí odesílající mailserver spojení po nějakém čase zopakovat. To celkem dobře funguje na odchycení spambotů, které potřebují co nejrychleji chrlit e-maily a nemají čas ze zdržovat opakovanými pokusy o doručení.
Poté co ale dojde k opakovanému pokusu o doručení se už gerylisting znovu neaplikuje protože si server na nějakou dobu zapamatuje kombinaci adresy odesílatele a IP adresy serveru. Bohužel první komunikace je tímto zdržena a přiznejme si, že to je občas k nas….. Ale protože statistiky výsledků greylistingu z hlediska úspěšnosti mi nedovolují tuto dosti svéráznou metodu boje proti spamu hned zavrhnout přemýšlel jsem jak její vedlejší efekty odstranit nebo alespoň minimalizovat. A to se mi myslím povedlo „adaptivním greylistingem“, tedy aplikovaním greylistingu pouze na podezřelé e-maily. Pro zjištění podezřelých e-mailů je samozřejmě nutné mít spamassassin, nebo podobné řešení, nastavené tak aby e-mail byl zpracován už během SMTP session, což při použití např eximu není žádný problém.
spamd_address = /tmp/spamd.sock
acl_smtp_data = acl_check_data
acl_check_data:
deny
message = This message $h_message-id: was classified as SPAM.
spam = qscand/defer_ok
accept
Takže teď použijeme grelisting jako doplňující test pro podezřelé e-maily s bodovým ohodnocením poblíž spínací úrovně spamassassinu. Tyto e-maily jsou velice často SPAM, ale není možné je bezpečně zahodit, protože by množství false-positive bylo mimo tolerovatelnou mez. Na základě mých praktických testů mi vychází optimální bodové hodnocení spamassassinu pro e-maily u kterých je vhodné aplikovat grelisting okolo dvou bodů. Předchozí příklad kontroly se tedy malinko zkompiluje:
hide mysql_servers = 127.0.0.1/databaze/login_jmeno/login_heslo
spamd_address = /tmp/spamd.sock
acl_smtp_data = acl_check_data
GREYLIST_TEST = SELECT CASE \
WHEN now() - block_expires > 0 THEN 2 \
ELSE 1 \
END \
FROM exim_greylist \
WHERE relay_ip = '${quote_mysql:$sender_host_address}' \
AND from_domain = '${quote_mysql:$sender_address_domain}'
GREYLIST_ADD = INSERT INTO exim_greylist (relay_ip, from_domain, \
block_expires, record_expires, create_time) \
VALUES ( '${quote_mysql:$sender_host_address}', \
'${quote_mysql:$sender_address_domain}', \
DATE_ADD(now(), INTERVAL 5 MINUTE), \
DATE_ADD(now(), INTERVAL 7 DAY), \
now() \
)
acl_check_data:
warn
spam = qscand/defer_ok
add_header = X-Spam-Flag: YES
warn
set acl_m2 = ${lookup mysql{GREYLIST_TEST}{$value}{0}}
accept
condition = ${if !def:spam_score_int {1}}
add_header = X-Spam-Note: SpamAssassin invocation failed.
deny
message = This message $h_message-id: was classified as SPAM.
condition = ${if >{$spam_score_int}{55} {1}}
delay = ERROR_DELAY
warn
condition = ${if >{$spam_score_int}{20} {1}}
set acl_m2 = ${lookup mysql{GREYLIST_TEST}{$value}{0}}
defer
message = Greylisted - please try again a little later.
condition = ${if >{$spam_score_int}{20} {1}}
condition = ${if eq{$acl_m2}{0}{1}}
condition = ${lookup mysql{GREYLIST_ADD}{yes}{no}}
defer
message = Greylisted - please try again shortly.
condition = ${if >{$spam_score_int}{20} {1}}
condition = ${if eq{$acl_m2}{1}{1}}
accept
add_header = X-Spam-Score: $spam_score
add_header = X-Spam-Level: $spam_bar
Pro správnou funkci je samozřejmě nutné aby byla dostupná databáze do které se budou ukládat informace o stavu pokusů o doručení. Je samozřejmě možné použít lokální souborovou databázi sqlite, která bude jistě vhodná pro spoustu menších serverů. Já jsem ale použil MySQL, protože antispamy provozujeme v clusteru a potřebuju aby sdílely data o grelistingu. Takže struktura databáze pro výše zmíněný príklad:
CREATE TABLE `exim_greylist` (
`relay_ip` varchar(64) default NULL,
`from_domain` varchar(255) default NULL,
`block_expires` datetime NOT NULL,
`record_expires` datetime NOT NULL,
`origin_type` enum('MANUAL','AUTO') NOT NULL default 'AUTO',
`create_time` datetime NOT NULL,
KEY `block_expires` (`block_expires`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Tímto přeju hodně ulovených spamů a rychle doručených e-mailů bez zbytečného zdržování greylistingem.