PR

 プログラマは自分でコードでも書きたくなるものである。だが,自分で書いたコードが,いついかなるときでも想定した動作をすると考えるのは危険である。独自実装には,予期せぬバグやセキュリティ上の問題が付きまとう。

 独自に実装する場合は,単なる勉強のためであったり,既にオープンソースとして提供されているプログラムよりも際立って速い,既存のプログラムが無い場合に限るべきであって,何でもかんでも独自実装をしてはいけない。

 独自に実装する前に,まずは既に実装があるかどうかを調べよう。既に実装がある場合は,その実装が期待に沿うだけのクオリティを保っているかどうかを確認した上で,採用するかどうかを決めるとよい。

メール・アドレスのバリデーションの例

 メール・アドレスのバリデーションを例に,どんな問題が起こり得るかを見てみよう。真ん中にアットマークが入ればよいからと言う理由で,

$mail =~ /[^@]+@[^@]+/;

などと書いてしまう方も多いのではないだろうか。このような記述が書かれている記事をオンライン上で見かけることがあるが,これはダメ。文字列の間にアットマークが含まれていれば,メール・アドレス以外の文字列にも一致してしまうからだ。例えば,

invalid@example?com

という文字列を正しいメール・アドレスと認識してしまう。

 このようなうかつな正規表現は,SQLインジェクションというデータベースを不正に操作するデータを埋め込む攻撃にもつながってくる。HTMLフォームから送信された値は,できる限り妥当かどうか正確に判断し,問題となるデータはサニタイズ(不正な文字を無効化すること)しておかなければならない。そうした危険を防ぐコードを自分で記述したければ,メール・アドレスがどのような形式なのかを正しく理解する必要がある。

 メール・アドレスの形式は,RFCという文書に定められている。具体的にはRFC2822にある。文書として相当な量である。これは正直,必要に迫られなければ読む気になれない仕様だろう。

 Perl正規表現雑技というサイトで,正規表現でメール・アドレスを表現するものが書かれている例もある。この例を見ると,RFCを満たす正規表現がすさまじい記述になっていることが分かる。

RFPに違反した形式もある

 オブジェクト指向にかかわる格言の一つに「車輪の再発明はするな」という言葉がある。再発明が有用なシーンもないわけではないが,多くの場合は格言の通りである。実装する前に,既に実装がオープンソースになっていないか探せばよいのだ。

 PerlならばEmail::Validと言うモジュールがある。このモジュールはRFC 822というRFC 2821, 2822の前身となる仕様に準拠したモジュールである。まず多くの場合で期待した結果になるだろう。

 ただし,メール・アドレスの判定はこうしたライブラリで万事問題無いかと思ったら,大間違い。実は,大きな落とし穴がある。日本の携帯電話で使用できるメール・アドレスは,実はRFCに違反した形式を取ることができる。それは次のような形式だ。

example.@docomo.ne.jp

 このアドレスをEmail::Validでバリデート(検証)すると不正な値になってしまう。こうしたイレギュラーな場合を考慮したモジュールもある。Email::Valid::Looseモジュールを使うと,そのようなRFC違反のメール・アドレスでも妥当であるとしてくれるのだ。

 以上,ちょっとしたメール・アドレスの妥当性検証だけでも様々なケースが存在し,実運用上やむを得ない現実(この例では,RFCに違反している携帯電話用のメール・アドレス)もあることが分かる。これらのすべてを自前の実装で行うには,

  • 正しくRFCを理解しておくこと
  • 現実的にRFCに準拠していないメール・アドレスが存在していて,どのような点で違反しているかを知っていること

といった事前知識を持った上で実装を行うことになる。到底実際の開発現場でやれることとは限らない。既に実装があるなら,それが十分検証されていることを確認して利用した方が早いし,確実だ。


山口徹
サイボウズ・ラボ
 サイボウズ・ラボ株式会社のプログラマ。バーテンダーからIT業界に転身後,様々なWeb制作を行い,大規模コミュニティ・サイトの開発・運用を経て,現在は研究開発の日々。Perl使い。Perlを中心とした開発のノウハウやネタをShibuya Perl Mongersのイベントで発表するなど講演活動も行う。個人の開発日記は「Yet Another Hackadelic」。仕事のブログは「log4ZIGOROu」。
■変更履歴
筆者の肩書きで,社名がライボウズ・ラボとなっていましたが,サイボウズ・ラボです。お詫びして訂正します。修正済みです。 [2008/04/07 15:10]