Antispam Tips

Menu

アンチスパム,

アンチスパム

あまりのスパムメールの多さに業を煮やして、最近話題のSpamAssassin(スパムアサシン)を導入するなり。

install

SpamAssassinprocmailから呼び出す例が多いが、使ってみたところprocmailqmailの仮想メールボックスへの配送ができなさそうだったので、qmailから直にSpamAssassinを使用する事に。2003/12/27

まずはperlのCPANモジュールをinstallする。

[yano@portage software]# perl -MCPAN -e shell
cpan> o conf prerequisites_policy ask
cpan> install LWP MD5
cpan> install HTML::Parser DB_File Net::DNS BerkeleyDB Net::SMTP Mail::SPF::Query IP::Country::Fast Digest::SHA1

http://spamassassin.apache.org/から3.0.1をダウンロードしてinstallする。

[yano@portage software]$ wget http://www.meisei-u.ac.jp/mirror/apache/dist/spamassassin/Mail-SpamAssassin-current.tar.bz2
[yano@portage software]$ mv Mail-SpamAssassin-current.tar.bz2 Mail-SpamAssassin-3.0.1.tar.bz2
[yano@portage software]$ bunzip2 -dc Mail-SpamAssassin-3.0.1.tar.bz2 | tar xvf -
[yano@portage software]$ cd Mail-SpamAssassin-3.0.1/
[yano@portage Mail-SpamAssassin-3.0.1]$ perl Makefile.PL PREFIX=/usr/local
What email address or URL should be used in the suspected-spam report
text for users who want more information on your filter installation?
(In particular, ISPs should change this to a local Postmaster contact)
default text: [the administrator of that system] [Enter]

Check network rules during 'make test' (test scripts may fail due to network problems)? (y/n) [n] [Enter]

Checking if your kit is complete...
Looks good
Writing Makefile for Mail::SpamAssassin
Makefile written by ExtUtils::MakeMaker 5.45
[yano@portage Mail-SpamAssassin-3.0.1]$ make
[yano@portage Mail-SpamAssassin-3.0.1]$ sudo make install
取り敢えず単体でテスト。ゴミ箱からスパムメールを取出して喰わせてみる。
$ /usr/local/bin/spamassassin -t < spamtest.txt
Spam detection software, running on the system "portage", has
identified this incoming email as possible spam. The original message
has been attached to this so you can view it (if it isn't spam) or block
similar future email. If you have any questions, see
the administrator of that system for details.

Content preview: extlucbvdaztq kuvpqebtvuk mxeuokdavdjbgc tacmetbgjm…

Content analysis details:   (10.2 points, 5.0 required)

pts rule name              description
---- ---------------------- --------------------------------------------------
1.0 SUBJ_HAS_SPACES        Subject contains lots of white space
0.6 PENIS_ENLARGE2         BODY: Information on getting larger penis/breasts
4.3 MONEY_BACK             BODY: Money back guarantee
0.1 HTML_70_80             BODY: Message is 70% to 80% HTML
0.1 HTML_FONTCOLOR_RED     BODY: HTML font color is red
0.4 HTML_FONT_INVISIBLE    BODY: HTML font color is same as background
0.1 HTML_FONTCOLOR_UNKNOWN BODY: HTML font color is unknown to us
0.0 HTML_MESSAGE           BODY: HTML included in message
0.1 HTML_FONT_BIG          BODY: HTML has a big font
0.3 HTML_TAG_BALANCE_BODY  BODY: HTML has unbalanced "body" tags
0.1 HTML_FONTCOLOR_UNSAFE  BODY: HTML font color not in safe 6x6x6 palette
3.1 USERPASS               URI: URL contains username and (optional) password
0.0 CLICK_BELOW            Asks you to click below
と、このメールではスパムらしさ10.2ポイントと判定された模様。デフォルトで5.0ポイント以上をスパムと判定するようになっているそうだ。

このままでは日本語のスパムメールには対応していないので、TLECから日本語スパム対応版の設定ファイルを頂戴し、サイト全般に対応させるべく /etc/mail/spamassassin/local.cf と置き換える。 ついでに題名の"drug"、本文の"アフィリエイト""報酬"も条件に追加。HTMLメールとSPAM_COP登録済みのポイントも増やす。全体的に厳しくした分、判定閾値も10.0ポイントに上げておく。2004/01/09

$ cd /etc/mail/spamassassin
/etc/mail/spamassassin
$ mv local.cf local.cf.org; chmod -w local.cf.org
$ snarf http://tlec.linux.or.jp/docs/user_prefs local.cf
$ cp local.cf local.tlec; chmod -w local.tlec
$ vi local.cf       # ここで編集
ちなみに日本語の条件を追加する場合、"od  -a"の出力から編集する
$ od -a
報酬
0000000 J s = 7 nl
0000005
$ less /etc/mail/spamassassin/local.cf
# "報酬" -> JIS文字調査方法:od -a
body BODY_HOUSHU /Js=7/
describe BODY_HOUSHU HOUSHU include
score BODY_HOUSHU 3.0
実際の設定ファイル > http://www.bravotouring.com/~yano/computer/linux/spamassassin.local.cf.txt
差分 > http://www.bravotouring.com/~yano/computer/linux/spamassassin.local.diff.html

/var/qmail/bin/qmail-spamassassin

~/.qmail から呼び出すフィルタを作成する。スパムと判定した場合は99を返してqmail-localで配送されないようにする。

#!/bin/sh
PATH=/usr/bin:/usr/local/bin:/bin
export PATH
bname=`basename $0`
tmpfile=`mktemp /var/tmp/$bname.XXXXXX` || exit 111
trap 'rm -f $tmpfile' 0 1 2 3 5 9 15
/usr/local/bin/spamassassin -e > $tmpfile
case $? in
0)
        # not spam. normal operation
        exit 0;
        ;;
*)
        case $# in
        0)
                ;;
        *)
                # forward spammed mail for 1st argument
                /var/qmail/bin/qmail-inject $1 < $tmpfile
        esac
        exit 99; # no more deliver in .qmail
esac
続いて ~/.qmail を変更。/var/qmail/bin/qmail-spamassassin を呼ぶようにする。
# SPAMは問答無用で捨て(転送する時はアドレスを指定)
# /var/qmail/bin/qmail-spamassassin メアド
| /var/qmail/bin/qmail-spamassassin spam@bravotouring.com

# Mailディレクトリの設定
./Maildir/
これでスパムメールを自分宛に送ってみて、spam@bravotouring.comに転送される事を確認。しばらくは受信しといてまとめて捨てる事にしよう。

参照
SpamAssassinhttp://spamassassin.apache.org/
Bug 2855:Simple patch to make spamc return is_spam result
http://bugzilla.spamassassin.org/show_bug.cgi?id=2855
TLEChttp://tlec.linux.or.jp/
ITmedia エンタープライズ:Linux Tipshttp://www.itmedia.co.jp/help/tips/linux/l0679.html
人生ままならずhttp://ssss.jp/~trombik/email/spamassassin.html
みもりのさんぽうhttp://www.mimori.org/~h/diary/d200305b.html
procmailhttp://www.procmail.org/

daemon化

と言ってもバイナリはできているので daemontools 用の起動環境を作るだけ。念の為、実行アカウント:グループもspamd:spamdで新規作成。

## アカウント:グループ作成
# /usr/sbin/groupadd spamd
# /usr/sbin/useradd -c "SpamAssassin Account" -d /dev/null -g spamd -s /bin/false spamd
#
## 起動環境作成
# mkdir /etc/spamassassin
# mkdir /etc/spamassassin/log
#
## それぞれrunファイルを作成する
#
## ログファイル環境作成
# mkdir /var/log/spamassassin
# chown -R spamd:spamd /var/log/spamassassin
#
## superviser管理下に配置(自動起動)
# sudo ln -s /etc/spamassassin /service

/etc/spamassassin/run

spamd のポート番号のデフォルトは 783 だが、敢えて 5783 に変更。

#!/bin/sh
exec env PATH=/usr/local/bin:/usr/bin:/bin \
        setuidgid spamd \
        spamd -i localhost \
        -p 5783 \
        --syslog=stderr \
        2>&1

/etc/spamassassin/log/run

#!/bin/sh
exec /usr/local/bin/setuidgid spamd /usr/local/bin/multilog t /var/log/spamassassin

「あとはspamcを呼び出すように/var/qmail/bin/qmail-spamassassinを書換えればお終い」と思いきや、実はspamcSPAM の検出を終了コードで返さないという事がわかり愕然。しかしさすがは困った時のGoogle先生。ソースをちょこっと読んで変数名を指定して検索するとお見事、先週リリースされたばかりBugzilla Bug 2855を教えてくれたので、早速パッチを適用。(2003/12/27)
これは2.61導入時の話で、最新版の3.0.0ではこの修正が盛り込まれた為パッチ不要。(2004/10/20)

$ cd Mail-SpamAssassin-2.61/spamd
$ snarf "http://bugzilla.spamassassin.org/attachment.cgi?id=1624&action=view" \ ## 続く
SPAMC_RETURN_RESULT.diff
http://bugzilla.spamassassin.org/attachment.cgi?id=1624&action=view (unknown size)
SPAMC_RETURN_RESULT.diff        [\]       2K
2546 bytes transferred in 0.01 sec (351.48k/sec)
$ patch < SPAMC_RETURN_RESULT.diff
patching file libspamc.h
patching file spamc.c

$ cd ..
$ make
$ sudo make install

/var/qmail/bin/qmail-spamassassin

spamassassinspamc に変更。ホスト名、ポート番号、-E オプションも抜かり無く。 また誤判定の救出を速やかに行う為、スパムとして排除したメール(日本語タイトルのもののみ)の題名と送信者を ~/.spamassassin/spam.log に記録し、~/.bashrcで表示するようにする。

#!/bin/sh
PATH=/usr/bin:/usr/local/bin:/bin
export PATH

logfile=~/.spamassassin/spam.log

# 日本語の題名だけログに記録
function logging {
  awk -v result=$1 '
    BEGIN { title = sprintf("%s,%s", strftime("%Y/%m/%d %X"), result) }
    /^Subject:/ { subject=$0; if(/?iso-2022-jp?/) jp=1;}
    /^From:/ { from=$0; }
    END { if(jp) printf("%s,%s,%s\n", title, subject, from);}
  ' $tmpfile \
  | nkf -m      # MIME decode
}

bname=`basename $0`
tmpfile=`mktemp /var/tmp/$bname.XXXXXX` || exit 111
trap 'rm -f $tmpfile' 0 1 2 3 5 9 15
/usr/local/bin/spamc -d localhost -p 5783 -E > $tmpfile
#/usr/local/bin/spamassassin -e > $tmpfile # コメントアウト
case $? in
0)
        # not spam. normal operation
        exit 0;
        ;;
*)
        case $# in
        0)
            ;;
        *)
            # forward spammed mail for 1st argument
            /var/qmail/bin/qmail-inject $1 < $tmpfile
        esac
        if [ $logfile ]; then
            logging spam >> $logfile
        fi
        exit 99; # no more deliver in .qmail
esac

/etc/sysconfig/ipchains

最後にspamd用のポートはlocalhost以外の接続を拒否する設定を 追加。


# spamd
-A input -s 127.0.0.1/24 -d 127.0.0.1/24 5783 -p tcp -j ACCEPT
-A input -s 0/0 -d 0/0 5783 -p tcp -j REJECT -l

宛先不明スパムの登録

blogwatcher、cron、tcpanalogなど実在しないメールアカウントを宛先にして送られてくるメールも多数ある。しかもほとんどが架空の発信者を偽装しているので、エラーメールもまた "failure notice" としてpostmasterに返って来てしまう。そんな悪循環を断つために前記アドレスをおとりアドレスとして受信してしまい、洗いざらいスパムとして登録する事にした。

収集用のメールボックス spam-learn を新たに作成し、おとりアドレスで受信したメッセージを全て集約する。

$ su pop   # DOMAINOWNERアカウントで操作する
$ cd
/home/pop/
$
$ # spam-learnを作成する
$ vida-passwd -a -u spam-learn -p ********
$ vida-assign -a -u spam-learn
$ vida-maildirmake spam-learn Maildir
$ echo ./Maildir/ > ~/spam-learn/.qmail
$
$ cd /var/qmail/alias/
/var/qmail/alias/
$
$ # おとりアドレスをspam-learn(spam-decoy)に関連付ける
$ sudo echo "&spam-learn" > .qmail-spam-decoy
$ sudo ln -s .qmail-spam-decoy .qmail-default     # 宛先不明はdefaultで処理される
/etc/cron.daily/spam_daily.cron

囮で収集したスパムメールは学習させたあとspam@bravotouring.comに転送する。またSpamAssassinのログをデイリーに分割する時に、囮で収集したスパムの件数を"collected by decoy"としてロギングする。

#!/bin/sh
#

# awkのパス
AWK=/bin/awk
# qmail-injectのパス
QMAIL=/var/qmail/bin/qmail-inject

#
LANG=us;

# イベント抽出対象:昨日
#
TARGET='yesterday'
TARGET_DATE=`date -d "$TARGET" | awk '{printf("%s %2d",$2,$3)}'`;
TARGET_YMD=`date -d "$TARGET" +"%Y-%m-%d"`;

logfolder=~yano/.spamassassin/
dailylog=$logfolder/$TARGET_YMD.log

#======================================================
# 前日分の処理
#======================================================

/usr/local/bin/svc -a /service/spamassassin/log # currentログのローテート

# 前日分のログをデイリーに書き出し
#-----------------------------------------------------
sed -e 's/^@[0-9a-f]* //' /var/log/spamassassin/@* \
  | grep ^$TARGET_YMD | sort > $dailylog

chown yano:members $dailylog

# おとりアドレスで収集したSPAMを学習させ、spamへ転送
#-----------------------------------------------------
# ドメインオーナーのアカウント(pop)
DomPopOwner=pop
export HOME=/home/$DomPopOwner
MAILFOLDER=$HOME/spam-learn/Maildir/new

# 転送先
FWD_ADDRESS=spam

# SPAMの学習
setuidgid $DomPopOwner sa-learn --no-rebuild --spam --dir $MAILFOLDER >/dev/null 2>&1
setuidgid $DomPopOwner sa-learn --rebuild >/dev/null 2>&1

# スパム件数として計上されるようログに残す
ls $MAILFOLDER/* | wc | $AWK '{print "'$TARGET_YMD' collected by decoy " $1}' >> $dailylog

# メールを個々にspam@…へ転送
for mailmsg in $MAILFOLDER/* ;
do
  # awkでヘッダーの最後に"X-Spam-Flag: YES"を追加して、転送
  $AWK '/^$/{if(!ignore)print "X-Spam-Flag: YES";ignore=1;}{print}' $mailmsg \
   | $QMAIL -a $FWD_ADDRESS

  # 処理したら削除
  /bin/rm -f $mailmsg
done

/etc/cron.weekly/spam_weekly.cron

月初からのスパムメール処理件数を日毎に纏めてレポートする。

#!/bin/sh
#

# awkのパス
AWK=/bin/awk
# qmail-injectのパス
QMAIL=/var/qmail/bin/qmail-inject

MAILTO=logwatcher@bravotouring.com
MAILFROM=spamassassin@bravotouring.com
MAILSUBJECT="SpamAssassin report"

# メール送信用出力ファイル
#
outfile=/tmp/$$mail.$RANDOM

#
LANG=us;

# イベント抽出対象:昨日
#
TARGET='yesterday'
TARGET_DATE=`date -d "$TARGET" | awk '{printf("%s %2d",$2,$3)}'`;
TARGET_YMD=`date -d "$TARGET" +"%Y-%m-%d"`;
TARGET_YM=`date -d "$TARGET" +"%Y-%m-"`;

date | awk '{print "'$0' working at " $0}' >> $outfile

#
# SpamAssassinのサマリー抽出 2003/12/29
#
# format:
# 2003-12-29 14:14:18.544718500 connection from portage [127.0.0.1] at port 1902
# 2003-12-29 14:14:19.614265500 processing message <WKWGIVK-0009981715518@croft> for pop:503.
# 2003-12-29 14:14:30.997354500 identified spam (8.6/7.0) for pop:503 in 12.0 seconds, 1978 bytes.
#

logfolder=~yano/.spamassassin/
dailylog=$logfolder/$TARGET_YMD.log

#======================================================
# 前日までのSPAM件数レポートを作成
#======================================================

echo -e "\n# SpamAssassin report at $TARGET_DATE"   >> $outfile
echo -e "#---------------------------------------"  >> $outfile
echo -e "\n   date,   total,clean, spam, perscent" >> $outfile

for logfile in $logfolder/$TARGET_YM*.log;
do
$AWK '
  BEGIN { total=0; spam=0; clean=0; checking=0; }
  /processing message/ { total++; checking=0; }
  /checking message/   { checking=1; }                        # test結果は除外
  /clean message/      { if(!checking) clean++; checking=0; }
  /identified spam/   { if(!checking) spam++; checking=0; }
  /collected by decoy/ { total+=$5; spam+=$5; }               # 囮による収集数
  { date = $1 }
  END {
    printf("%s, ", date);
    if (0 < total) printf("%5d,%5d,%5d,%5d%%", total, clean, spam, (spam * 100)/total);
    else printf("no mail");
    printf("\n");
  } ' $logfile >> $outfile
done

#
# メール送信
#

(echo "To: $MAILTO"
echo "From: $MAILFROM"
echo "Subject: $MAILSUBJECT in $TARGET_DATE"
echo ""
cat $outfile )| $QMAIL -f $MAILTO
rm -f $outfile


Tipsに戻る | Topに戻る

Copyright (c) 2002-2004 by YANO
All rights reserved.