我可以通过仅替换 CR 来避免 CRLF 注入攻击吗?
我有一个表格,允许一个文件附件,并生成一封电子邮件到一个硬编码的地址。我想避免恶意用户输入自定义邮件标头的可能性(CRLF 注入,因为根据 RFC 电子邮件标头以 \r\n 结尾,所以称为 CRLF 注入)。
假设我对每条数据运行以下函数,这些数据可能会进入 $additional_headers 参数:
<?php
function strip_crlf($string){ return str_replace("\r\n", "\n", $string); }
?>
仅替换 CRLF 对的回车符一半。这能充分防止潜在的攻击吗?
通常我只是将 \r\n 替换为空字符串。但这种特殊形式允许一个附件,这意味着消息正文实际上最终会通过 $additional_headers 参数传递,因为 PHP 没有用于构建多部分 MIME 编码电子邮件的本机函数(据我所知)。
如果有人关心,这是我邮寄附件的功能:
<?php
function mail_attachment($to, $from, $from_name, $subject, $message, $file = false, $filename = false, $filetype = false){
// Remove CRLF sequences from everything that might go into a header
$from = strip_crlf($from);
$from_name = strip_crlf($from_name);
$message = strip_crlf($message);
if($filename){ $filename = strip_crlf($filename); }
if($filetype){ $filetype = strip_crlf($filetype); }
// $to and $subject escaping handled natively by mail();
// $file is base64 encoded before mail_attachment() is called.
$header = '';
// No file attachment; just send a regular email.
if(!$file){
$header .= "From: ".$from_name." <".$from.">\r\n";
return mail($to, $subject, $message, $header);
}
$uid = md5(uniqid(time()));
// Build a MIME encoded message.
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"$uid\"\r\n\r\n";
$header .= "This is a multi-part message in MIME format.\r\n";
$header .= "--$uid\r\n";
$header .= "Content-type:text/plain; charset=utf-8\r\n";
$header .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$header .= "$message\r\n\r\n";
$header .= "--$uid\r\n";
$header .= "Content-Type: $filetype; name=\"$filename\"\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= "Content-Disposition: attachment; filename=\"$filename\"\r\n\r\n";
$header .= "$file\r\n\r\n";
$header .= "--$uid--";
// Send the mail.
return mail($to, $subject, '', $header);
}
?>
I have a form which allows one file attachment, and generates an email to a hard-coded address. I would like to avoid the possibility of malicious users entering custom mail headers (a CRLF injection, so called since email headers end in \r\n as per RFC).
Suppose I run the following function on every piece of data which might make it into the $additional_headers parameter:
<?php
function strip_crlf($string){ return str_replace("\r\n", "\n", $string); }
?>
That replaces JUST the carriage return half of the CRLF pair. Will that prevent potential attacks adequately?
Ordinarily I would just replace the \r\n with an empty string. But this particular form allows for one attachment, which means that the message body actually winds up getting passed through the $additional_headers parameter since PHP doesn't have a native function for building a multipart MIME encoded email (that I know of).
In case anyone cares, here's my function for mailing an attachment:
<?php
function mail_attachment($to, $from, $from_name, $subject, $message, $file = false, $filename = false, $filetype = false){
// Remove CRLF sequences from everything that might go into a header
$from = strip_crlf($from);
$from_name = strip_crlf($from_name);
$message = strip_crlf($message);
if($filename){ $filename = strip_crlf($filename); }
if($filetype){ $filetype = strip_crlf($filetype); }
// $to and $subject escaping handled natively by mail();
// $file is base64 encoded before mail_attachment() is called.
$header = '';
// No file attachment; just send a regular email.
if(!$file){
$header .= "From: ".$from_name." <".$from.">\r\n";
return mail($to, $subject, $message, $header);
}
$uid = md5(uniqid(time()));
// Build a MIME encoded message.
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"$uid\"\r\n\r\n";
$header .= "This is a multi-part message in MIME format.\r\n";
$header .= "--$uid\r\n";
$header .= "Content-type:text/plain; charset=utf-8\r\n";
$header .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$header .= "$message\r\n\r\n";
$header .= "--$uid\r\n";
$header .= "Content-Type: $filetype; name=\"$filename\"\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= "Content-Disposition: attachment; filename=\"$filename\"\r\n\r\n";
$header .= "$file\r\n\r\n";
$header .= "--$uid--";
// Send the mail.
return mail($to, $subject, '', $header);
}
?>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您担心注入,请不要构建自己的消息。使用 Swiftmailer 或 PHPMailer,为您解决所有这些后顾之忧。
If you're worried about injections, then don't build your own messages. Use Swiftmailer or PHPMailer, which take care of all those worries for you.
不,仅替换 CR 是不够的 - 有足够多的邮件客户端只查看 LF,从而可以利用它。当然,大多数标头字段根本不需要换行符,因此您可以简单地从除
$message
之外的所有内容中删除 CR 和 LF。对于$message
,请确保它不能包含您的 MIME 分隔符(在本例中为--$uid
),或者将其编码为 base64 或其他内容。No, replacing just the CR is not sufficient - there are enough mail clients which only look at the LF that it can be exploited. Of course, most of the header fields don't need newlines at all, so you can simply strip both CR and LF from everything but
$message
. For$message
, either make sure it can't contain your MIME seperator (--$uid
in this case), or encode it as base64 or something.