Category Archives: Perl

メールのドメイン指定送信

メールの誤送信を防止するには下記のような手段が考えられる。

  1. サーバ側で対応する。
    Postfixのsmtpd_client_restrictionsなど。
  2. クライアント側で対応する。
    Thunderbirdのcheck and sendなど。
    https://addons.mozilla.org/ja/thunderbird/addon/check-and-send/
  3. サーバ-クライアント間で対応する。
    SMTPのProxyを使ってチェックする、AntiVirusっぽくクライアントのOSレイヤーで通信をチェックする、DeepInspection的にパケットの転送経路で通信をチェックする。などなど。

なんとなく、3.の一番目「SMTPのProxyを使って対応する」が可能かコードを書いてみた。結果はページの最後に。PerlのCPANは非常に便利で簡単に書ける。(ただし、テストはあまりしていないので信頼性などは微妙。ここはproof-of-conceptの場所なのでその辺りはつっこまないでください。)
なお、下記のコードは悪意のある人がいる状況下で一定の人にしかメールを送らせないための対応としては使ってはいけない
なぜなら、RFCで許されるメールアドレスのチェックは難しく、一定文字列が含まれる場合は許可というルールは危険すぎるからである。
http://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9
メールアドレスチェックが難しい理由としては、メールの不正中継をテストするテストパターンも参考になる。(%による転送経路指定とか。)
http://www.atmarkit.co.jp/fsecurity/rensai/securitytips/005checkmail.html

以下、Perlのコード。

use Carp;
use Net::SMTP::Server;
use Net::SMTP::Server::Client;
use Net::SMTP::Server::Relay;
use Data::Dumper;
my $SMTP_SERVER = "smtp_server";
my $SMTP_PORT = "587";
#メールあて先チェック用
sub is_ok_to{
  my $ref_to_ary = shift;
  foreach my $to (@$ref_to_ary) {
    #あて先チェックをここに書く。
    if($to !~ /[email protected]/){
      return 0;
    }
  }
  return 1;
}
# 以下本体処理部分
#CPANより。
#http://search.cpan.org/~macgyver/SMTP-Server-1.1/Server.pm
$server = new Net::SMTP::Server('localhost', 25) ||
  croak("Unable to handle client connection: $!n");
while($conn = $server->accept()) {
  my $client = new Net::SMTP::Server::Client($conn) ||
    croak("Unable to handle client connection: $!n");
  $client->process || next;
  #ここまでCPANのサンプルコード(コメントは削除)
  if(is_ok_to($client->{TO})){
    &send_mail($client->{FROM},$client->{TO},$client->{MSG});
  }else{
    print "bad mail  [" . Dumper($client). "]";
  }
}
#問題の無いメールを送る
sub send_mail{
  my $from = shift;
  my $ref_to_ary = shift;
  my $msg = shift;
  $smtp = Net::SMTP->new($SMTP_SERVER, Port=>$SMTP_PORT );
  $smtp->mail($from);
  foreach my $to (@$ref_to_ary) {
    $smtp->to($to);
  }
  $smtp->data($msg);
  $smtp->quit() || croak "send_mail() failed [" . Dumper($from, $ref_to_ary, $msg). "]";
  return;
}