Защита от спама PHP формы отправки данных
Реклама - двигатель прогресса. Рекламодатели постоянно ищут все новые способы рекламы своих товаров и услуг. Поэтому не исключено, что через вашу форму будут рассылать СПАМ - так называемый вид рекламной рассылки.
Как защитить форму от отправки таких данных. 100% защиты не может быть, так как никто никогда не запрещает заполнить вашу форму вручную. Но все же мы можем защитить ее от роботов (программ), которые могут отправлять сотни сообщений в секунду.
Создание скрытого поля с шифром при помощи PHP
Простейший способ – создание скрытого поля с генерацией в нем набора спец символов.
Прежде всего, мы добавляем в форму скрытое поле.
<input type="hidden" name="zf" value="<?=$zaschita?>">
То есть в это поле подставляется переменная $zaschita, которую мы должны сгенерировать заранее. Это сделаем следующим образом:
<?php
$zaschita = md5(md5(time())."ivan");
?>
Мы шифруем время запуска формы и имя ivan. Получается, что каждую секунду данная переменная будет изменена, а алгоритм шифрования известен только вам. Вы можете использовать любой другой метод шифрования или использовать набор любых символов вместо ivan. Для того, чтобы обойти такую защиту в вашей форме потребуется разгадать метод шифрования. Поверьте – это возможно, но на это потребуется некоторое время. И, если это произошло, и защита PHP формы отправки данных на почту не работает, то вы всегда можете поменять шифр.
Код формы изменится:
<form action="send.php" method="post">
<input type="text" name="fio" placeholder="Укажите ФИО" required>
<input type="text" name="email" placeholder="Укажите e-mail" required>
<input type="hidden" name="zf" value="<?=$zaschita?>">
<input type="submit" value="Отправить">
</form>
Проверка передаваемого шифра на PHP
Со стороны PHP мы должны принять скрытую переменную и проверить ее тем же образом, но при этом нам обязательно нужно создать новую переменную и зафиксировать в ней время загрузки формы, иначе наша простейшая защита PHP формы от спама будет работать против нас и не даст пользователю отправить сообщение. Для этого создаем переменную, также шифруя ее:
$vremya = md5(time());
Затем прикрепляем переменную при помощи GET массива.
<form action="send.php?p=<?=$vremya?>" method="post">
После этого нам нужно при отправке формы сформировать шифр и сравнить его с тем, который передан нам в скрытом поле.
Получаем данные:
$pol_time = $_GET['p'];
$vernii_shifr = md5($pol_time."ivan");
$pol_shifr = $_POST['zf'];
Сравниваем их. Если совпадают, то отправляем данные на почту, иначе выводим сообщение:
If($vernii_shifr == $pol_shifr){
….
код отправки письма
….
} else {
echo “Не нужно здесь спамить”;
}
Таким образом, полный код PHP формы с защитой от спама выглядит следующим образом:
<html>
<head>
<meta charset="utf-8">
<title>Форма заявки с сайта</title>
</head>
<body>
<?php
$zaschita = md5(md5(time())."ivan");
$vremya = md5(time());
//проверяем, существуют ли переменные в массиве POST
if(!isset($_POST['fio']) and !isset($_POST['email'])){
?> <form action="send.php?p=<?=$vremya?>" method="post">
<input type="text" name="fio" placeholder="Укажите ФИО" required>
<input type="text" name="email" placeholder="Укажите e-mail" required>
<input type="hidden" name="zf" value="<?=$zaschita?>">
<input type="submit" value="Отправить">
</form>
<?php
} else {
$pol_time = $_GET['p'];
$vernii_shifr = md5($pol_time."ivan");
$pol_shifr = $_POST['zf'];
If($vernii_shifr == $pol_shifr){
$fio = $_POST['fio'];
$email = $_POST['email'];
$fio = htmlspecialchars($fio);
$email = htmlspecialchars($email);
$fio = urldecode($fio);
$email = urldecode($email);
$fio = trim($fio);
$email = trim($email);
if (mail("to@email.ru", "Заявка с сайта", "ФИО:".$fio.". E-mail: ".$email ,"From: ot@email.ru \r\n")){
echo "Сообщение успешно отправлено";
} else {
echo "При отправке сообщения возникли ошибки";
}
} else {
echo "Не нужно здесь спамить";
}
}
?>
</body>
</html>
Описание формы отправки данных на почту
Попробуйте посмотреть исходный код данного скрипта в браузере и обновляйте его каждую секунду – вы увидите, что ключи постоянно меняются.
Теперь предлагаю усложнить защиту, т.е. добавить головной боли для спамеров.Для этого можно создать динамическую переменную в скрытом поле:
<input type="hidden" name="z_<?=$t_vse?>" value="<?=$zaschita?>">
Переменную $t_vse можно создать из времени.$t1 = substr(time(), 9, 1);
$t2 = substr(time(), 7, 1);
$t3 = substr(time(), 8, 1);
$t_vse = $t1+$t2+$t3;
Например текущее время "1547380408". При помощи скрипта мы берем 10-й, 7-й и 8-й символы и просто их складываем, получая переменную $t_vse.Далее нужно передать еще одним скрытым полем текущее время,вместо GET запроса, предварительно зашифровав его с возможностью расшифровки:
$kluch = '3287987984';
$shifruem = time();
$kript = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$shifr = base64_encode(
$kript .
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $kluch, true),
$shifruem,
MCRYPT_MODE_CBC,
$kript
)
);
Добавляем скрытое поле:<input type="hidden" name="d" value="<?=$shifr?>">
Перед отправкой данных формы нужно расшифровать переменную d и получить на первый код:$rsh = $_POST['d'];
$dannie = base64_decode($rsh);
$kript = substr($dannie, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$nashe_vremya = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $kluch, true),
substr($dannie, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
MCRYPT_MODE_CBC,
$kript
),
"\0"
);
$vernii_shifr = md5(md5($nashe_vremya)."ivan");
$t1 = substr($nashe_vremya, 9, 1);
$t2 = substr($nashe_vremya, 7, 1);
$t3 = substr($nashe_vremya, 8, 1);
$t_vse = $t1+$t2+$t3;
$z = 'z_'.$t_vse;
$pol_shifr = $_POST[$z];
Здесь мы воссоздаем, расшифровывая данные, переменную z_{число}, затем получаем наш первый шифр и сверяем его. Таим образом защита от спама PHP формы была усилена и позволит не использовать поля для ввода символов и т.п., что отпугивает пользователей.Полный исходный код нашей PHP формы отправки данных с защитой от спама выглядит следующим образом:
<html>
<head>
<meta charset="utf-8">
<title>Форма заявки с сайта</title>
</head>
<body>
<?php
$zaschita = md5(md5(time())."ivan");
$vremya = md5(time());
$kluch = '3287987984';
if(!isset($_POST['fio']) and !isset($_POST['email'])){
$t1 = substr(time(), 9, 1);
$t2 = substr(time(), 7, 1);
$t3 = substr(time(), 8, 1);
$t_vse = $t1+$t2+$t3;
$shifruem = time();
$kript = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$shifr = base64_encode(
$kript .
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $kluch, true),
$shifruem,
MCRYPT_MODE_CBC,
$kript
)
);
?> <form action="pismo.php" method="post">
<input type="text" name="fio" placeholder="Укажите ФИО" required>
<input type="text" name="email" placeholder="Укажите e-mail" required>
<input type="hidden" name="z_<?=$t_vse?>" value="<?=$zaschita?>">
<input type="hidden" name="d" value="<?=$shifr?>">
<input type="submit" value="Отправить">
</form>
<?php
} else {
$rsh = $_POST['d'];
$dannie = base64_decode($rsh);
$kript = substr($dannie, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$nashe_vremya = rtrim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
hash('sha256', $kluch, true),
substr($dannie, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),
MCRYPT_MODE_CBC,
$kript
),
"\0"
);
$vernii_shifr = md5(md5($nashe_vremya)."ivan");
$t1 = substr($nashe_vremya, 9, 1);
$t2 = substr($nashe_vremya, 7, 1);
$t3 = substr($nashe_vremya, 8, 1);
$t_vse = $t1+$t2+$t3;
$z = 'z_'.$t_vse;
$pol_shifr = $_POST[$z];
if($vernii_shifr == $pol_shifr){
$fio = $_POST['fio'];
$email = $_POST['email'];
$fio = htmlspecialchars($fio);
$email = htmlspecialchars($email);
$fio = urldecode($fio);
$email = urldecode($email);
$fio = trim($fio);
$email = trim($email);
if (mail("to@email.ru", "Заявка с сайта", "ФИО:".$fio.". E-mail: ".$email ,"From: ot@email.ru \r\n")){
echo "Сообщение успешно отправлено";
} else {
echo "При отправке сообщения возникли ошибки";
}
} else {
echo "Не нужно здесь спамить";
}
}
?>
</body>
</html>
Естественно эту защиту можно обойти, если разгадать данный метод, но на это потребуется немало сил и времени.На рисунке я представил исходный код в браузере, обратите внимание на два скрытых поля. В первом каждую секунду меняется и шифр и название переменной, во втором просто меняется шифр.
На следующем рисунке отображен исходный код через несколько секунд.
Вы всегда можете использовать Google ReCaptcha для защиты от спама. Это более надежная защита.
А по поводу защиты PHP формы от спама, описанной в данной статье, я предлагаю в комментариях описать возможные способы ее обхода для того, чтобы мы могли ее усложнить и сделать более надежной, при этом не перегружая пользователя лишними и раздражающими действиями. Пока главная проблема здесь в том, что все ключи видны пользователю. Можно хранить закрытые ключи в базе данных или банально в файле и это усложнит задачу взлома для любителей СПАМА.