manekineko倉金家ホームページ

趣味の部屋/サーバー構築メモ その2/メールサーバー その2

再度のスパム対策

2011年5月7日(土)開始 2011年9月7日(水)更新
 通常のメール(とはいっても多くはダイレクトメールやメールマガジンのたぐい)が受信できなかったことが幾度かありメールサーバーの送受信制限を緩和したところ、迷惑なスパムメール受信が増えてしまいました。
 で、あたらしい方法を検討し採用したところ、激減! 簡単なわりに効果絶大です。
でもメールが全然来ない日もあり、逆になんだか少し寂しくなったりして…。


 10年近くホームページのトップに堂々とメールアドレスをさらしてきたこともあってか、私のメールアドレスには毎日百通を越えるスパムメールが来ます。
そのためスパム対策のひとつとして逆引き設定がされていない接続からのメールは受けないようにしていました。この効果は絶大で、海外からのほとんどのスパムメールをはじくことができていました。

 ところがなんと、日本国内の名の知れた企業の中にも逆引き設定をしていないメールサーバーを使っているところがあり、通常のメールの受信に支障が出たことが2、3度あって、この設定を解除しました。またまともなはずの大手企業や公的機関のメールマガジンなどにも同様のことがありました。(おそらくこれらはメール発送を下請業者にでも丸投げしているのではと思われます。)

 昔は規格か何かでメールサーバーは逆引き設定することになっているのかと思っていましたが、最近調べたらメールサーバーの逆引き設定は、少なくとも日本では常識ではありますが規定ではありませんでした。(会社や組織の表札や看板みたいなもんだがね。)だから文句も言える筋でもないのですが、うしろめたい仕事のものならともかく、やっぱりちゃんと名乗ってほしいよね。

 BLサービスやaccess、header_checksなどで大半(約9割)のスパムは阻止できているのですがそれでもスパムメールを一日数通は受信してしまうようになり、手動でaccessやheader_checksに登録していました。でも次から次へとちがうアドレスやIPでくるので一向に減らずらちがあきません。それどころかどんどん増えてくる気がします。永遠にこんなことをやってはいられません。

 で、方策をいろいろ検討して、あたらしい方法を採用。

新方式の検討
 しばらく到達するスパムメールのアドレスなどを登録しながら見ていますと、ほとんどすべてIPの逆引きが設定されていません。
ヘッダーはReceived: from .... (unknown [xxx.xxx.xxx.xxx])となっています。
 やはり逆引き設定されていないホストを拒否するのは絶大な効果があるようです。
またこの方法の妥当性についても "http://www.hart.co.jp/spam/rejiponly2.html" などの記事を読んで考えてみましたが、他人のメールを業務として取り扱う場合ならともかく、個人のメールサーバーでやる分には非難される筋合もないように思います。
で、これを復活させることにしました。

 ただし、まともなメールを拒否してしまわないようにするため何か考えなくてはなりません。何万件のスパムを撃退しても1通の大事なメールを失ったら全くやる意味もありません。
 まともなメールサーバーなら配送を再試行してくるはずなので、これを利用することにします。(実は以前スパムでないメールを拒否してしまったときこれに気がついたのが再送アクセスが幾度もあったため。)

 ただ、逆引き設定をしていないだけのまともなメールサーバーには余計な負荷をかけてしまうことになりますが、私の場合は日本のメールしかやりとりはせず、日本のメールサーバーはほとんどすべて逆引き設定はされているので(例外が10年間で3件ほどあったが)、実質まともなメールを送ってくるところに迷惑をかける可能性はほとんどないと考えられます。
 また逆引き設定をしていないサーバーからのメールは少なくともいったんは拒否するという手法も実際にはかなり使われているようなので、まともなメールサーバーを目指すならちゃんと設定してほしいし、規則ではないが日本では習慣や礼儀の問題でちゃんと名乗らないなら警戒されてもしかたがないよと言いたいところ。

 ところでCentOSにはすでに自動的に再送を検知して登録してくれるpostgreyというパッケージがありますが、初回とにかく1回は再送を促すようになっているみたいで大げさ。それにPerlで書かれているみたいだし。(Perlわかんない!単に個人的なことだけど。)
さらに逆引き設定はされていてもあやしい(動的IPらしい)名前の接続もいったん蹴るようになっているらしいが、現在の状況ではそこまでしなくてもいいみたいだし。

 で、逆引きがちゃんとできないアクセスに再試行要求を出し、簡単なシェルスクリプトでログを監視して再送アクセスがあった場合自動的にその接続を許可するようにしました。これだと状況に応じて自由に改変できるし、少しくらいスパムメールが漏れてくるのはよしとしましょう。
結果、たいへん良好!初日は1通もメールが来ずにかえって心配になったくらいです。
 まれにスパムでもオープンリレーのメールサーバーを見つけてそれを使っているためかちゃんと再送されるのや、しつこく短時間にいくつも送りつけてくるのがあるのですが、そう多くはありません。たまにはどんなことが書いてあるか見てみるのもいいかといった程度。

スクリプトと設定
 すでにこのような目的に合うスクリプトなどはないかと調べてみると、ありました。
すごく研究している方が世の中にはいるもので、さっそく参考にさせていただき、スクリプトを使わせていただくことにしました。

 スクリプトは
http://www.gabacho-net.jp/anti-spam/log-sorting-script.html よりいただき、自動的に登録されるように改造しました。
以下、参考に。スクリプト check450retry.sh :

2011.5.10 V1.0 自動登録スクリプト完成(再試行回数による登録と通知)
2011.5.17 V2.0 判定に再試行アクセス継続時間を加えました。
2011.5.22 V2.1 バグ修正。コメント追加等。
2011.5.23 V3.0 再試行があったら早めに通知するように改良。
 〜 この間、実際使ってみて使いにくいところなどいろいろ改良。〜
2011.6.12 V3.9 ほぼ満足のいくもの完成。以後細かい改良は続けることとします。

以下になるべく最新版を掲載しておきます。
 コードが長く、ページが読みにくくなるので別表示にしました。

本来シェルスクリプトですが読むためにテキストソースに(.txt追加)してありますので、コピーして使うならシェルスクリプトとして設置してください。
ブラウザによっては(あるいはパソコンの改行コードによる?)改行してくれないことがあります。その場合、ソースを表示するとちゃんと見れるかもしれません。

文字化けしましたらエンコードにUTF-8を指定してください。


←ダウンロードするならこちら。
あるいはアーカイブしていない生のファイルがお好みなら「ダウンロードの小部屋」からダウンロードできます。
他のお薦めファイルも置いてありますのでどうぞ覗いてみてください。

設定
(1)テキストエディタで頭の設定部分を設定します。
(2)上記スクリプトを(もちろん実行権限をつけて)/etc/cron.hourlyに置きます。
 10分間隔のcronでもつくってそこに置けばさらにいいです。
(3)いったん手動で実行してみます。(cd /etc/cron.houryで ./check450retry.sh)
 あるいはcronテストも兼ねてしばし待ちますと /etc/postfix/access_retryがつくられます。
 ファイルが無事作成されることを確認します。
 もし該当アクセスがない場合自動でデータベースファイルが作成されないので、手動でpostmap /etc/postfix/access_retryを実行。
(4)/etc/postfix/main.cf の smtpd_recipient_restrictions を変更。
(私の場合は)
smtpd_recipient_restrictions =
  permit_mynetworks,
  check_client_access btree:/etc/mail/dracd, …(pop-before-smtp認証)
  permit_sasl_authenticated, …(SASL認証)
  reject_non_fqdn_recipient,
  reject_unknown_recipient_domain,
  reject_unauth_destination,
  check_recipient_access hash:/etc/postfix/access, …(以前からのアクセス制限)
  check_client_access hash:/etc/postfix/access, …(追加)
  check_client_access hash:/etc/postfix/access_retry, …(追加)
  reject_unknown_client_hostname, …(追加)
  permit
としました。

 最初は smtpd_client_restrictions に置いていましたが、既に確定している他の制限をすべて適用してからの方が効率的なので最後のrestrictionsである smtpd_recipient_restrictions の方に変更。

 reject_unknown_client_hostname は ホストの逆引きとその正引き両方ができてしかも一致しない場合は拒否するというたいへんに強烈な制限で、450retry救済の手を設置しておかなくては到底こわくて使えない設定です。
 最初reject_unknown_reverse_client_hostname でやったところ、スパム発信原には逆引きはできるが正引きができないというでたらめな(あるいはうその)逆引き設定も意外と多く、reject_unknown_client_hostnameに変更。

 その他のsmtpd_xxxx_restrictionsにも450rejectを返すアクセス制限と組み合わせて置くことで同様に再試行での救済が可能ですが、smtpd_hello_restrictionsではやらないほうがいいと思います。ためしに reject_unknown_helo_hostname をセットしてみたらパソコンからメール送信ができなくなりました。この設定だとFQDN heloが要求されますが、パソコンにちゃんとしたFQDNを設定する人もいないと思うので。また、まともなサーバーでもちゃんとした外部参照のできるFQDN heloが設定されていない場合も多いようです。

使い方
動作は以下のようになります。
1.スクリプトはcronで定期的に実行され、指定されたメールログをチェックします。
2.メールログから、" 450 .... rejected:"を含む行を抽出、チェックします。
3.設定された回数と継続時間を越える再試行があった場合、
 /etc/postfix/access_retry に "IPアドレス  DUNNO" を設定します。
 postmap、postfix reload を行い、管理者に通知します。
 (この時点では実質まだOKやREJECTのアクションは行われません。)
4.DUNNOのままで放置してその後さらに許可設定された回数と継続時間を越える再試行があった場合、
 /etc/postfix/access_retry に "IPアドレス  OK" を設定し、アクセスを許可します。
 同様にpostmap、postfix reload を行い、管理者に通知します。

 管理者への通知は、ダイアログとメールで行われます。(各々ON、OFFが可能です。)

 ダイアログでは、Please confirm or edit it ! -> [OK]ボタン で即アクセスファイルを編集でき、変更された場合には自動的にpostmap、postfix reload が行われたいへん便利です。(常時デスクトップが起動されている必要はありますが。)

 あやしいメールを受ける前に受信OKあるいはREJECTを決定するとしたら、そのための情報は、拒絶ログから得られる "IPアドレス" "from=<...>" "to=<...>" "helo=<...>" の4つだけです。
 慣れるとIPアドレスのwhois情報やfrom, to, helo の内容などを見てほぼわかりますが、基本的にはDUNNOのまま放っておけばいいのです。
まれにしつこいのがすり抜けてきますが、もしスパムだったら参考に最近のスパムメールの内容など見て、それからおもむろにREJECTを設定してさしあげます。
 以下のようなのはほぼ間違いなくスパムなので、即座に DUNNO を REJECT に変えてしまってもかまわないかとも思われます。(私はそのままにしておきます。DUNNOのままlog rotateの2期間を過ぎればもう来ないということで躊躇なく消せるので。)
(1)受取人(to)のユーザー名の部分によく使われそうなsales,info,shopなどを使ってくる。
 (実際に使ってたらだめだけど。)
(2)差出人にこちらのメールアドレスをかたっている。
 fromとtoが両方ともこちらのメールアドレスになっている。
(3)宛先(to)に全く関係ないメールアドレスを設定している。
 不正中継を試したものと思われ、差出人(from)にこちらのメールアドレスが使われたりしていることもあります。
(4)heloにIPアドレスを使っている。(まともなメールサーバーならありえないと思うんだけど。)
 さらにひどいのはheloにこちらのメールサーバーのIPアドレスをかたっている。
 smtpd_helo_restrictions に reject_unknown_helo_hostname を仕掛けたくなりますが、やめておいたほうが賢明です。(パソコンにFQDNをセットしないと自分が送信できなくなります。)
(5)IPアドレスをwhoisで調べると海外なのにもかかわらず、fromは日本のyahoo様などの大手プロバイダーのメールアドレスになっている。
(6)メールアドレスのユーザ名部分がいかにもいやらしい、通常使用しないような名前。
 sokuhame, morodashi, yarihoudai など、とてもここには書けない。
 なぜか日本のスパムに多い。(外国語で書かれてもわからないだけか?)

 この方法の欠点は運用している限りアクセスリストの保守が必要です。
ほうっておくとリストがどんどん膨らんでいきますので、以下のようにすることにしました。

ログローテートでログから消え去ったアクセスについて:
1.正常な接続でOKとしたものは本来のaccessに移動する。
2.スパムでREJECTとしたもののうち、たちの悪いのも同様にaccessに移動する。
 (しばらく経ったら消去する。)
3.DUNNOのまま残っているものや残りのREJECTはさっさと消去。
 (スパムの大半は一時的で、残しておいても役にはたたない。)
 → 2011.6.11 自動で消去できるよう改良しました。
といったところです。

 自前メールサーバーをお使いの方でスパムメールで困っている方はこの方法を試してみてはいかがでしょうか。

ちょっと思ったことなど参考にメモ:
1.少しくらいスパムメールがきてもいいから安全をとりたいなら、reject_unknown_client_hostname より reject_unknown_reverse_client_hostname のほうがいいかと思います。
2.短時間に多くのスパムを送りつけてくる場合がまれにあり、このスクリプトでは対応できません。
 60分以上Retryが続いた場合許可するなどとした方がより完璧かなとは思いますが。
 ....そのうちやるね。 …2011.5.17 改良!規定回数と継続時間で制御可能に。GOOD!
3.SELinuxさんがからんでくるとちょっとめんどうです。
 どうも/etcという大事な場所をまさぐるので目を付けられるようです。
 私の場合、SELinux Management で、Boolean -> cron の各項目を許可、
 さらに拒否されたpostmapアクセスなどの許可モジュールを作ってインストールしました。
 (SELinuxってあんまりよくないな。)
4.いまのところ登録は一日に一件あるかないかくらいですので確認もさほど大変という感じではありませんが、もっと件数が増えたら確認や管理がしやすいようにさらに工夫する必要があるかな。
  …2011.6.11 だいぶ改良。新しいアクセス順に並び替え、確認項目表示、自動消去など。
5.同じアドレスからスパムと正常なメールの両方がこちらのサーバー宛に送られることは考慮していません。
 今のところそういうのはまだ無いようですが、その場合は受けるしかないかな。
 http://www.gabacho-net.jp/anti-spam/ の浅見さんに感謝です。スクリプトをありがたく使わせていただきました。(かなり改造したけど。)
おかげさまでスパム受信は激減です。排除率はおそらく99.9%は越えています。また幾通かのメールがちゃんと救済されました。

その後の状況(2011年7月7日)
 逆引きできないホストに450再試行要求をセットし、運用を開始して約2ヶ月経ちました。最初アクセスリストには十数件リストされていましたが、そのうちなぜかだんだんスパムが減り、今週ついにリストは空になりました。
 ここしばらくスパムメールは来ることは来ますが受信していません。
スパマーも送信効率を考えているのでしょうか。
だとすれば、スパムメールは受けて振り分けるよりサーバーで拒否するのが絶対正解のようです。

 ...いままでちょこちょこプログラム改良を続けていましたが、リストが空ではテストもできないので、これでよしとしましょう。