2007年03月25日

spam除け手順をまとめてみる

グレイリストまでかけてもまだまだ漏れてくるのがあるので困ったものだが、現在のところ私の管理サーバ群に実装させているspam除けの手法をメモ程度にまとめてみた。メールサーバにはいずれもpostfixを使っており、設定の容易さからpostfix-pcreも入れている。間違いはいっぱいありそうなので、ご指摘歓迎。

ポート25のルータフィルタリング (iptablesなど)
これは誤操作が怖いのと、公私共に国外とのやり取りが発生しているのでほとんど行わず、DoS対策程度。コンソールが目の前にある家サーバで送信者が国内限定なら、特定地域ブロックごとはたき落とすというのはまぁありか。
HELOの強制
postfixでsmtpd_helo_requiredをyesにしている。昔はそれなりに効果あったようだけど、今どきのspam発信はだいたいHELOも出すのであまり意味はないかもしれない。
送信ホストアドレスでの拒否
postfixのsmtpd_client_restrictionsにcheck_client_access pcre:/etc/postfix/pcre_client_tableのような設定を加えておく。pcre_client_tableはPCRE書式で書いたリストファイルで、たとえばこんな感じ。
/219\.147\.232\.\*/     DISCARD
 …
単一のホスト名やIPであれば//形式じゃなくてもいい。2列目はOK(通し)、REJECT(拒否して返却)、DISCARD(拒否して破棄)といったものが指定できる。spammer相手にREJECTしてもろくなことにならない(また戻ってきたり)のでDISCARDしよう。ポート25フィルタリングに近いけど、こちらはpostfixだけでできるので、設定に失敗してもログインできなくなるなんてことはない。PCREファイルは書いた時点で反映されるので、postmapなどで変換する必要はない。
送信者アドレスでの拒否 (リストによる拒否)
SMTP FROM(メールのFrom:アドレスとは違う。メールヘッダのReturn-Path:に書かれているようなアドレス)で判定を行うようにもする。smtpd_sender_restrictionsにcheck_sender_access pcre:/etc/postfix/pcre_sender_table のように加え、同様にリストファイルを作成する。たとえば
/^shima_tani_h@infoseek/        DISCARD
/^.*@wildclubs.*\.info/         DISCARD
 …
送信者アドレスでの拒否 (DNSによる拒否)
これも最近は効果がなくなってきた手法だけど。SMTP FROMに書かれた多種多様な送信者アドレスのドメイン=spammerのドメインを提供するDNSサーバを調べると、実はspammerが管理するごく少数のDNSサーバに行き着くというのがあった。そこで、smtpd_sender_restrictionsにcheck_sender_ns_access pcre:/etc/postfix/reject_ns のように加えて、DNSサーバのIPを列挙する。
ns1.is-name.net  DISCARD
 …(「postfix check_sender_ns_access」で探すといろいろ見つかるはず)
宛先名での拒否
ローカルにユーザがいないならそもそもREJECTするといえばそれまでなんだけど、うざったいピンポンが起きることもある。smtpd_recipient_restrictionsにcheck_recipient_access pcre:/etc/postfix/pcre_rcpt_table、で存在しないのにやたらと届く宛先に来たら捨てるとか。
/^\d+@/  DISCARD
 …
グレイリストでの拒否
昨日書いたpostgrey。smtpd_recipient_restrictionsにcheck_policy_service inet:127.0.0.1:60000 を加える。ホワイトリストのメンテナンスも忘れずに。
amavisd-new+clamavによるコンテンツフィルタリング
amavisd-newではspamassassinの呼び出しもできるけど、spamassassinはアグレッシブすぎることがあるので、基本的にはclamavと合わせたウイルススキャンを主としている。clamavはvolatileのものを使っている。/etc/amavis/amavisd.confを設定(特に$mydomain、$inet_socket_port、$forward_method、$banned_filename_re)し、たとえばポート10024で動かしておく。postfixのmain.cfでは「content_filter = smtp-amavis:[127.0.0.1]:10024」、master.cfでは「127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o strict_rfc821_envelopes=yes」のようにして、ポート25で受けたメールをポート10024のamavisに通し、amavisは結果をポート10025のフィルタリングはもうしないpostfixに吐くというように流している。
全体procmailによるコンテンツフィルタリング
postfixでmailbox_commandにprocmail -a "$EXTENSION"としてあるので、ローカルメールボックスへの最終配送はprocmailを使っている。よって、/etc/procmailrcで全体の統制ができる(とはいえ、あまり複雑なことはしないほうがよさそう)。たとえば最近Received: うちのサーバ名 (unknown [spammerの中国ボットIPアドレス]) などというのがよく来てるので、こういうわかりやすそうなのは捨てる。
SHELL=/bin/sh
PATH=/bin:/usr/bin
SENDMAIL=/usr/sbin/sendmail

:0 Hf
* ^Received: from kmuto\.jp \(unknown
| formail -b -f -a"X-global-spam-check: fake" (←メールヘッダを加えている)

 …

:0
* ^X-global-spam-check: (←先ほど付けたメールヘッダを発見)
/dev/null
まぁ実際にはいきなり/dev/nullというのもアグレッシブすぎるので、junkフォルダに転送するようにしている。
各個procmailによるコンテンツフィルタリング
これ以上は誤認で廃棄してしまう恐れがあるので、ユーザごとでの設定としている。基本になるのはprocmailで、各ユーザの~/.forwardに「| /usr/bin/procmail」とでもしておく(IFS=' 'とかexit 75とかってpostfixでも必要なんかな?)。~/.procmailrcはこんな感じから。
SHELL=/bin/sh
PATH=/bin:/usr/bin
SENDMAIL=/usr/sbin/sendmail
LOGFILE=/home/kmuto/procmail.log (←デバッグ用)

(ここに以降の設定を入れていく)

:0
$DEFAULT
spamassassinでのフィルタリング
spamassassin、spamc、razorを入れておく。razorは共同構築型のフィルタリングネットワーク、らしい。今のところRBLのようなひどい誤認などはない模様。入れておけばspamassassinが勝手に拾って使ってくれるようだ。spamdをデーモン化させるのは危険もあるのだが、毎度起動しているとOOMが働いてもっとひどいことに…ということがあるのでデーモン起動で(/etc/default/spamassassinでENABLED=1)。/etc/spamassassin/local.cfは次のようにしている。
ok_languages    ja
required_hits   10

body KI         /\033\$[B@]/ (←$が誤認されるので日本語開始コードのスコアを下げる)
score KI        -2.394

header SJISFROM From =~ /=\?shift\-jis\?/ (SJISのFromはspam)
score SJISFROM  3
 …
あとは、spamcを通すよう~/.procmailrcに書いておく。
:0fw
| spamc

:0
* ^X-Spam-Status: Yes
/dev/null
:0
* ^X-Spam-Flag: Yes
/dev/null
ベイジアンフィルタによるフィルタリング
一世を風靡したベイジアンフィルタだけど、spammer側の対策もすっかり済んでしまった感じ…。一応まだ使っているけど、「重いだけ」になっているかもしれない。bogofilterとbsfilterを利用。
:0fw
| bogofilter -u -e -p
:0
* ^X-Bogosity: Spam
/dev/null

:0fw
| bsfilter -a --pipe --insert-flag --insert-probability
:0
* ^X-Spam-Flag: Yes
/dev/null
初期データのhamとspamは手持ちのものから適当に。その後のspam認識追加については、漏れたものを学習用IMAPフォルダに入れて、それを「formail -s bogofilter -s < spam」(bogofilter用)「bsfilter -s < spam」(bsfilter用)「formail -s sa-learn --spam < spam」(spamassassin用)という処理をするcronで更新させるようにしている。ただ、あまりやりすぎると今度は誤認のほうが多くなるので、それほど期待しないほうがよいと思う。
procmailでの個別撃破
残りはかなり地道で、ヘッダやボディを見て特徴的なものを/etc/procmailrcあるいは~/.procmailrcに書いていく。
:0 Hf
* ^From: .*@.*(shopjapan|bls|vip|aviss|dtmail\.idg|ogilvy)\.co\.jp (正規表現で指定)
| formail -b -f -a"X-procmail-spam-check: jp"

:0 Hf
* ^Subject:.*iso-2022-jp
* ^Subject:.*\/.*
* ? echo "$MATCH" | nkf --utf8 | egrep '未承諾広告|援助します' (日本語Subjectを分解して処理)
| formail -b -f -a"X-procmail-spam-check: jp"

:0
* ^X-procmail-spam-check:
/dev/null
MUAでの拒否
現在メールソフトに使っているWanderlustでもいくつかのフィルタリングはできるようだし、WindowsのアンチウイルスソフトであればMUAの前に取り付いてフィルタリングもやってくれるようなのだが、ここまででだいたい落ちているので今のところは目視フィルタで収まってはいる。が、確実を期すならMUAでのフィルタリングを考えてもよいだろう。Icedove/Thunderbirdではspam登録を簡単にできるので、それを使うのもよい。

RBL系は負荷や信頼性の面で使わないことにしている(blogコメントspamのほうはniku.2ch.netのRBLを利用)。spamprobeは昔使ってたのだけど、データベースが異常に肥大化して使いものにならなくなってしまい、やめてしまった。



/

Postfix 2.1までの情報を網羅。現時点でPostfixのガイドの最高峰に位置する。でも2.4版もほしいなぁ。



/

ちょっと古いんだけど、procmailについては実際のところこれくらいしかない(あとは『Debian辞典』にこれを参照して少し書いたくらい)。