![]() ![]() ![]() ![]() ![]() Tweet ![]()
| ||
Article Time Stamp: 14 March 2006, 10:33:34 GMT+7 |
Security Hole Mail Header Injection at PHP
ENGLISH LANGUAGE | Go to Indonesian Language |
If you use PHP language to send an email (especially if using HTML form), you must take extra precautions. In the last few weeks, many have tried actively exploiting PHP scripts that use mail() function:
mail($recipient, $subject, $message, [$extraheaders], [$extraparams]);
Most general mistakes that have done by PHP programmer are, they didn't validate every variables that coming to their server. If there's some variables from HTML form, then someone can adding any header into it and that can cause trouble to your server or might send spams by using your server.
As an example, let see this sample code:
mail("me@example.net", $subject, $text, "From: $email\n");
would have security hole if you didn't validate $subject variable and $email variable.
The simple way to detect header injection exploitation is by checking whether there's newline character (\r or \n) at those variables. Here's the example to check $subject variable:
<?php
if (eregi("\r", $subject) || eregi("\n", $subject)) {
die("Why??");
}
?>
Make sure that you check every variable that coming to your server. Beside the example above, you must also check $email variable that being used in mail() function.
Here's the sample PHP code that i've used to prevent spam injection (your critics and suggestions are very welcome)
function logbad($value)
{
$report_to = "your_email";
$name = "www.monx007.com";
$mail = "from_email";
// replace this with your own get_ip function...
$ip = (empty($_SERVER['REMOTE_ADDR'])) ? 'empty'
: $_SERVER['REMOTE_ADDR'];
$rf = (empty($_SERVER['HTTP_REFERER'])) ? 'empty'
: $_SERVER['HTTP_REFERER'];
$ua = (empty($_SERVER['HTTP_USER_AGENT'])) ? 'empty'
: $_SERVER['HTTP_USER_AGENT'];
$ru = (empty($_SERVER['REQUEST_URI'])) ? 'empty'
: $_SERVER['REQUEST_URI'];
$rm = (empty($_SERVER['REQUEST_METHOD'])) ? 'empty'
: $_SERVER['REQUEST_METHOD'];
$headers = "MIME-Version: 1.0\n";
$headers .= "Content-type: text/plain; charset=iso-8859-1\n";
$headers .= "X-Priority: 1\n";
$headers .= "X-MSMail-Priority: Normal\n";
$headers .= "X-Mailer: php\n";
$headers .= "From: \"".$nama."\" <".$mail.">\r\n\r\n";
(
$report_to
,"[ABUSE] mailinjection @ " .
$_SERVER['HTTP_HOST'] . " by " . $ip
,"Stopped possible mail-injection @ " .
$_SERVER['HTTP_HOST'] . " by " . $ip .
" (" . date('d/m/Y H:i:s') . ")\r\n\r\n" .
"*** IP/HOST\r\n" . $ip . "\r\n\r\n" .
"*** USER AGENT\r\n" . $ua . "\r\n\r\n" .
"*** REFERER\r\n" . $rf . "\r\n\r\n" .
"*** REQUEST URI\r\n" . $ru . "\r\n\r\n" .
"*** REQUEST METHOD\r\n" . $rm . "\r\n\r\n" .
"*** SUSPECT\r\n--\r\n" . $value . "\r\n--"
,$headers
);
}
// Check 1
//First, make sure the form was posted from a browser.
// For basic web-forms, we don't care about anything
// other than requests from a browser:
if(!isset($_SERVER['HTTP_USER_AGENT']))
{
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (0)</font>');
exit;
}
// Cek 2
// Make sure the form was indeed POST'ed:
// (requires your html form to use: action="post")
if(!$_SERVER['REQUEST_METHOD'] == "POST")
{
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (1)</font>');
exit;
}
// Host names from where the form is authorized
// to be posted from:
$authHosts = array("yourdomain.com");
// Where have we been posted from?
$fromArray = parse_url(strtolower($_SERVER['HTTP_REFERER']));
// Test to see if the $fromArray used www to get here.
$wwwUsed = strpos($fromArray['host'], "www.");
// Make sure the form was posted from an approved host name.
if(!in_array(($wwwUsed === false ? $fromArray['host'] : substr(stristr($fromArray['host'], '.'), 1)), $authHosts))
{
logbad("Form was not posted from an approved host name");
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (2)</font>');
exit;
}
// Attempt to defend against header injections:
$badStrings = array("content-type:",
"mime-version:",
"content-transfer-encoding:",
"multipart/mixed",
"charset=",
"bcc:",
"cc:");
// Loop through each POST'ed value and test if it contains
// one of the $badStrings:
foreach($_POST as $k => $v)
{
foreach($badStrings as $v2)
{
if(strpos(strtolower($v), $v2) !== false)
{
logbad($v);
die('<font face="verdana" size="2">Form processing cancelled: string
(`<em>'.$v.'</em>`) contains text portions that
are potentially harmful to this server. <em>Your input
has not been sent!</em> Please use your browser\'s
`back`-button to return to the previous page and try
rephrasing your input.</font>');
exit;
}
}
}
// Made it past spammer test, free up some memory
// and continuing the rest of script:
unset($k, $v, $v2, $badStrings, $authHosts, $fromArray, $wwwUsed);
See these sites below to find additional information:
* http://securephp.damonkohler.com/index.php/Email_Injection
* http://us2.php.net/mail (look at the comment section)
INDONESIAN LANGUAGE | Go to English Language |
Jika anda menggunakan bahasa pemrograman PHP untuk mengirim email (terutama jika anda mengirim email dari form HTML), harap untuk berhati-hati. Dalam beberapa minggu terakhir, pihak-pihak yang tidak bertanggung jawab secara aktif mengeksploitasi script-script PHP yang menggunakan fungsi mail():
mail($recipient, $subject, $message, [$extraheaders], [$extraparams]);
Kesalahan yang paling umum dilakukan oleh pemrogram PHP adalah tidak mengecek variabel yang masuk. Jika variabel didapatkan dari form HTML, maka pihak yang tidak bertanggung jawab bisa menambahkan header apapun.
Sebagai contoh, misalnya script PHP seperti ini:
mail("saya@example.net", $subject, $text, "From: $email\n");
memiliki celah keamanan jika anda tidak mengecek validitas variabel $subject dan $email.
Cara pengecekan yang paling mudah untuk mendeteksi eksploitasi header injection adalah dengan mengecek apakah ada karakter newline (\r atau \n) pada variabel tersebut. Berikut adalah contoh untuk mengecek validitas variabel $subject:
<?php
if (eregi("\r", $subject) || eregi("\n", $subject)) {
die("Why??");
}
?>
Perhatikan bahwa anda harus mengecek seluruh variabel yang masuk. Pada contoh di atas hanya diberikan contoh untuk mengecek variabel $subject untuk menyederhanakan. Selain itu, untuk contoh di atas, anda juga harus mengecek variabel $email yang juga digunakan pada fungsi mail() yang digunakan.
Berikut ini contoh PHP coding yang saya lakukan untuk mencegah spam injection (Kritik dan saran sangat saya harapkan)
function logbad($value)
{
$report_to = "email_anda";
$nama = "www.monx007.com";
$mail = "email_pengirim";
// replace this with your own get_ip function...
$ip = (empty($_SERVER['REMOTE_ADDR'])) ? 'empty'
: $_SERVER['REMOTE_ADDR'];
$rf = (empty($_SERVER['HTTP_REFERER'])) ? 'empty'
: $_SERVER['HTTP_REFERER'];
$ua = (empty($_SERVER['HTTP_USER_AGENT'])) ? 'empty'
: $_SERVER['HTTP_USER_AGENT'];
$ru = (empty($_SERVER['REQUEST_URI'])) ? 'empty'
: $_SERVER['REQUEST_URI'];
$rm = (empty($_SERVER['REQUEST_METHOD'])) ? 'empty'
: $_SERVER['REQUEST_METHOD'];
$headers = "MIME-Version: 1.0\n";
$headers .= "Content-type: text/plain; charset=iso-8859-1\n";
$headers .= "X-Priority: 1\n";
$headers .= "X-MSMail-Priority: Normal\n";
$headers .= "X-Mailer: php\n";
$headers .= "From: \"".$nama."\" <".$mail.">\r\n\r\n";
(
$report_to
,"[ABUSE] mailinjection @ " .
$_SERVER['HTTP_HOST'] . " by " . $ip
,"Stopped possible mail-injection @ " .
$_SERVER['HTTP_HOST'] . " by " . $ip .
" (" . date('d/m/Y H:i:s') . ")\r\n\r\n" .
"*** IP/HOST\r\n" . $ip . "\r\n\r\n" .
"*** USER AGENT\r\n" . $ua . "\r\n\r\n" .
"*** REFERER\r\n" . $rf . "\r\n\r\n" .
"*** REQUEST URI\r\n" . $ru . "\r\n\r\n" .
"*** REQUEST METHOD\r\n" . $rm . "\r\n\r\n" .
"*** SUSPECT\r\n--\r\n" . $value . "\r\n--"
,$headers
);
}
// Cek 1
//First, make sure the form was posted from a browser.
// For basic web-forms, we don't care about anything
// other than requests from a browser:
if(!isset($_SERVER['HTTP_USER_AGENT']))
{
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (0)</font>');
exit;
}
// Cek 2
// Make sure the form was indeed POST'ed:
// (requires your html form to use: action="post")
if(!$_SERVER['REQUEST_METHOD'] == "POST")
{
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (1)</font>');
exit;
}
// Host names from where the form is authorized
// to be posted from:
$authHosts = array("yourdomain.com");
// Where have we been posted from?
$fromArray = parse_url(strtolower($_SERVER['HTTP_REFERER']));
// Test to see if the $fromArray used www to get here.
$wwwUsed = strpos($fromArray['host'], "www.");
// Make sure the form was posted from an approved host name.
if(!in_array(($wwwUsed === false ? $fromArray['host'] : substr(stristr($fromArray['host'], '.'), 1)), $authHosts))
{
logbad("Form was not posted from an approved host name");
die('<font face="verdana" size="2">Forbidden - You are not authorized to view this page (2)</font>');
exit;
}
// Attempt to defend against header injections:
$badStrings = array("content-type:",
"mime-version:",
"content-transfer-encoding:",
"multipart/mixed",
"charset=",
"bcc:",
"cc:");
// Loop through each POST'ed value and test if it contains
// one of the $badStrings:
foreach($_POST as $k => $v)
{
foreach($badStrings as $v2)
{
if(strpos(strtolower($v), $v2) !== false)
{
logbad($v);
die('<font face="verdana" size="2">Form processing cancelled: string
(`<em>'.$v.'</em>`) contains text portions that
are potentially harmful to this server. <em>Your input
has not been sent!</em> Please use your browser\'s
`back`-button to return to the previous page and try
rephrasing your input.</font>');
exit;
}
}
}
// Made it past spammer test, free up some memory
// and continue rest of script:
unset($k, $v, $v2, $badStrings, $authHosts, $fromArray, $wwwUsed);
Informasi lebih lanjut dapat dibaca di:
* http://securephp.damonkohler.com/index.php/Email_Injection
* http://us2.php.net/mail (pada bagian komentar)
Copyrighted@ Monx Digital Library, otherwise stated
Use of our service is protected by our Terms of Use