Защита от спама
формы отправки данных.




   Довольно часто раньше использовалась такая форма связи с клиентом. Сейчас в связи развитием различных мессенджеров и сервисов обратного звонка эта тенденция стала уменьшаться. Однако на многих существующих сайтах и разрабатываемых такая опция присутствует.
Для отправки сообщений обычно используется тэг form. Он позволяет вводить и передавать обрабатывающей программе несколько полей. Я не буду здесь рассматривать синтаксис тэга form и стандартные способы отправки сообщений.

Спамеры, используя специальных роботов, научились использовать такие формы для отправки спама.
В свое время, когда я стал получать уже не единичные такие письма, задумался о безопасности использования таких форм. Итак, первое, что я сделал, страница, формирующая сообщение, была переписана на PHP (так же, как и отправляющая). В формирующей странице устанавливалась сессионная переменная с произвольным именем, а в отправляющей проверялось наличие такой переменной.
Т. е. если обращение шло к отправляющей странице без предварительного захода на формирующую - это уже подозрительно. Но необязательно спам. Так поступают поисковые роботы, которые просматривают страницы. Но у них нет цели написать вам письмо. Да и все поля в этом случае пустые. Так что отправлять сообщение в этом случае нет необходимости.
Поток спама снизился. Далее я решил раз уж есть дополнительная сессионная переменная, то нужно ее исползовать)) На формирующей странице в нее заносится значение текущего времени, на отправляющей (если эта переменная определена) от текущего времени вычитается значение этой переменной. Полученное значение можно условно назвать временем ввода сообщения.
Роботы и люди ведут здесь себя не всегда похоже. Так что смело можно поставить рубеж отсечения. Например, время ввода сообщения менее 3 секунд не характерно для человека.

    Следующим шагом для создания дополнитедьных сложностей спамерским роботам стала еще одна хитрость. Это - переменное имя поля в форме. Точнее - уникальное для каждого захода. Поле в которое вы вводите данные в форме, имеет свое имя. Именно по этому ими вы будете получать ее значение. Таким образом, имя одного из полей всякий раз будет разным.
Несложно сформировать на PHP случайное имя. Простейший пример:

$random = substr(md5(mt_rand()), 0, 6);


Можно взять часть значения имени текущей сессии (session_id),

$id_s=substr(session_id(),0,20);


Еще один вариант - взять md5 от текущего времени.

$random =substr(md5( microtime(true) ),4,8);


    Эту псевдосучайную последовательность можно использовать как часть имени поля с текстом письма. Поскольку это не пароль, а одноразовое контрольное значение, (к тому же доступное пользователю как наименование поля textarea) то и не требуется криптографически безопасное значение.
Однако отправляющая страница должна знать имя поля. Если использовать часть имени сессии или md5 от времени, то не требуется дополнитедьной сессионной переменной для передачи имени поля. Именно второй вариант приведен в примере.

Итак, на странице, формирующей сообщение, размещаем следующий код PHP:

$t_mt= microtime(true); $_SESSION['tposter']=$t_mt; $name_textarea='z' . substr(md5( $t_mt ),2,6)


Далее, при описании формы, для textara подставляем псевдослучайное значение имени.
Условно так:

<textarea name="<? echo $name_textarea; ?>" required></textarea>


А на странице, отправляющей сообщение размещаем следующий код PHP:

$tosend=FALSE; if ( isset($_SESSION['tposter']) ) { $t_mt=$_SESSION['tposter']; unset($_SESSION['tposter']); $prep=microtime(true)-$t_mt; $name_textarea='z' . substr(md5( $t_mt ),4,8); if ( isset($_POST[$name_textarea]) AND $prep > 5 ) { $soob =trim($_POST[$name_textarea]); if (strlen($soob) > 3 AND strpos($soob,'<a href=') === false) $tosend=TRUE; } } if ( !$tosend ){ if(!headers_sent()){ header("Location:poster2.php"); exit; } echo "Что-то пошло не так. Ваше сообщение не отправлено."; exit; }


    Еще одна, как мне кажется, полезная вещь - подмена имени страницы отправки сообщения. Поисковые роботы увидят в поле action одну страницу, а в процессе работы она будет заменена действительной из яваскрипта. Проще посмотреть на примере.
В HTML:

<form method="post" action="/index.html" id="fform">


И в javascript подмена на реальное имя:

document.getElementById('fform').action = 'poster.php';


    Следует отметить, что страница, указанная в форме, должна реально присутствовать на сайте. Иначе поисковые роботы зафиксируют ошибку 404.

    Использовать капчу я не стал, дабы не не причинять неудобств пользователю. Все, что происходит незаметно для клиента, обеспечивает достаточную защиту от спамеров.

    Отдельная тема - само сообщение.
Для начала несколько слов не о спаме, а о общей компьютерной безопасности. То, что вы получили от клиента, может содержать все что угодно. Например, javascript. Поэтому этот текст надо преобразовать для безопасности например, функцией htmlspecialchars. На мой взгляд, вполне допустимо преобразование каждого символа полученных данных в Unicode последовательность(&#xddd;). Недостатком такого подхода является то, что длина сообщения будет в 7 раз больше. Но здесь следует учитывать тот факт, что само сообщение редко превышает 100 знаков. Таким образом, если пользователь ввел сообщение с длиной 100 символов, то преобразованное сообщение будет больше исходного всего на 600 байт! Вполне допустимая плата за безопасность. Вышестакзанные рассуждения о безопасности относятся не только к тексту письма, но и ко всем полученным от пользователя текстовым полям (например, имя, адрес и тд)

    Вернемся к теме статьи - защита от спама формы отправки данных. По моим наблюдениям абсолютное большинство спамерских сообщений содержит тэг <a href=... На странице формирующей сообщение проверяется наличие такого вхождения. Если такое имеется, выдается предупреждение и сообщение не отправляется. Поэтому наличие такого вхождения на странице отправки - достаточный повод не отправлять сообщение.

    Хочу обратить ваше внимание на то, что предложенная здесь реализация идеи не является шедевром. Улучшайте, дополняйте, модифицируйте. Более того, на моей странице стоит несколько похожий, но иной скрипт)).



HTML и CSS
корректный