这个 mail() 函数对标头注入安全吗?

Posted

技术标签:

【中文标题】这个 mail() 函数对标头注入安全吗?【英文标题】:Is this mail() function safe from header injection? 【发布时间】:2012-06-17 21:54:41 【问题描述】:

我正在为网站构建一个简单的联系表单。它不连接到数据库,它只是发送电子邮件。此代码会阻止垃圾邮件发送者使用标头注入吗?有没有我没有看到的漏洞?

//create short variable names
$name= filter_var($_POST['Name'],FILTER_SANITIZE_STRING);
$email= filter_var($_POST['Email'],FILTER_SANITIZE_STRING, FILTER_VALIDATE_EMAIL);
$subject= filter_var($_POST['Subject'],FILTER_SANITIZE_STRING);
$message= filter_var($_POST['Message'],FILTER_SANITIZE_STRING);

//set up some static information
$toaddress = 'blah@localhost.com,blahblah@localhost.com';

$mailcontent = "Customer name: ".$name."\n".
            "Customer email: ".$email."\n".
            "Subject: ".$subject."\n\n".
            $message;

$fromaddress = "From:" . $email;

//invoke mail() function to send mail
mail($toaddress, "Website Contact Form",$mailcontent, $fromaddress);
?>

【问题讨论】:

谢谢大家,所有的答案都很有帮助。只要没有其他人可以在其中戳洞,我就会接受 Alnitak 的回答。谢谢 Alnitak! 【参考方案1】:

标头注入依赖于能够在标头变量中插入额外的换行符,这使得字符串看起来像一个新标头。

例如,允许 Testing\nCc: spamrecipient@example.com\n\nSome body text 的主题值将导致消息头包含:

Subject: Testing
Cc: spamrecipient@example.com

Some body text

即施虐者不仅添加了其他收件人,而且还设法提供了自己的正文。

但是,在您的情况下,$toaddress 是恒定的,即使 $toaddress 是用户提供的,它也应该由 mail() 函数正确清理。

你的主题标题同样是不变的

$message 变量是安全的,因为根据定义,它是正文,仅在真正的标题之后发送。

只剩下$fromaddress,你已经在使用FILTER_VALIDATE_EMAIL,它也应该拒绝任何带有换行符的东西。

但是,您应该严格检查该测试的结果,如果结果为FALSE,则中止整个测试。因为如果验证失败,那么mail() 将抱怨给了一个空白的From: 地址,但那里没有标头注入机会。

据我所知,这段代码实际上是安全的。


另外,恕我直言,您不应该从用户提供的电子邮件地址发送电子邮件。这会违反 SPF 等反垃圾邮件机制。

您应该使用属于您自己域的常量From: 值。如果您愿意,可以在 Reply-To 标头中使用经过正确清理的值,以便更轻松地将后续回复发送到所需地址。

【讨论】:

【参考方案2】:

恕我直言,您的代码不安全,因为您错过了 \r\n 字符。 filter_var() 只会杀死那些,如果 FILTER_SANITIZE_STRINGFILTER_FLAG_STRIP_LOW 一起使用,这也会过滤掉 ASCII 32 以下的任何字符:

$message= filter_var($_POST['Message'], 
                     FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);

另外,FILTER_VALIDATE_MAIL 将返回 true 或 false,您也没有考虑到这一点。我建议查看thisfilter_var() 的优秀来源,因为主要的 php 手册信息非常短。


更新:正如 Alnitak 指出的,通过代码中的\n\n,这实际上并不重要。

【讨论】:

没有一个裸露的FILTER_SANITIZE_STRING 变量最终出现在标题中,因此那里没有风险。您关于检查FILTER_VALIDATE_EMAIL 的结果的观点与我已经提出的相同。 它甚至不是\n\n - 它已经在邮件正文中,并且不是标题的一部分。这只是令人困惑,因为 OP 将文本放在 看起来 像标题(但不是)的正文中。【参考方案3】:

不,这不会对任何东西进行消毒。

很容易捏造那个邮件。

我可以在帖子值(您阅读的)中添加任何内容来操作邮件。

【讨论】:

为什么?如何?如何预防? @Neal 使用 filter_var,我很好奇你还能看到哪些额外的漏洞。 Neal,您能否提供一个可能导致恶作剧的输入示例(或者更好的是几个不同的示例)以及什么样的代码可以处理它们? @ikh 防止注入最关键的事情是确保任何将被放入标题中的字段都不能插入任何换行符。例如如果你可以强制value\nHeader: XXX 进入主题,那么你会得到一个额外的假标题。 @Alnitak 据我所知,进入标题的值是$email,用FILTER_VALIDATE_EMAIL 检查,(我认为?)会拒绝带有换行符的字符串。我在这里错了吗?其他一切都进入身体。

以上是关于这个 mail() 函数对标头注入安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Security 注入默认安全标头

我的 PDO 查询对 SQL 注入安全吗?

这种动态 SQL 查询生成对注入安全吗?

这个 PDO 代码对 SQL 注入是不是足够安全? [复制]

使用 Javascript 预防 WebSQL 注入

SQL注入漏洞的判断