Captcha — это картинка с буквенным или цифровым содержимым, которое пользователь должен ввести в поле вручную. Таким образом исключается полностью или частично поступление спама. Captcha не всегда удобна для пользователя, поэтому рассмотрим другие способы защиты от спама.
Защита от ботов основана на предположении, что любой бот заполняет все поля значениями. Получается, что если поле имеет атрибут, который скрывает поле от посетителя, последний не видит это поле и потому не заполняет его, тогда как бот считывает код страницы и пытается заполнить все поля формы. Итак, наша форма, необходимо добавить в нее скрытое поле:
<form action="/register.php" method="post">
<input type="text" name="login" value="">
<input type="text" name="e-mail" value="">
<input type="password" name="pass" value="">
<input type="text" name="invisible" id="invisible" value="">
<input type="submit" value="Отправить">
</form>
А также в файле .css дописать код:
#invisible {
display: none;
}
И, наконец, добавить в скрипт, которым обрабатывается форма, строки:
// Если скрытое поле заполнено
if ($_POST['invisible']!=''){
die('Ботам - нет!');
}
else{
// Обработка формы
}
В обработчике формы создаем массив с вопросами и вариантами ответа на них и перемешиваем элементы массива:
<?
$spam[] = array("Три плюс пять равно...","v.match(/^восемь$/i)||v=='8'");
$spam[] = array("Шесть минус два равно...","v.match(/^четыре$/i)||v=='4'");
$spam[] = array("Девять минус девять равно...","v.match(/^ноль$|^нуль$/i)||v=='0'");
shuffle($spam); // Перемешиваем элементы массива
?>
Вопросов может быть сколько угодно. Не забудьте про все варианты ответа (i
показывает, что регистр ввода неважен).
Форма обратной связи:
<form method="post" action="<?php echo $_SERVER['REQUEST_URI'] ?>">
Имя: <input type="text" name="login" /><br />
E-mail: <input type="text" name="e-mail" value=""><br />
Сообщение: <br /><textarea name="message"></textarea>
<?php echo $spam[0][0] ?>
Ответ: <input type="text" id="myspam" size="20"/>
</form>
Как вы видите, здесь отсутствует кнопка «Отправить». Она появится с помощью JavaScript после того, как пользователь ответит правильно на поставленный вопрос. Сам код JavaScript пишем внизу файла:
<script type='text/javascript'>
document.getElementById('myspam').onkeyup = function(e){var v = this.value;if(<?php echo $spam[0][1] ?>){var inp = document.createElement('DIV');inp.innerHTML = '<input type="submit" value="Отправить!" />';this.parentNode.insertBefore(inp,this.nextSibling);this.onkeyup = null;}}
</script>
Простейший способ – создание скрытого поля с генерацией в нем набора спец символов. Прежде всего, мы добавляем в форму скрытое поле <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 формы от спама будет работать против нас и не даст пользователю отправить сообщение. Для этого создаем переменную, также шифруя ее: $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>
Естественно эту защиту можно обойти, если разгадать данный метод, но на это потребуется немало сил и времени.