PHPとメールサーバーに問い合わせフォームのあるウェブサイトを持っています。メールはPHP mail
関数の助けを借りて送信されます
$name = cleanInput($_POST["name"]);
$e = $_POST["email"];
$email = filter_var(cleanInput($e), FILTER_SANITIZE_EMAIL);
if (strpos($name, "@") !== false) {
$msg = 'Invalid name!';
exit();
}
else if (strcmp($e, $email) !== 0 ||
filter_var($email, FILTER_VALIDATE_EMAIL) === false ||
!checkdnsrr(substr(strrchr($email, "@"), 1))) {
$msg = 'Invalid email address!';
exit();
}
else
{
$message = nl2br(cleanInput($_POST['message']));
$subject = 'Support request';
$to = '[email protected]';
$sender = '[email protected]';
$headers = array(
'From' => $name . '<' . $email . '>',
'MIME-Version' => '1.0',
'Content-type' => 'text/html; charset=iso-8859-1'
);
$result = mail($to, $subject, $message, $headers, '-r' . $sender);
}
function cleanInput($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
最近、このようなFrom
フィールド値を使用してメールを投稿しているスパマーに攻撃されました
[email protected], [email protected], [email protected],
"US:http"@mydomain.com://www.somedomain.com/page <[email protected]>
名前フィールドの@
文字をそのように禁止しました
if (strpos($_POST["name"], "@") !== false)
exit()
Postmanからname@
のような名前のPOSTリクエストを送信してみましたが、拒否されましたが、同じスパムメールを受信しています。
スパマーが検証チェックを迂回する方法を教えてください。
更新
これは、生の入力フィールドのerror_logを含むスパムメールの例です https://Pastebin.com/29ppLGuX
Update2
@ mti2935のおかげで、実行された注入がないことがわかりました。スパマーはname
フィールドにリンクを含む単純なテキスト行を入力しているだけで、MTA(Postfix)が何らかの理由でそのテキストのすべての単語にドメイン名を追加しています。私はデータをいじってみましたが、この問題の原因はcolon
であることがわかりました。
If $name="one two three" then the header of the received email looks good
From: one two three<[email protected]>
If $name="one: two three" then
From: [email protected]:two three <[email protected]>
If $name="one: two: three" then
From: "one:two"@mydomain.com:three <[email protected]>
ヘッダー配列をmail
にフィードする前に文字列に変換してみましたが、同じ結果が得られました。
Pastebinの投稿は非常に役立ちます。まず第一に、投稿した無害化されたユーザー入力から、スパマーは実際にはフォームの「名前」フィールドに@文字を含む入力を入力していないことがわかります。つまり、スクリプトのチェックを通過する方法がわかります。
あなたのMTAが@ yourdomain.comをこれらの入力に追加していることが起こっているようです。これは、ドメインのないメールアドレスに遭遇したときにMTAがデフォルトで行うことです。
それで、MTAがこれらの値をFrom:
ヘッダー。通常は送信者の名前を、名前ではなく電子メールアドレスとして使用します。これは、mail()関数への4番目の入力として渡す$ headers配列を作成する方法に関連していると思います。ヘッダーの各行の後に「\ r\n」が必要で、配列を文字列に変換する必要があると思います。他にも注意すべき点があるかもしれません。これを正しく行う方法の詳細については、 https://stackoverflow.com/questions/27478307/having-issue-on-setting-array-of-headers-in-php-mail-function を参照してください。
更新:上記の問題に加えて、フォームに入力するときにユーザーが送信者の名前フィールドにコロンを含めると、後でこの文字がFrom:
メッセージのヘッダー。詳細とソリューションについては、yaugenkaによる以下のコメントを参照してください。
Fromヘッダーで$ nameと$ emailの両方を組み合わせていますが、投稿によると$ nameのみをフィルターします。攻撃者(自動化されたスパムボット)は、おそらく$ email変数に注入しています。
箱から出して、PHPは、チェックのフレームワークなしでさまざまなインターフェースに直接アクセスできます。場合によっては、出入りするものについての厳密なルールを使用して、厳密に制御されたサンドボックス内での操作に制限することをお勧めします。PHPはそのような環境ではありません。
あなたが私たちに示したコードに基づいて、これを悪用することは簡単です。 anyをユーザーの電子メールヘッダー内のユーザー投稿テキストに許可すると、攻撃者は受信者といくつかの送信者アドレスを制御できます。フィールド長を70文字に制限し、「<」、「>」、「、」、\ r、および\ nをSMTPヘッダーで終わる可能性のあるフィールドから禁止することは役立ちますが、堅牢なソリューションにはまだ不十分です。 。
彼らがこれをどのように行ったかがわからないということは、コードのロギングが不十分であることも強調しています。