milter-greylist で SPF を使う

milter-greylist には他の spam 判定要素を組み合わせて、最終的に拒否するのか、許可するのか、Greylisting するのか、という判断をする。例えば、

  • GeoIP を使って、送信元の国によって判断。
  • SpamAssasinの結果を参考にして判断。
  • DNSBL の結果を参考にして判断。
  • SPF の結果を参考にして判断。

といったことが可能(ただし、コンパイル時に有効になっている必要あり)。

で、milter-greylist での SPF の使い方でおもしろい方法がある。

SPF のメリットとデメリット

SPF は、エンベロープの差出人アドレスのドメイン部を使って、DNS の TXT レコードを取得し、そこに記述されている「うちのドメインの付いたメールは、ここから送信するよ」という情報を元に、正規のメールかどうかの判断材料とするもの。送信する側とすると、送ったメールを spam 扱いされないようにするために DNSSPF の情報を用意しておく、といった具合になる。

弱点は、メールが alias や .forward などで、自動転送されるような場合、SPF の結果は「pass」にならない。メーリングリストの場合は、メーリングリストのソフト次第だが、同様の問題が生じる可能性はある。こればっかりは、SPF の性質上、転送するメールサーバ自体がエンベロープの差出人アドレスを書き換えるような仕組みになっていない限り、False Positive を避けることはできない*1

また、False Negative となるケースもある。一見、SPF の結果が「pass」になれば、whitelist 扱いに出来そうな気がするが、spammer が下記のような SPF 情報を記述する場合がある。

v=spf1 +all

こうなると、どんな IP アドレスから届いても、SPF の結果は「pass」になる。本来は「pass」となっていたら、積極的に許可したいのに、無条件に SPF で許可してしまうと spammer の思う壺になってしまう。

milter-greylist + SPF の隠し技*2

普通に、SPF の結果を使った ACL を書くと、下記のようになる。

racl whitelist spf pass

こう書けば、SPF が pass のものは(この行より前にある ACL に引っかからなければ)無条件で受信する。しかし、これでは前述の「どこからでも pass」も通ってしまう。この「どこからでも pass」というケースを検出するための仕組みが、milter-greylist にひっそりと入っている。

greylist.conf の man には、下記のように書かれている。

spf

This is used to test SPF status. Possible values are pass, softfail, fail, unknown, error, none, and self. The first six values are plain SPF validation status. The self value is a special test that checks the server's local IP address against the sender's SPF record. If that test validates, odds are good that the sender SPF record is wide open, and this is hint that SPF should not be trusted.

「self」という独自の値があり、これが指定されると、サーバ自身の IP アドレスを使って SPF レコードをチェックする。もし、その結果が pass だったとすれば、その SPF レコードは「wide open」、つまり「どこからでも pass」という可能性が高いので、その場合の SPF の結果は信用できない、ということになる。

はっきり言って、まっとうな送信元で SPF レコードが「どこからでも pass」になっているのは皆無と考えて良い*3。なので、思い切って、

racl blacklist spf self msg "Your SPF record is wide open."

としても良いだろう。

SPF を使ってホワイトリスト

spf self」を使ってあらかじめ拒否しておけば、「どこからでも pass」で False Nagative となるケースを回避できる。とはいえ、それでも SPF が pass を無条件でホワイトリストにしてしまうのは気が引ける。実際にあったケースとして、spam 発信者がホスティングサービスと契約していて、取得しているドメインSPF レコードに、そのホスティングサービスの SPF レコードを取り込む*4ことで、SPF が pass になるようにしているケースがあった。

もちろん、ホスティングサービスを使っているのだから、ちゃんと再送もする。見かけ上は健全なメールと区別出来ないが、大抵はホスティングサービス側の契約で「spam を送るために使わないこと」みたいなことになっているので、送信元の IP から利用しているホスティングサービスを見つけ出し、その業者に「あんたのとこから、こんなメールが送信されてるよ」と報告すると、業者が対処してくれる場合が多い。

とはいえ、spam 送信者もそんなことは百も承知で、また別のホスティングサービスに乗り換えるだけだとは思うが、それでも、ある期間、大量にメールを送信出来れば OK、と割り切っているのだろう。

とまぁ、こういった spam は SpamAssasin などを使ってメールの中身を評価するしかないので、この際、あきらめることにする(^^;

ただ、S25R による False Positive を避けるために積極的に使う方法もある。

S25R に引っかかりやすいものとして、小規模な ISP の配下やホスティングサービスの他に、大規模なメールサービス、ISP もひっかかりやすい。例えば、携帯電話からのメールや、gmail や Yahoo メールといった場合が S25R に引っかかる。しかも gmail に至っては、SPF に記述されている IP アドレスの範囲がものすごく大きく、再送してくる時の IP アドレスが大きく違ってくる可能性はある*5

こういった「有名どころ」からのメールを SPF で評価してホワイトリストにしてやると、Greylisting による遅延を回避できる。

list "Whitelist with SPF" from { \
    /[.@]docomo\.ne\.jp[> ]*$/ \
    /[.@]ezweb\.ne\.jp[> ]*$/ \
    /[.@]softbank\.ne\.jp[> ]*$/ \
}

racl whitelist list "Whitelist with SPF" spf pass

上記のように書けば、SPF が pass の時にホワイトリストにしたいものを、「list "Whitelist with SPF"」の中に追加すれば良い*6

条件付きホワイトリスト

ホワイトリストというと、送信元の IP アドレスや、送信元メールアドレスのドメイン部だけで判断して通す、というイメージがあるが、

  • IP アドレスだと、相手が引っ越しや ISP の変更、回線種別の変更で IP アドレスが変わった時にホワイトリストから漏れる。
  • 送信元メールアドレスを元にすると、そもそも、送信元メールアドレスは詐称しやすいので、spammer がたまたま、そのメールアドレスを送信元メールアドレスに使うと False Negative になる。

という問題がある。

前述の SPF との組み合わせでれば、上記の問題は解消される。IP アドレスが変わっても SPF が正しければ OK だし、spammer が送信元メールアドレスに使ってもホワイトリストとはならない。

ただ、SPF レコードを設定しているところは多くない。有名どころでは記述しているケースが多いが、中小企業などは記述している方が珍しい。

SPF レコードが無いけどホワイトリストに入れたい時の方法として、「DNSBL に引っかからなければ OK」という方法もある。

ということで、次回は DNSBL との組み合わせを書くことしようっと(^^;

*1:SPF と似た仕組みに Sender ID があるが、こちらはヘッダ情報を参照するので、転送時にヘッダを追加するようになっていると回避できる。ただ、メールヘッダを参照する、ということは、SMTP の RCPT TO の段階では判定できない、ということになる

*2:ただし、Postfix との組み合わせでは、Postfix が {if_addr} マクロを milter 側へ渡さないので利用出来ない。--enable-postfix を付けてビルドすると、明確に「spf self clause is broken on Postfix」と怒られる。milter-manager 経由にすると回避出来るかな?

*3:まぁ、設定した人間が間違って「+all」と書いてしまった、という可能性もないわけではないが...

*4:具体的には、「include:example.jp」と書けば、example.jp の SPF レコードを取り込むこになる

*5:まぁ、見ていると 24 bit 程度のネットマスクで評価(subnetmatch /24 と設定)しておいて、再送メールが永遠に Greylisting されるような事はなさそうではある。

*6:ただ、メールアドレスを正規表現で引っかける場合、大文字小文字を区別してしまうので、本当は「/[.@][Dd][Oo][Cc][Oo][Mm][Oo]\.[Nn][Ee]\.[Jj][Pp][> ]*$/」と書く必要がある。もし、「docomo.ne.jp」だけ書くと、部分文字列による比較なので、xyz@docome.ne.jp.example.com とか docomo.ne.jp@example.com も引っかかってしまう。部分文字列による比較の時は、大文字小文字を区別しない。