メールヘッダーインジェクション:その「改行」が世界を壊す
やあ、現場の最前線でコードと格闘している諸君。今日は「メールヘッダーインジェクション」について話そう。
「今どきそんな古い脆弱性?」と鼻で笑ったそこの君。それが一番危ない。この攻撃は、現代の複雑なクラウドアーキテクチャやマイクロサービス間でも、レガシーなSMTPライブラリや不適切なユーザー入力処理が残っている限り、いとも簡単にゲートをこじ開けてくる。
実際に僕のインシデント対応経験でも、この脆弱性を突かれて自社サーバーがスパムの踏み台にされ、IPレピュテーションが地に落ちて、全メールがGmailの迷惑メールフォルダに直行するようになったケースは一度や二度じゃない。今日は、この攻撃の真の恐怖と、現場で通用する「二度と穴を開けないための実装」を叩き込む。
—
1. 攻撃のメカニズム:CRLFがもたらす「意図せぬ制御」
メールヘッダーインジェクションの本質は、SMTPプロトコルの脆弱性ではなく、「ヘッダーと本文の境界」を改行コード(\r\n)で強制的に操作することにある。
多くのメール送信ライブラリは、内部的に以下のような形式でメールを構築する。
To: {ユーザー入力値}
Subject: お問い合わせの件
From: system@example.com
本文…
ここで、攻撃者が To フィールドに victim@target.com\r\nBcc: spam-target@attacker.com\r\nSubject: 詐欺サイトへようこそ と入力したらどうなるか?
SMTPサーバーに渡される文字列はこう書き換わる。
To: victim@target.com
Bcc: spam-target@attacker.com
Subject: 詐欺サイトへようこそ
Subject: お問い合わせの件
From: system@example.com
本文…
結果として、本来の宛先以外にスパムメールが密かに送信され、件名も乗っ取られる。これが「BCC追加」や「本文の改ざん」のカラクリだ。攻撃者はこれを使って、フィッシングサイトへの誘導や、自社サーバーの信用毀損を狙う。
—
2. 実務で「完全に」防ぐためのコード実装
インジェクションを防ぐ鉄則は、「ユーザー入力をヘッダー値に直結させない」ことだ。特に、改行コードが含まれていないか厳格にチェックする必要がある。
PHPでの対策実装(バリデーションの徹底)
PHPの mail() 関数を直接叩くような古い実装は避け、PHPMailer や Symfony Mailer などのモダンなライブラリを使うのが前提だ。しかし、もし既存コードを改修するなら、以下のようなガード節を必ず挟むこと。
function is_safe_header_value(string $value): bool {
// 改行コード(CR: \r, LF: \n)が含まれていないかチェック
// 含まれていれば攻撃とみなして弾く
if (preg_match(‘/[\r\n]/’, $value)) {
return false;
}
return true;
}
$user_email = $_POST[‘email’];
if (!is_safe_header_value($user_email)) {
// ログに記録し、攻撃をブロック
error_log(“不正なヘッダー入力の試行: ” . $user_email);
die(“Invalid input.”);
}
// 送信処理(ライブラリ使用時も必ずバリデーションを通す)
Python (smtplib) での対策例
Pythonでも同様だ。ライブラリ側でエスケープしてくれる場合もあるが、信頼しきってはいけない。
import re
def send_secure_email(to_address, subject, body):
# 改行コードの検知
if re.search(r'[\r\n]’, to_address) or re.search(r'[\r\n]’, subject):
raise ValueError(“Invalid header input detected.”)
# ここからSMTP送信処理へ(SMTPヘッダー構築時はライブラリのAPIを正しく使う)
# email.message.EmailMessage クラスを使用することを推奨
—
3. インフラ・環境レベルでの防御(多層防御)
コードレベルの修正に加え、インフラ側でも「もしコードに穴があっても被害を出さない」ためのガードを固める。
Nginx/WAFでのフィルタリング
WAF(AWS WAF等)を使っているなら、「CRLFを含むリクエストをブロックする」ルールを適用しろ。これはWebアプリケーションへの攻撃全般に有効な汎用的な防御策だ。
メールサーバー(Postfix等)の制限設定
SMTPサーバー側で、ヘッダー内の不正な改行を許容しない設定(厳格なRFC準拠)を行うこと。main.cf に以下のような制限を加えるのも有効だ。
Postfixの例:不正なヘッダーフォーマットを拒否
smtpd_helo_restrictions = permit_mynetworks, reject_invalid_helo_hostname
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination, reject_non_fqdn_recipient
—
最後に:なぜ「ライブラリ」を使うのか
現場のエンジニア諸君に最後に伝えておきたい。「独自のメール送信関数を作ろうとしないこと」。
メールプロトコルは非常に複雑で、エンコーディングや引用符の扱い一つでヘッダーインジェクションの余地が生まれる。PHPMailer や PythonのEmailMessage といった、長年世界中の開発者がバグを潰し続けてきたライブラリは、そうしたエッジケース(特殊な文字コードや制御文字)に対する防壁が標準で組み込まれている。
「自分で書いたほうが軽いから」という理由で独自のSMTP構築を行うのは、セキュリティの世界では「無防備な要塞を作る」ことと同義だ。
コードを修正したら、必ず \r\n を含めた入力値でテストすること。もし開発環境でメールが送信されたら、それは脆弱性が残っている証拠だ。自分の書いたコードが、いつか世界を混乱させる踏み台にならないよう、今一度、入力を疑う癖をつけてほしい。
現場からは以上だ。何かあればいつでも相談してくれ。
コメント