日曜日, 10月 29, 2006

大手ISPに導入されたらしいが…

 佐藤さんから聞いた話。IPアドレスの割り当て1個の接続サービスを利用している会社から某大手ISPにメールを送ろうとしたら、リトライアウトでエラーリターンしたとのこと。先月(9月)のことである。そこに示されたエラーメッセージは、「may not be mail exchanger」という、私が作ったものだった。応答コードは「450」だった。
 このメッセージ文で検索すると、困っている人の情報が得られると佐藤さんに言われて、検索してみた。そのISPへのメールのエラーリターンに「550」の応答コードが示されているのがさらされていた(日付はやはり9月だった)。これには驚いた。
 裏を取ろうと、ダイヤルアップ接続で手動のSMTPアクセスをかけてみた。RCPT TOコマンドに対する応答コードは「250」。拒否していない。私がダイヤルアップ接続に使っているISPのダイヤルアップ用IPアドレスの逆引き名はルール5(逆引きFQDNが5階層以上で、下位2階層の名前がともに数字で終わる)に引っかかるが、もしかしたらルール5を入れていないのかもしれない。私は8個ブロックのIPアドレスをもらっていて逆引き権限の委譲を受けているので、予備サーバのIPアドレスの逆引き名を「219-163-213-19.rev.reto.jp」とS25Rに思い切り引っかかるものに変えて、予備サーバからアクセスしてみた。「450」で蹴られた。「550」を返していたという裏は取れなかった。
 それにしても、正当なメールをリトライアウトさせてしまったとはどういうことだろう。通常のMTA(くだんの会社ではqmailを使っているとのこと)なら数日間リトライする。その間ずっと、ログを確認せずに放置していたのだろうか。
 私は、善良な送信者や受信者をハッピーにするためにS25R方式を発表したのである。善良なユーザーを困らせてはいけない。正当なメールを「450」で蹴ってしまうというリスクをちゃんとコントロールしてくれなければ困る。正当なメールを救済することには真剣勝負の覚悟で取り組んでほしい。リトライのログを確認しやすくするために、私は拒絶ログソーティングスクリプトを提供している。まめにログを確認することができないなら、Rgreyなどでリトライアクセスの救済を自動化することを考えてほしい。それさえしないなら、S25R方式は使わないでほしい。
 大手ISPでもS25R方式が導入されたとは光栄なことではあるが、正しく運用してくれているのだろうか。導入初期に失敗はあったけれども今はうまくやっていると信じたいが。
 そのISPはS25R方式の導入を公表していないので、私がここで社名を公表するのは差し控える。もっとも、私が作ったメッセージ文で検索すればわかってしまうけれども。

土曜日, 10月 21, 2006

無精者の勝利

 2001年3月、sendmailから、設定の楽なPostfixに乗り換えた。
 2001年8月、悪気のない未承諾広告メールを2度送ってきた業者に対して拒絶の意思を伝えようと考え、header_checksパラメータでFromヘッダをチェックしてエラーリターンさせるようにした(今にして思えば、smtpd_sender_restrictionsパラメータを使ってもよかったのだが)。これが私のスパム対策の始まりである。
 2001年10月、同じ文面でFromアドレスを変えたスパムが2通来た。body_checksパラメータで、スパマーが宣伝しようとするウェブサイトのURLを引っかけてエラーリターンさせることを思い付いた。
 その後1年あまり、この方法はうまくいっていた。着信するスパムがあまりに少なくなって、スパム防御策を研究しにくくなって面白くなくなった。そこで、2003年3月、見えないmailtoアンカーにおとりのアドレス(User unknownになる)を書いてホームページに仕掛けた。さっそく引っかかった奴が現れたので楽しかった。
 2003年5月、着信するスパムが急に増え始めた。次々に来るスパムに防御が追い付かなくなった。また、URLに十六進文字符号を混ぜたり、本文全体をBASE64符号化したりするスパムもあった。内容チェックによる防御策に見切りを付けた。
 内容チェックを高度化したベイジアンフィルタという技術があることは知らなかった(そのころすでに一般化していたのかどうか、今も知らない)。根が無精だから、世の中にどんなスパム対策技術があるのかをつぶさに調査することもしなかった。もっとも、もしベイジアンフィルタを知っていても、使いはしなかっただろう。受けてからフィルタリングする方法では、拒絶の意思をスパマーに思い知らせることができない。拒否応答を返さなければ気がすまない。悪人に対してはサディスティックなのである。
 多くのスパムに共通することは何かと観察して、送信元のIPアドレスに着目した。ほとんどのスパムはエンドユーザー回線から直接送信されており、その多くは逆引きできないことがわかった。smtpd_client_restrictionsパラメータを使うことを覚え、「reject_unknown_client」を指定したら効果てきめんだった。また、逆引きできるエンドユーザー回線には逆引き名にIPアドレスを反映したものがかなりあることに気付いた。そこで、ハイフンかドットで区切られた4個の数字列が逆引き名に含まれていたら蹴るように正規表現を書いた。リトライする正当なメールサーバを救済する方法もマスターした。S25R方式の開発はここから始まった。個人サーバだから、思い切った試行錯誤ができた。
 根が無精だから、楽をするためには労苦を惜しまない。たくさんの不正メールアクセスを観察しながら、なるべく多くのエンドユーザー回線を引っかけることができて(つまり、ブラックリスト作成の手間が少ない)、メールサーバを引っかけることがなるべく少ない(つまり、ホワイトリスト作成の手間が少ない)正規表現を作り上げた。この方式でよいと判断したのは、10ヶ月後の2004年3月だった。スパムだけでなくウィルスメールもほとんど阻止できる方式ができ上がった。
 スパマーの立場に立って、S25R方式を破る方法も考えた。少量のスパムなら、ISPのメールサーバを経由するなどして送り込むことができるが、S25R方式の防御を破って大量のスパムを届かせることは、スパム送信コンピュータのリソース負荷が大きくなってきわめて難しいと結論付けた。簡単に破れる方式でも、大量スパムの90%以上を阻止し続けることができれば、それは勝利である。
 私のような無精者が考え付くことはすでに世界の誰かが作っているのではないかと思ったが、不思議なことに、あちこち情報を検索しても見つからなかった。
 もし私がベイジアンフィルタの発明者だったら…。もし私がもっと頭が良くて勤勉で、高度な数学を駆使することができて、内容チェックを高度化する道を突き進んでいたら…。宣伝文を画像化するというあまりにも簡単な方法で破られることに気付かされた時、「ああ、私の今までの努力は何だったのか」と嘆き悲しみ、絶望のあまりに憤死していたに違いない。
 無精者だからできる発明もある。

火曜日, 10月 17, 2006

パラノイド検査

 S25R方式を導入された方から、「送信元ホストが逆引きできるのにPostfixで『unknown』になることがあるのはなぜ?」という質問を受けた。
 私はすぐにパラノイド検査の結果を疑った。案の定、逆引き名を順引きしたらIPアドレスが検索されなかった。
 Postfixは、逆引き名を順引きした結果が元のIPアドレスに一致するかどうかまで見る。これをパラノイド(猜疑的)検査という。逆引き名を偽造することは簡単にできるので、パラノイド検査をパスしないと逆引き名を信用しないようになっているのである。パラノイド検査をパスしなかった場合は、逆引きできなかった場合と同じく「unknown」として扱われる。sendmailもやはりパラノイド検査を行っており、逆引きできたら逆引き名はReceivedヘッダに記録するが、パラノイド検査をパスしなかったら「(may be forged)」(偽造かもしれない)と付記する。
 以前、BBSで、「スパム対策のためにはパラノイド検査は不要だ」という意見を書かれた方がいる。ISPで逆引きが管理されている場合はユーザーが逆引き名を偽造することはできないし、スパマーが逆引き権限を持って逆引き名を偽造してスパムを送信した場合はIPアドレスに基づいてブロックすればよいからだという。パラノイド検査をやめた方が、世界のDNSサーバにかかる負荷を減らすことができる。確かにもっともだとは思うが、それを言ったところで、MTAのユーザーである我々としては、MTAの仕様を受け入れるしかない。
 それに、もしPostfixにパラノイド検査をやめるオプションが設けられたとしても、私はそれを使わないだろう。もしかしたら、悪者が逆引き権限を持って逆引き名をたとえば「mail.microsoft.com」と偽造し、マイクロソフトからの案内であるかのように偽ってウィルスをばらまくかもしれない。Receivedヘッダに逆引き名がそのまま記載されたら、受信者には、本当にマイクロソフトから送信されたメールであるかのように見えてしまう。このやり方は詐欺メールにも使える。「unknown」と記載されるか、「(may be forged)」と付記された方が、受信者がだまされないためには安全である。
 DNSサーバの負荷の問題は、さほど心配する必要はないと思う。負荷が問題になったらDNSサーバを増強すればよい。最も負荷がかかると思われるルートサーバの数も増えている。ルートサーバの名前はa.root-servers.netからm.root-servers.netまでの13個であり、これはUDPパケットの長さの制限のために増やせないのであるが、実はルートサーバの台数はもっと多い。anycast(相手任意の通信)という通信技術によって、同じ名前、同じIPアドレスのサーバを数台ずつ世界に分散配置することが可能になっているのである。

火曜日, 10月 10, 2006

SQLgrey

 佐藤さんのブログ記事で、SQLgreyというものがあることを知った。postgreyから派生したグレイリスティングサーバで、動的IPアドレスっぽいFQDNパターンと、メールサーバっぽいFQDNパターンを検査する正規表現が用意されていて、動的IPアドレスっぽいパターンにマッチしてメールサーバっぽいパターンにマッチしなければグレイリスティングをかけるという方式だそうである。コンセプトは佐藤さんのRgreyと同じである。

動的IPアドレスっぽいパターン:
(^|[0-9.x_-])(abo|br(e|oa)dband|cabel|(hk)?cablep?|catv|cbl|cidr|d?client2?|cust(omer)?s?|dhcp|dial?(in|up)?|d[iu]p|[asx]?dsld?|dyn(a(dsl|mic)?)?|home|in-addr|modem(cable)?|(di)?pool|ppp|ptr|rev|static|user|YahooBB[0-9]{12}|c:alnum:?{6,}(\.[a-z]{3})?\.virtua|[1-9]Cust[0-9]+|AC[A-Z][0-9A-F]{5}\.ipt|pcp[0-9]{6,}pcs|S0106:alnum:?{12,}\.[a-z]{2})[0-9.x_-]

メールサーバっぽいパターン:
^(.+[._-])*(apache|bounce|bulk|delay|d?ns|external|extranet|filter|firewall|forward|gateway|gw|m?liste?s?|(bulk|dead|mass|send|[eqw])?mail(er)?|e?mail(agent|host|hub|scan(ner)?)|messagerie|mta|v?mx|out(bound)?|pop|postfix|w?proxy|rela(is|y)|serveu?r|smarthost|v?smtp|web|www)(gate|mail|mx|pool|out|server)?[0-9]*[._-]

すげえな…
 S25Rの一般規則を一つの正規表現にまとめたものと比較してみようか。

^(unknown|[^.]*[0-9][^0-9.]+[0-9]|[^.]*[0-9]{5}|([^\.]+\.)?[0-9][^.]*\.[^.]+\..+\.[a-z]|[^.]*[0-9]\.[^.]*[0-9]-[0-9]|[^.]*[0-9]\.[^.]*[0-9]\.[^.]+\..+\.|(dhcp|dialup|ppp|adsl)[^.]*[0-9])

こっちの方がずっと短い。
 ついでに、9月23日の記事「Becky!でのフィルタリング」で紹介した簡易一般規則をPostfix向けに手直しすると…

^(unknown|[0-9]|[^.]*[0-9][0-9][0-9][0-9][0-9]|[^.]*[0-9]+(([a-z]|-)+|\.)[0-9])

もちろん、さらにシンプルである。これは、Postfixではさらに短く

^(unknown|[0-9]|[^.]*([0-9]{5}|[0-9]([^0-9.]+|\.)[0-9]))

とも書ける(Becky!では通用しないが)。
 で、2006年7月に私のサイトへ不正メールを送り込もうとしたホスト4423個をどれだけ引っかけることができるかを比較してみた。その際、SQLgreyでの動的IPアドレスっぽいパターンの正規表現は、egrepコマンドにかかるようにするため、および「unknown」も引っかけるために、以下のように書き換えた。「:alnum:?」という書き方は謎だったが、不正メール送信の常連さんのFQDNからよきに推察して「[0-9a-f]」と書き換えた。

(unknown|(^|[0-9.x_-])(abo|br(e|oa)dband|cabel|(hk)?cablep?|catv|cbl|cidr|d?client2?|cust(omer)?s?|dhcp|dial?(in|up)?|d[iu]p|[asx]?dsld?|dyn(a(dsl|mic)?)?|home|in-addr|modem(cable)?|(di)?pool|ppp|ptr|rev|static|user|YahooBB[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|c[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]+(\.[a-z][a-z][a-z])?\.virtua|[1-9]Cust[0-9]+|AC[A-Z][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]\.ipt|pcp[0-9][0-9][0-9][0-9][0-9][0-9]+pcs|S0106[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]+\.[a-z][a-z])[0-9.x_-])

 その結果…

SQLgrey:3781個(85.5%)
簡易一般規則:4331個(97.9%)
S25R一般規則:4344個(98.2%)

なんてこったい。SQLgreyは、ものすごい正規表現の割に、S25Rの一般規則に比べて8倍もの不正メール送信元ホストを見逃しているではないか。しかも、catv.ne.jpやadsl.ne.jpやhome.ne.jp(いずれも実在する)をドメインごと引っかけてしまう。こんなものを使うよりも、S25Rのルールを取り入れたRgreyを選ぶべきである。
 自慢じゃないけど(自慢だけど)、私が作ったルールの方がはるかに簡潔でしかも効果的である。

日曜日, 10月 08, 2006

S25Rが敗北する時は来るか?

 スパマーがS25R方式の防御を突破する方法はいくつかある。
 第一に、ISPのメールサーバを経由することである。防御側では、ISPのサーバをブラックリスト登録するわけにはいかない。しかし、スパムの量は抑えられる。サーバのパフォーマンスがボトルネックになるからである。それに、スパマーがサーバを過負荷にしたら、ISPも黙ってはいないだろう。
 第二に、逆引きできてサーバっぽい逆引き名を持つサーバを侵害してそこからスパムをばらまくことである。私のサイトに着信するスパムには、この方法で送信されたと思われるものが多い。日本の企業や大学のサーバが乗っ取られてそこから来たスパムもあった。この場合も、おいそれとブラックリスト登録はできない。しかし、やはりスパムの量は抑えられる。乗っ取ることができるサーバは、ゾンビ化できるエンドユーザーPCに比べて非常に少ないからである。それに、乗っ取られたサーバの管理者はすぐに守りを固めるだろうから、同じサーバを長く利用し続けることはできない。
 第三に、ドメインを取得してサーバっぽい逆引き名を使うことである。しかし、コストがかかるので、この方法をとれるスパマーは少ないだろう。しかも、そのホストからスパムばかりが来ることがわかれば、ブラックリスト登録によって防御できる。
 第四に、まともなMTAを使うか、あるいはゾンビPCにまともなMTAと同じ動作をさせることである。つまり、「450」の拒否応答に対して何時間もリトライを続け、tarpitting(応答遅延)に対しても5分間辛抱強く待つ。スパム送信コンピュータにかかるリソース負荷が大きくなるが、技術的に不可能ではない(今の大半のスパマーがそうしていないのは、そうしなくてもスパムの送達に成功することが多いからである)。もし多くのスパム送信がそういうものになったら、S25R方式の運用は困難を極めることになるだろう。アクセス元が正当なメールサーバかスパム送信コンピュータかの区別ができなくなるからである。
 しかし、そうなってもまだS25R方式は負けてはいない。受けてからフィルタリングする方法が残っている。SpamAssasinのようなフィルタリングプログラムで、送信元の逆引き名を検査し、S25Rの拒否条件に引っかかるものに「スパムの疑いあり」のマークを付けて配信すればよい。そうすれば、受信者は容易にスパムをごみ箱行きにできる(間違ってごみ箱行きになった正当なメールはごみ箱から回収すればよい)。
 結局のところ、S25R方式は半永久的にスパムに敗北しないと私は考える。
 もっとも、当分は、S25R方式で拒否応答を返す方法が無力化する心配はない。大多数のサイトがスパムに対して無防備な状況では、スパマーは、防御の固い少数のサイトを攻撃するためにわざわざスパム送信コンピュータに大きなリソース負荷をかけたりはしないだろう。逆説的な言い方だが、S25R方式が世界中でこぞって採用される時が来るまでは、S25R方式は安泰である。

日曜日, 10月 01, 2006

1時間近くリトライするスパム

 次のようなスパムアクセスを見つけた。

Sep 29 05:13:36 unknown [74.130.145.173]
Sep 29 05:18:43 unknown [74.130.145.173]
Sep 29 05:23:50 unknown [74.130.145.173]
Sep 29 05:57:26 unknown [74.130.145.173]
Sep 29 06:03:12 unknown [74.130.145.173]

 5分余りの間隔で3回トライし、その後33分余りたってから、また5分余りの間隔で2回トライしている。8月28日の記事「リトライするスパムをRgreyで蹴る」で、最初のアクセスからアクセスを受け入れるまでの遅延時間を25分にすれば、リトライするスパムをほとんど阻止できると書いた。しかし、そのようにしても上記のアクセスはすり抜けてしまう。かといって、遅延時間をあまり長く設定するわけにもいかないだろう。
 考えてみると、スパマーにとって、スパム送信コンピュータにあまりリソース負荷をかけずにRgreyを突破するのは、さほど困難ではないと思われる。「450」の拒否応答が返された宛先をアドレスリスト上でマークしておき、30分~1時間後に、送信者アドレスを変えずに再送信すればよい。
 そのような手口にどう対抗するかというと、佐藤さんのStarpit(S25R+tarpitting)が有効だろう。たくさんの宛先サーバからtarpitting(応答遅延)を食らうと、プロセスが増加しすぎてリソース負荷に耐えきれなくなるので、送信を早々にあきらめてしまうと考えられるからである。
 ところが、それでも安心してはいられない。佐藤さんのブログ記事によると、STRATIONウィルスは65秒のtarpittingを抜けるそうである。このことから考えると、スパマーは、たくさんのゾンビPCを操ることによって、リソース負荷の問題も克服してしまうかもしれない。
 RgreyもStarpitもすり抜けるスパムが増えたらどうするか。そうなったら、通過したメールをSpamAssasinのようなフィルタリングプログラムにかけて、送信元の逆引き結果を再度検査し、S25Rの拒否条件に引っかかるものに「スパムの疑いあり」とマーキングして配信するのがよいと思う。正当なメールがマーキングされることはあっても、取りこぼす心配はない。
 もっとも、上記のようなアクセスは今のところレアケースである。当分は、S25R方式やそれを応用した方式によって90%以上のスパムを排除し続けることができるだろう。それというのも、まだ大半のサイトがスパムに無防備だからである。だからスパマーは、軽いリソース負荷で、いい気になってスパムを大量配信することができるのである。強力な防御策が多くのサイトに普及した時には、スパマーは、さらにそれを破る手を打ってくるだろう。