メール送信のセキュリティ

PHP Security, Security 12月 25, 2013 #メール
(Last Updated On: 2018年8月8日)

昨日はHTTPヘッダーのセキュリティについて解説しました。SMTPはHTTPと似た構造を持つため、メールを送信する場合も似たようなヘッダーインジェクション問題が発生します。

Mailヘッダーインジェクションとは?

SMTPもHTTPと同様に「”ヘッダー名”+”:”+値」の形式を持ったヘッダーを持っています。HTTPと同様に改行が二回連続で現れるとボディになります。SMTPプロトコルの解説ではないので、できるだけ簡易にMailヘッダーインジェクションを解説します。MailヘッダーインジェクションはHTTPヘッダーインジェクションと全く同じように行われます。

To: $address

Hello this is test mail

Toヘッダーはメールの送信先ヘッダーです。$addressに任意の文字列が設定でき

yohgaki@ohgaki.net
Bcc: spam@example.com

This is your order info
http://example.com/evil_page.html

(改行部分は\r\nとして読んで下さい)

のような文字列が設定されると

To:yohgaki@ohgaki.net
Bcc: spam@example.com

This is your order info
http://example.com/evil_page.html

Hello this is test mail

となり、Bccヘッダーと送信先が設定されるため、意図しないアドレスに意図しないメッセージが送信されてしまいます。

 

PHPのメール送信関数

以下がPHPのメール送信関数です。

bool mail ( string $to , string $subject , string $message [, string $additional_headers [,string $additional_parameters ]] )

bool mb_send_mail ( string $to , string $subject , string $message [, string$additional_headers = NULL [, string $additional_parameter = NULL ]] )

bool imap_mail ( string $to , string $subject , string $message [, string $additional_headers =NULL [, string $cc = NULL [, string $bcc = NULL [, string $rpath = NULL ]]]] )

mail関数はマルチバイト文字非対応のメール送信関数です。mb_send_mailはマルチバイト文字対応のメール送信関数です。imap_mailはIMAPサーバーを利用してメールを送信する関数です。

$toで送信先、$subjectで件名、$messageで本文、$additional_headersで追加ヘッダーが指定可能になっています。$to, $subject, $messageはヘッダー区切り文字である\r\nを含める事はできません。$additional_headersは\r\nで区切ることにより複数のヘッダーを指定できるようになっています。

 

MailヘッダーインジェクションとPHP

PHPのメール関数はMailヘッダーインジェクション対策が行われている為、ToやSubjectヘッダーの値となるパラメーターを利用し、ヘッダーを分割して不正なメールを送信できないようになっています。改行以外にもヌル文字チェックなども行っています。PHPのメール送信関数では、単一のヘッダーの値となるべきパラメーター($to, $subject, $cc, $bcc)は、Mailヘッダーインジェクションに注意する必要はありません。

$additional_headerパラメーターは”\r\n”で複数ヘッダーを指定できる仕組みになっています。ここに含まれるパラメーターに任意文字列が設定できる場合、Mailヘッダーインジェクションが行われ不正なメール送信を許してしまいます。$additional_headerを利用する場合、パラメーターの内容が意図する内容であるか十分バリデーションする必要があります。

メールの送信方法は関数のみではありません。UNIX系のシステムではメール送信を行うsendmailコマンドが用意されています。sendmailコマンド(または類似のコマンド)とパイプを利用してメールを送信できます。この場合、PHPのmail/mb_send_mail/imap_mail関数が行っているような保護は一切ありません。PHPでプログラムしている場合、パイプを使ったメール送信を行うことはあまり無いと思いますが、何らかの理由(大量送信に適した特別なメール送信プログラムを利用するなど)でパイプを利用する場合には十分に注意してください。

 

UNIX系OSとWindows OS

PHPのmail/mb_send_mail関数はUNIX系OSとWindows OSで異なる方法でメールを送信します。

  • UNIX系OS – sendmailコマンドを利用して送信
  • Windows OS – SMTPを利用して送信

送信方法の違いは次に説明するコマンドインジェクションに関係します。

 

コマンドインジェクションとPHPのメール関数

UNIX系OSではsendmailコマンドを実行してメールを送信します。現在のPHPにはコマンドをインジェクションできる脆弱性はありませんが、今までで何度かコマンドインジェクション脆弱性問題が報告され修正されてきました。

現在のmail/mb_send_mail関数はパラメーターのエスケープにescapeshellcmdを内部的に利用している為、不正なオプションを指定できてしまう問題があります。この問題についてはPHPのセキュリティMLで議論中です。このブログでは詳細を解説しません。次のブログを参照してください。

mb_send_mail(),mail()で第5引数を設定する際の注意点
(t_komuraさんのブログは色々参考になります)

メール送信関数用のパラメーターに限らず、全ての外部からの入力はセキュリティ対策としてバリデーションされなければなりません

 

まとめ

メール関数を使えば簡単にメールを送信できます。しかし、注意しなければならない事もあります。システムから意図しないメールが送信されないよう、十分注意してください。

メール関数には安全性を向上させるためのバリデーション機能やエスケープ機能が付いています。堅牢なアプリケーションを作るには、これらの機能に頼るのではなく、全ての入力パラメーターをバリデーションすることが重要です。

入力バリデーションは最も有効なセキュリティ対策です。一部に入力バリデーションはセキュリティ対策ではないとする意見もあるようですが、国際情報セキュリティ標準 ISO 27000の定義ではセキュリティ対策です。疑問に思う方は参考のエントリを参照してください。

基本を押さえておけば、自信を持ってプログラミングできます。楽しく、セキュアにコーディングしましょう!

 

参考

 

 

投稿者: yohgaki