防止 PHP 网页联系表单垃圾邮件。

40

我是一名业余网页设计师,我在stackoverflow.com和其他网站上搜索了许多解决我遇到问题的方法,但它们都没有起作用(可能因为我实施它们时出现了问题)。我希望有更多知识的人可以帮助我找到简单的解决方案或者向我展示如何实施我找到的其中一个解决方案。

问题是:我的企业网站上有一个非常简单的php联系表格。它多年来一直很好用,但在过去的一周里已经被黑客攻击了。现在我每天接收到数百个联系表单提交,里面没有评论,只有(明显有效的)电子邮件地址和姓名字段中一串字符(例如“58ee8b52eef46”)。

我尝试了几种技术来防止这些垃圾邮件,但它们要么破坏了我的php表单,要么无法防止垃圾邮件。如果可能,我想要一个不需要扭曲文本测试的Captcha解决方案,并且不要求填写表单的所有字段。

以下是我的完整PHP代码:

<?php
if(isset($_POST['email'])) {
  $email_to = "myemail@example.com";
  $email_subject = "website form submission";

  function died($error) {
    echo "We are very sorry, but there were error(s) found with the form you submitted. ";
    echo "These errors appear below.<br /><br />";
    echo $error."<br /><br />";
    echo "Please go back and fix these errors.<br /><br />";
    die();
  }

  if (!isset($_POST['name']) ||
    !isset($_POST['email']) ||
    !isset($_POST['telephone']) ||
    !isset($_POST['comments'])) {
    died('We are sorry, but there appears to be a problem with the form you submitted.');       
  }

  $name = $_POST['name'];
  $email_from = $_POST['email'];
  $telephone = $_POST['telephone'];
  $comments = $_POST['comments'];

  $error_message = "";
  if(strlen($error_message) > 0) {
    died($error_message);
  }
  $email_message = "Form details below.\n\n";

  function clean_string($string) {
    $bad = array("content-type","bcc:","to:","cc:","href");
    return str_replace($bad,"",$string);
  }

  $email_message .= "Name: ".clean_string($name)."\n";
  $email_message .= "Email: ".clean_string($email_from)."\n";
  $email_message .= "Telephone: ".clean_string($telephone)."\n";
  $email_message .= "Comments: ".clean_string($comments)."\n";

  $headers = 'From: '.$email_from."\r\n" .
             'Reply-To: '.$email_from."\r\n" .
             'X-Mailer: PHP/' . phpversion();
  @mail($email_to, $email_subject, $email_message, $headers);  
?>

Thank you for contacting us. We will be in touch with you soon. You will now be redirected back to example.com.
<META http-equiv="refresh" content="2;URL=http://www.example.com">

<?php
}
die();
?>

2
你看过 captcha 吗? - RiggsFolly
我确定之前已经向你提到过,但是Google reCAPTCHA现在对于大多数合法访问者来说是不可见的。 - Steve
2
我考虑过使用验证码。但是我更喜欢不使用验证码的解决方案,以保持我的网站干净整洁的外观。 - user7858610
1
任何人都不应该使用reCaptcha。这是不道德的,因为为了使用它,您需要故意感染您的网站以针对您的用户进行间谍软件攻击。任何不同意跟踪(例如通过阻止来自Google的第三方脚本)的人都无法使用由reCaptcha“保护”的您网站的任何部分。 - Skylar Ittner
1
我太多次不得不点击十几次才能通过验证码,因为它们现在用新的图片替换了一些旧的。真是让人烦恼。请尽量避免使用它们! - Patanjali
显示剩余6条评论
12个回答

78
一个简单的技巧是创建一个蜜罐字段:

html

<!-- within your existing form add this field -->
<input type="text" id="website" name="website"/>

CSS

/*in your css hide the field so real users cant fill it in*/
form #website{ display:none; }

PHP

//in your php ignore any submissions that inlcude this field
if(!empty($_POST['website'])) die();

3
是的,website 是一个不错的通用选择,因为大多数傻瓜垃圾邮件机器人都在寻找链接。您可以添加任意数量的蜜罐字段。您甚至可以添加一个名为 email 的蜜罐,并将真实的电子邮件字段重命名为其他名称(例如 emailaddress)。 - Steve
3
把我的回答中的 isset 改成 !empty,那是我的错误 - 空表单字段会被提交为空字符串,因此总是被设置了。 - Steve
3
这篇帖子已经两年了,似乎不再起作用。我在几个网站上试过这个方法,但机器人似乎已经将其考虑在内。 - bolvo
12
浏览器自动填充了我的某个或多个诱饵表单的问题。解决方法是在每个诱饵表单元素中添加 " autocomplete='off' " 属性。 - ReverseEMF
3
如果机器人是为特定网站设计的,它就不会陷入这个陷阱。 - Abhishek Choudhary
显示剩余8条评论

27
对我来说,一种更简单的方法是筛选所有垃圾邮件中包含网址的信息,自从这样做后,我就再也没有收到过任何垃圾邮件。我曾经每周收到大约10封垃圾邮件。 在您的php文件中,在行   $error_message = "";   下添加以下内容:
if(preg_match('/http|www/i',$comments)) {
    $error_message .= "We do not allow a url in the comment.<br />";
  }

preg_match中的/i使其不区分大小写。'http'也过滤了'https'。


我一直在一个经常遭受机器人垃圾邮件攻击的网站上使用这个,它很有效!如果要添加第二个输入框,例如地址,该怎么做?我尝试了下面的代码,但都没有起作用。if(preg_match('/http|www/i',$company)) { 和 if(preg_match('/http|www/i',$message)) {if(preg_match('/http|www/i',$message,$company)) { echo - ControlZ
哦,太棒了! - AymDev
除非有时你需要在消息中包含一个URL。我的FormSpammerTrap解决方案(现在是版本10,即将推出版本11)允许多个URL以及大量其他表单的自定义。代码中使用了非常有效的技术-我的网站不会受到垃圾邮件的侵扰。 - Rick Hellewell

5
创建一个表单字段并将其隐藏,以便用户无法看到。 在php脚本中,检查此字段是否已提交但为空。 现在您知道请求来自您的表单和用户。
垃圾邮件会填充隐藏字段,或者如果他们直接使用您的php脚本,则垃圾邮件保护字段未设置。
HTML
<input name="website" type="text" class="website"/>

CSS

form .website{ display:none; } /* hide because is spam protection */

PHP

# spam protection
if (isset($_POST["website"]) && $_POST["website"] == "") {
  # your php code to mail here
} else {
  http_response_code(400);
  exit;
}

您可以在此处找到更多保护PHP表单免受垃圾邮件的方法:https://zinoui.com/blog/protect-web-forms-from-spam


强大的垃圾邮件机器人很容易找到并提交隐藏字段。这些机器人可以高度自动化地查找和利用表单。 - Rick Hellewell

5
通常机器人可以非常快速地提交表单。因此,基于此,另一个解决方案是添加另一个隐藏字段,其中包含从打开页面开始经过的秒数。 这可以使用JavaScript完成。然后在PHP中进行检查。如果秒数小于5秒,则为垃圾邮件(真正的客户可能需要更多时间来填写表单)。您可以根据表单包含的字段数量来调整秒数。

1
你可以将两者结合起来生成一个随机数或类似的东西。我发现这种组合非常有效。 - alimack

3

针对我的回答,因为我经历过这个问题,所以我会简单地增加一些新的可能性。由于 Steve 的蜜罐非常好,但被劫持了(也许是因为现在有一些新的软件用于垃圾邮件),手工验证码(比如“3+4等于几”)对我来说也不起作用,即使随机生成数字,它也只能使用一段时间,之后就停止工作了。我不知道他们是如何通过的,但我不得不添加一些代码...

所以我通过以下方式成功获取了垃圾邮件发送者的IP:

$ip = $_SERVER['REMOTE_ADDR'];

我使用 PHP 代码将 $ip 添加到发送的电子邮件主题中,然后添加了此代码以检查结果而无需在我的收件箱中产生垃圾邮件:

if ($ip == '1.1.1.1') /*<-- this is an example*/
{
 $fp = fopen('spam_log.txt', 'a');
 fwrite($fp, 'Inputname: '.$inputname.' IP: '.$ip."\n");
 fclose($fp); die;
}

有了这个,我可以安全一段时间,因为垃圾邮件发送者的IP地址不经常更改。

我得到的大部分内容都是URL,所以我添加了以下内容:

if (strstr($inputname, 'http')){die;} /*<-- did that for each input i had*/
if (strstr($inputname, 'www')){die;} /*<-- did that for each input i had*/

但有时我会收到没有链接的垃圾邮件...偶然我收到了主要是西里尔文的垃圾邮件,所以我使用了这段代码:

$inputname_cyrillic = (bool) preg_match('/[\p{Cyrillic}]/u', $inputname);
if ($inputname_cyrillic){die;}

如果需要的话,您也可以添加阿拉伯语或希腊语,这很好,因为我不会阅读这些语言,也不感兴趣。

如果你是俄罗斯人、阿拉伯人或希腊人,你可以反过来添加{Common}代码,如果你只想接收西里尔字母、阿拉伯字母或希腊字母。

这个主题对我帮助很大,所以我想贡献我的经验。


3
隐藏字段、愚蠢的问题(比如3+4等)等方法并不是在表单中阻止垃圾邮件非常有效的方式。
我几年前进行了研究,并提出了一种称为“FormSpammerTrap”的解决方案。它使用JavaScript代码来“监视”必填字段上的焦点/点击。自动化过程,除非高度定制为特定站点(这需要比垃圾邮件机器人所有者想要花费的时间更多的时间),否则无法“聚焦/点击”必填字段。
我在我的www.FormSpammerTrap.com网站上提供免费解决方案。那里有一个表格,垃圾邮件机器人可以尝试垃圾邮件……但他们已经三年多没有成功。你可以试试看……这是开源的,所以你可以看到它是如何工作的。(如果你使用表格,我不会收集你的电子邮件。我回复一次,然后删除你的电子邮件。)
我的技术在阻止垃圾邮件机器人方面更加有效。他们无法对该网站上的联系表单进行垃圾邮件机器人攻击。

不确定为什么会被踩:添加于2018年7月12日。诀窍是添加一个单击/聚焦事件,将操作参数更改为实际处理页面。否则,我使用的默认值是一种蜜罐类型的网站。我认为这对于垃圾邮件发送者来模拟这些事件是很困难的,虽然可能有可能。该技术可以阻止大量的机器人垃圾邮件发送者。即使在使用该技术的网站上几年后,表单也没有被机器人垃圾邮件发送者攻击过。(我定义机器人垃圾邮件发送者是指通过攻击发送多个提交,而不仅仅是一个提交。)对我来说有效。 - Rick Hellewell
您的系统是否与诸如1Password之类的合法表单填充器兼容? - Stephen R
应该可以,虽然我从未尝试过。它只是使用了一些JavaScript来在单击和聚焦事件中更改内容。由于垃圾邮件机器人无法轻松执行JavaScript,因此这会阻止很多垃圾邮件。如果您想要,可以轻松地向表单添加reCaptcha。它没有什么花哨的东西,只是将其实现到表单中,所以您只需要更改一些变量,包含一个文件,并调用“构建”表单的函数即可。它是免费试用和使用的;功能齐全。请查看网站获取详细信息。 - Rick Hellewell
表单填充器可以与FormSpammerTrap(FST)一起使用。并且提供了大量的自定义选项,以构建具有各种字段类型的表单。机器人保护非常出色;我从未遇到过自动化垃圾邮件的问题。版本11即将发布。有关所有详细信息,请访问FST网站。 - Rick Hellewell
现在已经到了第14个版本,正在开发第15个版本。V14有大量的新功能(语言等),还有许多可定制的功能。您可以将FST垃圾邮件拦截添加到任何表单中。仍然全部免费。请在我的FormSpammerTrap网站上查看使用v14的情况(上面的链接)。自2011年以来一直存在-在我看来仍然是最好的解决方案。 - Rick Hellewell

2
我已经分析了一段时间的垃圾邮件。我注意到以下几点:
1. 在提交表单的时间上,垃圾邮件和非垃圾邮件存在重叠。 我不知道缓慢的垃圾邮件是人工提交还是机器人被编程等待,但我收到的最慢的垃圾邮件需要26秒,有些非垃圾邮件的人比这还要快(8秒)。我通常在文本编辑器中撰写消息,并且大多数情况下不会立即提交它们。因此,当我提交消息时,我会访问网站,然后将消息复制粘贴到表单中,提交消息只需要几秒钟。我猜这就是这些非垃圾邮件发送者所做的。
2. 只有约一半的垃圾邮件填写了隐藏的蜜罐字段(48%)。
3. 大多数垃圾邮件在消息正文中包含URL,但约3%的垃圾邮件没有URL,而有些非垃圾邮件则有。
综合这三种方法可以过滤掉我收到的绝大部分垃圾邮件,但仍存在一些误判。

但是我发现一个单一的指标可以检测到100%的垃圾邮件,并且不会将任何非垃圾邮件误认为垃圾邮件,那就是

邮件的语言。

我运营的是一个非英语网站,所有的垃圾邮件都是英文的,而非垃圾邮件中没有一封是英文的。

因此,我只需要在邮件正文中搜索像“you”这样所有邮件都常用的词汇,但在我的语言中不存在的词汇即可。

这可能对那些针对英语读者的网站没有帮助,但许多网站并非以英语为主要语言,对于它们来说,这可能是垃圾邮件的另一个指标。


0
我成功解决了通过网络电子邮件表单收到垃圾邮件的问题。我在HTML表单页面上使用JS生成了0-9之间的随机数,并为每个数字创建了相应的文本形式图像(例如,“one”,“two”,“three”...)。数字的文本颜色较浅(更难以OCR扫描),并且由我放置在图像中的其他工件略微混淆。用户必须将这些文本数字(我有3个,但可以轻松添加更多)转换为实际数字并在表单上提交。服务器上的PHP检测提交的数字是否对应于随机生成的数字,如果不是,则拒绝提交。
然而,仍有一些垃圾邮件能够通过。为了找出原因,我决定在发送给我的电子邮件中包含用户在提交表单时键入的数字,以查看是否在网页上使用了OCR,或者表单实际上是手动填写的。令我惊讶的是,没有数字出现,这在从HTML表单页面提交表单时是不可能的。这意味着垃圾邮件电子邮件是由PHP本身生成的,绕过了HTML表单。

互联网上有很多关于如何轻松地将外部数据注入到php中的信息,特别是在php mail()函数中的变量。为了对抗这种情况,我将服务器上该php文件的文件访问权限限制为600,并将此文件放置在另一个具有严格文件访问权限710的目录中。这样一来,机器人就很难在这些权限约束下读取该文件。到目前为止,这似乎解决了问题。

我还应该提到,在html和php文件中隐藏了所有电子邮件地址。对于垃圾邮件发送者来说,获取有效的电子邮件地址是有利可图的。针对这种情况,我创建了一张电子邮件地址的图像,并将其作为图像显示在html页面上。当然,网络页面的OCR扫描可能会将其解码,但到目前为止还没有发生。对于后者,我将文件中的任何电子邮件地址都分成几个片段,并将它们重新组合到mail()需要时的位置。这样,如果服务器上仍然存在文本扫描这些文件的情况,也不会直接揭示任何电子邮件地址。


2
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

蜜罐方法更好。

但作为开发人员,我们仍然可以做得更好。特别是过滤垃圾邮件词汇...

  • 我们在客户网站中过滤了色情、性爱、http/www、金钱等垃圾词汇,效果很好。

  • 您可以在此处尝试这些链接并进行检查。

    我们使用以下脚本来处理电子邮件和消息字段。它还将阻止来自MAIL.RU域的垃圾邮件。

if (!preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,5})$/i", $email));if (preg_match('/mail.ru/', $email)){$errors .= "\n Error: Invalid Email Address";}

if (preg_match("/^abc|jpg|png|dating|funding|inbound|www|viagra|porn|sexy|honey|game|и|д|й|л|à/i", $message)){$errors .= "\n Error: Spammy message";}

0
自从提出这个问题以来已经过去了6年。当时最好的解决方案是实施蜜罐和ReCaptcha。
如今,由于LLMs的出现,处理联系表单垃圾邮件有了更好的方法:使用BotButcher或Akismet等API之一将消息发送进行分类。只传递被分类为非垃圾邮件的消息。这些服务非常便宜且非常有效。额外的好处是您现在可以删除ReCaptcha或任何其他“您是人类吗?”的挑战 - 这会提供更好的用户体验。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接