Spamassassin TxRep Reputation plugin e filtro Bayesiano (SQL)

16 luglio 2021 Roberto Puzzanghera0 commenti

TxRep was designed as an enhanced replacement of the AutoWhitelist plugin. TxRep, just like AWL, tracks scores of messages previously received, and adjusts the current message score, either by boosting messages from senders who send ham or penalizing senders who have sent spam previously. This not only treats some senders as if they were whitelisted but also treats spammers as if they were blacklisted. Each message from a particular sender adjusts the historical total score which can change them from a spammer if they send non-spam messages. Senders who are considered non-spammers can become treated as spammers if they send messages which appear to be spam. Simpler told TxRep is a score averaging system. It keeps track of the historical average of a sender, and pushes any subsequent mail towards that average.

Changelog

  • 16 luglio 2021: il campo bayes_token.token è stato cambiato da char(5) a binary(5)
  • Upgrade alla versione 3.4.3: Mi è stato segnalato (grazie a Tony Fung) che la colonna count è stata rinominata nella versione 3.4.3 di spamassassin, perciò è necessario apportare queste modifiche al database dopo l'aggiornamento:
ALTER TABLE `txrep` CHANGE `count` `msgcount` INT(11) NOT NULL DEFAULT '0';

Creazione delle tabelle

> mysql -h [MySQL-IP]-u root -p

USE spamassassin;
CREATE TABLE txrep (
  username varchar(100) NOT NULL default '',
  email varchar(255) NOT NULL default '',
  ip varchar(40) NOT NULL default '',
  msgcount int(11) NOT NULL default '0',
  totscore float NOT NULL default '0',
  signedby varchar(255) NOT NULL default '',
  last_hit timestamp NOT NULL default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (username,email,signedby,ip),
  KEY last_hit (last_hit)
) ENGINE=InnoDB;

CREATE TABLE bayes_expire (
  id int(11) NOT NULL default '0',
  runtime int(11) NOT NULL default '0',
  KEY bayes_expire_idx1 (id)
) ENGINE=InnoDB;

CREATE TABLE bayes_global_vars (
  variable varchar(30) NOT NULL default '',
  value varchar(200) NOT NULL default '',
  PRIMARY KEY  (variable)
) ENGINE=InnoDB;

INSERT INTO bayes_global_vars VALUES ('VERSION','3');

CREATE TABLE bayes_seen (
  id int(11) NOT NULL default '0',
  msgid varchar(200) binary NOT NULL default '',
  flag char(1) NOT NULL default '',
  PRIMARY KEY  (id,msgid)
) ENGINE=InnoDB;

CREATE TABLE bayes_token (
  id int(11) NOT NULL default '0',
  token binary(5) NOT NULL default '',
  spam_count int(11) NOT NULL default '0',
  ham_count int(11) NOT NULL default '0',
  atime int(11) NOT NULL default '0',
  PRIMARY KEY  (id, token),
  INDEX bayes_token_idx1 (id, atime)
) ENGINE=InnoDB;

CREATE TABLE bayes_vars (
  id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(200) NOT NULL default '',
  spam_count int(11) NOT NULL default '0',
  ham_count int(11) NOT NULL default '0',
  token_count int(11) NOT NULL default '0',
  last_expire int(11) NOT NULL default '0',
  last_atime_delta int(11) NOT NULL default '0',
  last_expire_reduce int(11) NOT NULL default '0',
  oldest_token_age int(11) NOT NULL default '2147483647',
  newest_token_age int(11) NOT NULL default '0',
  PRIMARY KEY  (id),
  UNIQUE bayes_vars_idx1 (username)
) ENGINE=InnoDB;

Configurazione

Abilitare TxRep editando il file local.cf

use_bayes 1
bayes_auto_learn 1
use_txrep 1
txrep_factory Mail::SpamAssassin::SQLBasedAddrList

e il file v341.pre

# TxRep - Reputation database that replaces AWL 
loadplugin Mail::SpamAssassin::Plugin::TxRep

e commentando questa riga nel file /etc/mail/spamassassin/v310.pre:

# loadplugin Mail::SpamAssassin::Plugin::AWL

Creare il file /etc/mail/spamassassin/90-sql.cf e aggiungere i parametri di accesso a mysql:

cat > 90-sql.cf << __EOF__
# txRep
txrep_factory                   Mail::SpamAssassin::SQLBasedAddrList
user_awl_dsn                    DBI:mysql:spamassassin:localhost
user_awl_sql_username           spamassassin
user_awl_sql_password           SApassword
user_awl_sql_table              txrep

# bayesean
bayes_store_module              Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn                   DBI:mysql:spamassassin:localhost
bayes_sql_username              spamassassin
bayes_sql_password              SApassword
__EOF__

Test

Per testare il funzionamento del sistema di "addestramento" (learning) salvare un messaggio spam in formato non elaborato (raw per intenderci) nel file spam.txt e lanciare sa-learn in questo modo (supponendo che postmaster@yourdomain.tld sia l'indirizzo email del destinatario)

sa-learn --debug --spam --username=postmaster@yourdomain.tld spam.txt

Addestramento del sistema bayesiano

  • Maggiori informazioni qui

Il classificatore bayesiano può assegnare un punteggio che funga da indice di quanto un dato messaggio sia da considerarsi spam o meno solo se ha già processato almeno 200 messaggi di spam e altrettanti di non spam (ham). E' quindi il momento di addestrare il sistema dandogli in pasto una cartella dove vi sono almeno 200 messaggi che siamo sicuri siano solo spam e un altra di solo ham.

Lanciamo sa-learn. Per la mailbox con lo spam:

sa-learn --showdots --spam spam-directory/*

E per la mailbox con ham:

sa-learn --showdots --ham ham-directory/*

E' importante fare entrambe le cose.

Manutenzione

La tabella txrep andrà ovviamente a riempirsi di record con il passare dei giorni, a una velocità che dipende dal traffico del vostro mail server con un conseguente e progressivo deterioramento della velocità delle query sql. La maggior parte dei records rappresentano degli eventi di spam isolati, che raramente si ripresenteranno e sarai d'accordo che potrebbe essere più conveniente cancellare periodicamente questi record, magari una volta al mese o una volta alla settimana, a seconda del carico di lavoro del mail server.

Creiamo quindi un file che racchiude la query che deve cancellare questi record. E' necessario personalizzarlo inserendo l'account MySQL per spamassassin (naturalmente questo account deve avere accesso al DB "spamassassin" sia dall'IP del mail server che da quello di apache (userprefs via Roundcube che da localhost):

cd /usr/local/etc

cat > txrep_purge.sql << __EOF__
USE spamassassin;
DELETE FROM txrep WHERE last_hit <= (now() - INTERVAL 120 day);
__EOF__

cat > txrep_purge.sh << __EOF__
#!/bin/sh
/usr/bin/mysql -uspamassassin -p[password] < /usr/local/etc/txrep_purge.sql
exit 0
__EOF__

Quindi "spamassassin" è l'utente mysql e "[password]" è la password. Non aggiungere spazi dopo l'ìopzione -u e -p se non si vuole che il programma presenti la richiesta di digitazione della password, cosa non voluta dato che il tutto deve essere lanciato da un cronjob.

Assegnare ora i privilegi di lettura per i due file al solo utente mysql:

chown root:mysql /usr/local/etc/txrep*
chmod ug+x /usr/local/etc/txrep_purge.sh
chmod o-rwx /usr/local/etc/txrep*

Infine editare il crontab

crontab -e

e aggiungere un cronjob come questo:

#minute hour mday month wday command
1 1 * 25 * /usr/local/etc/txrep_purge.sh

Aggiungi un commento