阻止 php 网络联系表单垃圾邮件

Prevent php web contact form spam

我是一名业余网页设计师,我在 whosebug.com 和其他网站上进行了搜索,并找到了针对我遇到的这个问题的许多修复程序,但其中 none 已经奏效(可能是因为我错误地实施了它们)。我希望有更多知识的人可以帮助我进行简单的修复或向我展示如何实施我发现的修复之一。

问题:我的公司网站上有一个非常简单的 php 联系表。它多年来一直运行良好,但在上周遭到黑客攻击。我现在每天收到数百个没有评论的联系表单提交,他们只有(显然有效的)电子邮件地址,以及名称字段中的一串字符(如“58ee8b52eef46”)。

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

这是我的完整 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();
?>

如果您收到的垃圾邮件没有评论,为什么不简单地添加一个检查呢?真正的人类访问者绝对没有理由在不发表评论的情况下提交您的联系表。

由于您不想添加验证码,短期内最简单的解决方案是检查评论是否达到最少字符数并且至少包含一定数量的单词。

例如:

$comments = trim($_POST['comments']); // trim() to strip off whitespace from beginning and end, like spaces and linebreaks

if (strlen($comments) < 20 || substr_count($comments, " ") < 3) {
    died('Your comment is too short.');
}

这是一个非常简单的检查,以查看评论是否包含至少 20 个字符和至少 3 个空格(4 个单词)。根据需要进行调整。

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

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+4?)等在阻止表单垃圾邮件方面不是很有效。

几年前我对此进行了研究,并提出了一个我称之为 "FormSpammerTrap" 的解决方案。它在必填字段上使用 JavaScript 代码到 'watch' 以获得 focus/onclick。自动化流程,除非针对特定站点进行高度定制(这比垃圾邮件机器人所有者想要花费的时间更多),不能 'focus/onclick' 必填字段。

我的 www.FormSpammerTrap.com 网站上有一个免费的解决方案。那里有一种形式,垃圾邮件机器人可以尝试发送垃圾邮件……但他们已经 3 年多没有这样做了。欢迎您试用...它都是开源的,所以您可以看到它是如何工作的。 (而且,如果你使用表格,我不会收集你的电子邮件。我回复一次,然后删除你的电子邮件。)

我的技术在阻止垃圾邮件机器人方面更加有效。他们无法通过垃圾邮件发送该网站上的联系表。

创建一个表单域并为用户隐藏它。 在 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

一种对我有用的更简单的方法。 从字面上看,我收到的所有垃圾邮件 (d) 在邮件中都有一个 url。所以我对此进行了过滤,此后没有收到任何垃圾邮件。我以前每周能拿到 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'.

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

我有另一种方法,我已经在几个网站上成功使用了十多年,但没有一次成功的垃圾邮件机器人攻击。我从服务器日志中了解到,这些表单每天被发送数百次垃圾邮件,但是 none 我已经收到了。此方法不需要验证码或任何其他购买的软件。我会尽量不在这里提供所有细节,但我会说大多数人都可以实现它。

首先,您将需要一个简单的基于文本的图形,其中显示反垃圾邮件“代码”,并且至关重要的是,它所使用的表单域的提示.

第二,您将需要一个接受别名的电子邮件脚本(例如 FormMail 和许多其他)。在您的表单上创建一个名为“收件人”的必填字段(或您的电子邮件脚本希望将表单输入发送到的任何字段名称)。显示您的“代码”图形,旁边带有嵌入式提示。确保您设置电子邮件脚本以接受您在图形中使用的任何代码作为真实电子邮件收件人(您)的别名。

实施后,人们可以轻松阅读和输入您在图形中选择的代码(即在电子邮件脚本中设置的电子邮件别名)。垃圾邮件机器人只能看到一个空白字段。

如果机器人选择随机填写该字段,它会在电子邮件脚本中生成一个错误,实际上表明收件人不存在。您永远不会看到该错误,也不会收到任何垃圾邮件。我已经尝试过此处其他帖子中描述的大多数其他方法,但 none 与此方法一样 100% 有效。

当然,一个人可以打败它,但如果他做到了,您只需在脚本设置中更改图形和电子邮件别名即可。然后,他必须重新开始手动提交。

我分析了一段时间以来收到的垃圾邮件。我注意到:

  1. 垃圾邮件和非垃圾邮件之间提交表单的时间重叠。

    我不知道缓慢的垃圾邮件是人类提交的还是机器人被编程为等待,但我收到的最慢的垃圾邮件需要 26 秒,而一些非垃圾邮件的人类比这更快(8 秒) .

    我经常在文本编辑器中撰写消息,而且大多不会立即提交,所以当我提交消息时,我访问网站,然后将消息复制粘贴到表单中,提交消息只需要几秒钟。我想这就是这些非垃圾邮件发送者所做的。

    7% 的垃圾邮件慢于 5 秒。

  2. 只有大约一半的垃圾邮件填充隐藏的蜜罐字段 (48%)。

  3. 大多数垃圾邮件在邮件正文中包含 URL,但大约 3% 不包含,一些非垃圾邮件包含。

这三种方法一起过滤掉了我收到的绝大多数垃圾邮件,但也有相当多的误报和一些误报。

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

消息的语言。

我 运行 一个非英文网站,我所有的垃圾邮件都是英文的,而 none的非垃圾邮件是英文的。

因此,我所要做的就是在邮件正文中搜索像“你”这样的词,这些词在所有邮件中都是通用的,并且在我自己的语言中不存在。

这可能对那些 运行 网站面向英语观众的人没有帮助,但许多网站不是英语,对他们来说,这可能是垃圾邮件的额外指标。

蜜罐方法简直更好。 但作为开发人员,我们仍然可以做到最好。特别过滤垃圾邮件词..

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

  • 你可以试试这里的那些链接并查看..

    我们对 EMAIL 和 MESSAGE 字段使用了以下脚本。它也会阻止来自 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";}

对于我的回答,既然我通过了这个,我将简单地添加一些新的可能性,因为史蒂夫的蜜罐非常好但被劫持了(也许是最近用于垃圾邮件的新软件)和手工制作的验证码(什么是 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*/

但有时我会收到没有 URL 的垃圾邮件...偶然我收到了基本上是西里尔文的垃圾邮件,所以我使用了以下代码:

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

如果需要,您还可以添加阿拉伯语或希腊语,因为我看不懂这些语言并且对它们不感兴趣。

如果您是俄语、阿拉伯语或希腊语,您可以执行相反的操作,如果您只想接收西里尔字母、阿拉伯语或希腊语字符,则只需添加与 A-Z 相关的 {Common} 代码。

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

我通过使用 js 在 html 表单页面上生成一个 0-9 之间的随机数,然后为每个生成相应的图像,设法解决了通过网络电子邮件表单发送垃圾邮件的问题文本形式的数字(例如,“一”、“二”、“三”……)。数字的文本是浅色的(更难进行 OCR 扫描)并且被我放入图像中的其他人工制品弄得有点模糊。用户必须将这些文本数字(我有 3 个,但可以轻松添加更多)转换为实数并在表单上提交。服务器上的PHP检测提交的号码是否对应于随机生成的号码,如果不对应则拒绝提交。

但是,仍有一些垃圾邮件仍在通过。为了找出方法,我决定在发送给我的电子邮件中包含用户在提交表单时输入的数字,以查看网页上是否使用了 OCR,或者该表单是否实际上是手动填写的。令我惊讶的是,没有数字出现,如果表单是从 html 表单页面提交的,这是不可能的。这意味着垃圾邮件是由 php 本身生成的,绕过了 html 表单。

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

我还应该提到我在 html 和 php 文件中隐藏了所有电子邮件地址。对于垃圾邮件发送者来说,获得有效的电子邮件是有利可图的。对于前者,我创建了电子邮件地址的图像并将其作为图像显示在 html 页面上。当然,网页的 OCR 扫描可以解码它,但到目前为止还不能。对于后者,我将文件中的任何电子邮件地址分成几部分,并在 mail() 需要它的地方 re-assembled 它们。这样,在服务器上对这些文件进行文本扫描(如果仍然发生的话)将不会直接泄露任何电子邮件地址。