メールアドレスの謎....
2007.08.31
配置が換わるなどして、数ヶ月ほどブログを書けないでいましたが、復活することにします。
さて、今回のお話はメールアドレスについてです。 Web アプリを作っていると、ユーザが手入力するメールアドレスが、正当なものかどうか...をチェックすることが頻繁にあります。では、「メールアドレスが正当である条件」は一体何で、どこで決まっているのでしょうか???
とりあえずここでは、
というケースでの、ドメイン名部分(somedomain.co.jp)の方は、「有効なドメイン名」ということだけにしておきましょう。こっちは要するに、DNSからMXレコードを引いて、Mail Exchanger のIPアドレスが取れる、という条件になるのは言うまでもないことです。しかし、someone の方、こっちは「ローカルパート」という用語になっていますが、こっちはですね、これ非常に意外な結果なのです。仕事に密接に関わる話で、しかも正確な情報があまりないようですので、面白いのでは?とも思いますよ。
SMTPトランザクションを規定したRFC2821によると(よく実装されているRFC822ベースのチェックは古いです...)、
システムは、SMTP において非 ASCII 文字(最上位ビットが1にセットされたオクテット)または ASCII "制御文字(control characters)" (10進数で 0-31 と 127)を必要とするようなメールボックスを定義してはならない(MUST NOT)。(4.1.2)
というのが、唯一の明示的な字種制限です。ということは、
のようなメールアドレス(メールボックス=ローカルパート)だって、実はSMTPの上では合法なアドレスなのです!
この背景には、次のような「哲学」があるようです。
アドレスは通常、ユーザーとドメインの指定から成る。標準的なメールボックスの命名規則は、"local-part@domain" と定義されている: 最新の使用法は、単純な "ユーザー名" よりさらに広範囲な応用を許可している。その結果、および中間ホストがそれらを修正することで転送を最適化しようとする場合の問題の長い歴史の結果、loca-part の意味の解釈および割り当ては、そのアドレスのドメイン部で指定されているホストによってのみ行われなければならない。(2.3.10)
ですから、ローカルパートについては、「それをどう解釈しようと、最終的にローカル配信を行うメールサーバの勝手である」というのが、前提なのですね。
実際、よくあるメールアカウント作成制限として、
英小文字と数値がOKだが、数値は最初に来てはダメ。
というのは、典型的な UNIX アカウントの作成制限です。ローカル配信をする際に、UNIXアカウントとして許容されるメールアカウントでないと、ローカル配信ができない...という制限の元に、こういう作成制限がついている、という結果なのですね。
ということは、逆に言えば、「ローカル配信をしないメールサーバ」であれば、ここらへんの実験ができるわけです。そういう例として、Pure Java で書かれたメールサーバである、James で実験してみるのがいいでしょう。James は Java アプリなので、システムコールのお世話にならざるを得ないローカル配信はまったくできないので、完全に「仮想ドメイン」で動きます。ですから、今の問題については、「ホントのユーザアカウントとして使えるメールアカウントでないと、実装上だめ」という状況を考慮する必要がないわけです。
James の SMTPサーバで、RCPT TO の宛先として書ける文字を調べてみましょう。そうすると、過激なことに、
" [ ] @ ( ) ; : , < >
以外は通ります。
とはいえ、ここでは \ をエスケープ文字として使えてしまいます(RFC2822 4.1.3に \ でクォートする説明がある...)。ですから、
RCPT TO: <\<test\@test\>@somedomain.jp>
RCPT TO: <"test@test"@somedomain.jp>
のような奇怪であっても、SMTP 的には合法な宛先指定は通ってしまうのですね!
まあ、実際に James で仮想ユーザが作れるか...というとそれは別です。デフォルトでは James はディスク上にアカウント名に対応したディレクトリを作成して、そこに受け取ったメールを保存します。ですから、「使っているOSで許容されるディレクトリ名」でないと、アカウントが作れない...という制限があることになります。しかし、これは完全な制限ではなく、DBの上にアカウントを作って管理すれば、ここらへん問題はありません....実質無制限なアカウント名が使えるようになっちゃうわけです!
実験してみたところ、危険な文字をエスケープして渡したところ、エスケープされたかたちで作成したアカウント(たとえば test\@test)には、きっちりメールが届いていました....まあ、中間のMTAが正しく動くかどうかは分かりませんし、MUAは「異常なメールアドレスだ!」となる可能性も高いのですが、test\@testt@mydomain.jp なんていうメールアドレスが「ありえない!!」と断言することまではできないわけです。
ですから、「ユーザが入力したメールアドレスが正当かどうか」をチェックするのは、実質的には、
1. 後ろから見て「@」を探して、その位置で分解し、
2. 前と後とが空でない。
3. ASCII で 0x20 ~ 0x7e に収まる。
のチェック程度しか、しようがないわけです。
(ドメインが正しいかどうか、は Ajax 経由で DNS から MX レコードを引いてチェックする....という技がありえますね! これのJavaでのやりかたをそのうち....)
投稿者 : 杉浦 こずえ | 投稿日時 : 2007.08.31 12:23





