Профессиональная разработка Web-приложений.  
Боишься нашего дизайна?
Новости
PDF журнал
Участники проектa
Сотрудничество
Ссылки
Карта сайта
Комментарии
Комментарии к статье
Добавить комментарий
Обсудить на форуме
Информация об авторе
Оценка статьи

Защита от спама на сайте

Рассуждения о том, как убрать все почтовые адреса и оставить вместо них на сайте лишь формоотправитель.

Введение в проблему

Все мы знаем, что такое спам, потому что либо сталкивались с этим, либо читали об этом. Все мы знаем, как спамеры собирают адреса для рассылок. Так же не секрет, что спам невозможно победить полностью. Проблема состоит в том, как максимально защитить пользователей, оставляющих свои контанктные координаты на вашем сайте, минимальными усилиями.

Ранее испытанные способы защиты

Самую большую угрозу почтовым ящикам представляют программы, качающие сайты и берущие из текста страниц почтовые адреса. Они качают либо только ваш сайт, либо бродят, как поисковые системы, по всей сети. Если ваш сайт небольшой, вполне достаточно защиты такой автозаменой текста:

<?php
$text 
preg_replace("~(<a[^>]+href=)([\"']?)mailto:([\\w_\\.\\-]+)([\\w_\\.\\-])@". <br>"([\\w_\\.\\-])([\\w_\\.\\-]+\\.[a-z]{2,4})\\2([ >])~i""\\1\"mailto:spamux@nospam.ru\" <br>onMouseover=\"this.href='mai' + 'lto:\\3' + '\\4' + '%40' + '\\5' + '\\6';\"\\7"$text);
?>

К сожалению, она не сработает, если у вас большой сайт. Скажем, spectator.ru, автор которого одним из первых стал использовать этот метод. Будь я спамером, я бы залез в персональные настройки, поставил галочки "не показывать ушки", 1000 отзывов на странице, и отловил куки Proxomitron'ом. Потом качалкой или php-скриптом выкачал бы страницы с комментариями (подставив куки с настройками) и при помощи регулярного выражения выловил адреса. Получил бы небольшую базу для рекламной рассылки.

Была ещё пара способов защиты, в которых ссылка mailto: автоматически заменяется на кукую-либо другую, но эффект оставался прежний — при нажатии на неё системный клиент создавал бы письмо по нужному адресу. Оба они не выдержали критики.

Знакомьтесь: ежовые рукавицы

Очевидно, сложно придумать другой способ защиты кроме уже испытанного — предоставления формы на сайте для отправки сообщения. Займёмся её проектированием. Достоинства способа очевидны: никто уже не сможет достать из вашего сайта адреса для своей спамерской базы данных. Отсылать сообщения, спрятав свой адрес, как это делают спамеры, не получится — веб-сервер зафиксирует его IP-адрес. Списки публичных анонимных прокси-серверов регулярно обновляются, и заблокировать доступ с них легко.

Формоотправитель

Начнём именно с него, потому что это самая сложная часть.

Устанавливая формоотправитель на сайте, важно защитить его от хулиганских атак, которые могут быть ничуть не легче спама. Поэтому нам придётся приложить большие усилия в этом направлении.

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

Во-вторых, защитимся от умных хулиганов, записывая логи сообщений. Если пользователь отправлят правильно заполненную форму, скрипт будет смотреть в логи и проверять, что там. Так, нужно запретить

  • отправлять сообщения по одному и тому же адресу чаще определенного периода
  • отправлять один и тот же текст по разным адресам
  • и просто слишком часто пользоваться формоотправителем — скажем, не более 10 сообщений в сутки на одного пользователя

ID сессии выводим в самом конце формы, чтобы хакеру требовалось скачивать всю форму и разбирать её, что сложнее, чем просто отправлять HTTP-запросы. Естественно, формоотправитель будет выдавать сообщения об ошибках в написании сообщения, требование указать обратный адрес и т.п.

Получившийся код формоотправителя оказался слишком большим, чтобы приводить его в тексте. Он помещён в архив на сайте. Вроде бы, скрипт работает и отправляет сообщения.

Замена адресов в тексте

Теперь формоотправитель готов, и нужно заменить все email`ы на ссылки на него. Конечно же, вручную делать этого не стоит. Для себя я написал скрипт, автоматически заменяющий адреса на ссылки к формоотправителю.

Учет ссылок / битые ссылки. Часто приходится ссылаться на одно и то же, также часто ссылки устаревают и «ломаются». Идея: хранить все ссылки в одном месте, нумировать их, и ссылаться на них в виде <a href=link.php3?id=10>.

...Минусы: большее время на расстановку ссылок (компенсирующееся каталогом ссылок), пользователь, наводя курсор на ссылку, не видит, по какому адресу он попадет. (Дмитрий Смирнов, "Идеальный авторский проект, гипертекстуальность")

Все упомянутые минусы легко устранимы, если использовать код аналогичный тому, который я сейчас опишу и покажу.

Ничего сложного здесь нет, если это ссылки, то не требуется "большее время на расстановку". На своём сайте я использую скрипт движка, который вызывается всеми страницами, поэтому не составляет проблемы дописать в него или вызвать из него код, заменяющий адреса. Почтовые адреса как писались, так и пишутся прямо в тексте страниц, но перед выводом пользователю они заменяются на нужный текст. Составить базу ссылок или почтовых адресов при этом не составляет проблемы.

Итак, что делает заменитель адресов. Он ищет в тексте ссылки "mailto:", выбирает из них адреса, отправляет запрос в базу, чтобы подсчитать (count(*)), сколько адресов из тех, что на странице, есть в специальной таблице. Если на странице новые адреса, то их число будет больше, чем результат запроса. В таком случае делается запрос, в котором выбираются значения адресов, и уже существующие в таблице исключаются из списка. Оставшийся список отправляется в таблицу INSERT-запросом.

Что касается ID адресов, то, на мой взгляд, лучше использовать что-то, что посетитель сайта не мог бы подобрать. Представляете, на формоотправитель ведёт ссылка /email.php?id=10 ? Какой соблазн подставить туда 11, 12 и т.д. и попробовать отправить им всем сообщение. Поэтому в качестве идентификаторов я решил использовать md5-хэш от адресов. Подбирать хэш вряд ли кто возьмётся. В случае с каталогом ссылок можно обойтись и ID, но тогда придётся выбирать из базы все значения, а для замены адресов на их хэши всё гораздо проще.

Выполняется команда вида

<?php
$text 
preg_replace("~(<a[^>]+href=)""(['\"]?)mailto:([\\w_\\.\\-]+@[\\w_\\.\\-]+""\\.[a-z]{2,4})\\2(.*?>)~ie""'\\1\\2\"/email.php?email='. urlencode(md5('\\3')). '\"\\4'"$text);
?>

...которая заменяет адреса на их хэши. Остальные адреса, находящиеся в тексте, я не решился заменять на ссылки, а сделал простую замену на адреса типа vasya_at_pupkin_dot_ru. Код автозаменителя так же есть в архиве.

Итог

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

Впрочем, возможно, я слишком жестко стараюсь защититсья от флуда. Ведь одно дело слать спам, используя ошибки почтовых серверов и пряча свой адрес, а другое - заходить по на веб-сервер, который записывает всё, что ты делал. Доступ с анонимных прокси к формоотправителю, естественно, следует закрывать.




For comment register here
   2002-11-15 13:46
Иш ты как меня цитируешь-то! ;) Про замену ссылок я уже думал. После того, как сделал keywords и замену кучу всего остального, это смотрится совсем легкой задачей: пишется скрипт, через который прогоняются уже готовые тексты заметок, он сам выдирает оттуда все ссылки, сам создает их перечень и сам заменяет на что надо. Так что это действительно не проблема, просто руки не доходят ;)

   2002-11-15 13:57
Зато я первый озвучил это. =) Я бы, кстати, не стал оставлять в текстах заметок ID ссылок, а делал бы это по-прежнему на лету. Тогда проще старые тексты редактировать. А скриптом бы только заменял (битые) ссылки.

> Иш ты как меня цитируешь-то!
Представляешь, мой сайт - целиком вторичный продукт. =)

   2002-11-15 14:51
Нет, не вторичный, ты просто менее ленивый ;) Я могу озвучить кучу идей, которые потом ни за что не буду делать. Ну а если и буду, то неизвестно когда. А ты, типа, копаешь вглубь и вширь ;)

Ну а по поводу "старые тексты редактировать". При редактировании можно делать обратное преобразование ;) Так зато клики на ссылки считать гораздо проще.

   2002-11-15 15:04
Спасибо. =)

Обратное преобразование - это как? Через специальный скрипт? А как же универсальный доступ по FTP? =) Считать клики можно и так, и так, только вот при выводе заменять на ID на лету, конечно, сложее.

   2002-11-18 08:49
А, можно все хитрее ;) На FTP закачивается версия для редактирования. После закачки она сама парсится (вставляются кавычки, title'ы, ссылки по теме, ссылки заменяются если надо). Если надо редактировать - редактируется версия для редактирования.

   2002-11-22 15:00
Единственный способ защитить - это не показывать емайл вообще.
А чтоб показать, и усложнить возможность спереть - можно попробовать емайлы перегнать в картинки, и отдавать картинками.
(Сервер конечно жалко ...).

   Unknown 2003-02-05 20:03
Была ещё пара способов защиты, в которых ссылка mailto: автоматически заменяется на кукую-либо другую, но эффект оставался прежний - при нажатии на неё системный клиент создавал бы письмо по нужному адресу. Оба они не выдержали критики.
_____________________________________________
Почему не выдерживает-то? думаешь, люди будут ходить, и вручную эти ссыдки собирать? Не вполне понятен аргумент.

   Unknown 2003-03-28 21:35
а почему бы не использовать вот такую функцию:

function nospam($email) {
$getval = strval($email);
for ($i = 0; $i < strlen($email); $i++) {
$asciicode = ord($getval[$i]);
$nospammail .= "&#$asciicode;";
}
return $nospammail;
}

echo nospam($mail);

icq 47573945

   2004-10-18 13:17
<script language="JavaScript" type="text/JavaScript">
function Mto() {
document.location='mailto:почта'+String.fromCharCode(2*32)+'домен.ру';
} // можно вместо 2*32 - что угодно, лишь бы = 64 :)
</script>

<a href="#" onclick="Mto()">пишите: нам на мыло</a>

   2005-02-25 20:16
Я сделал немного интереснее..имхо...
Просто вместо обычного текста генеряться картинки с надписью адресов эл. почты, в принципе, к этому потом можно "прикрутить" формоотправитель...

   2005-03-16 13:20
Самый лучший способ это находу генерится страница, а ссылка работает от скрипта:
<script language="JavaScript" src="mail.js"></script>
function otpr (imen, idimen)
{
var corpser = new Array;
corpser[0] = "название почтового сервера1";
corpser[1] = "mail.ru";
corpser[2] = "название почтового сервера2";
corpser[3] = "название почтового сервера3";
corpser[4] = "название почтового сервера4";

mra = imen + "@" + corpser[idimen];
return mra;
}

function mylo (imen, idimen)
{
document.write (otpr(imen, idimen));
}

function namylo (imen, idimen, sub)
{ nam = "mailto:";
mra = nam + otpr (imen, idimen);
if (sub != "") eml += "?subject=" + sub;
window.location.href = mra;
}

   2005-03-26 10:50
>> Я сделал немного интереснее..имхо...Просто вместо обычного текста генеряться картинки с надписью адресов эл. почты, в принципе, к этому потом можно "прикрутить" формоотправитель...

Я бы прошёлся по твоему сайту "качалкой", выкачал бы только "почтовые" картинки и натравил бы на них какой-нибудь OCR (FineReader etc.) База адресов у меня кармане... IMHO

   2005-04-25 18:45
А ещё можно графический код встроить. А елси совсем параноиком быть, то не просто графический код, а математический. Правда юзеры не склонны парить мозги и решать что-то, поэтому чтоит ограничиться примером с плюсом или минусом, числа в один знак. Тогда, я думаю, форма отправления будет совсем непробиваема. И, возможно даже и не нада будет лимит на ip ставить. А ещё можно проверить сабмит формы.

   2005-06-23 11:56
я вот такой код сделал - пашет и шифркет мыла JavaScript

if(ereg("[[:alnum:]]+(@)[[:alnum:]]+\.[[:alnum:]]+", $text)){
$text = explode("@", $text);
$perm1 = "ml".rand()."aWe".rand().rand();
$perm2 = "ml".rand()."bWe".rand().rand();
$text = "
<script>
var $perm2 = '$text[1]';
var $perm1 = '$text[0]';
document.write('<a href=mailto:'+".$perm1."+'@'+".$perm2."+'>'+".$perm1."+'@'+".$perm2."+'</a>');</script>";
}

   2006-05-08 22:13
Я защиту от спама сделал следующим образом :
На страничьке размещаю ссылку вида -- <a href="?mail=135" target=anti_spam>мыло</a> --
И ещё определяю на странице нулевой фрейм --
<iframe frameborder="0" height="0" width="0" NAME=anti_spam BORDER=0></iframe>

А скрипт обработки выглядит вот так -

//-------------------------------------------------------------------------------------------



if(isset($_GET['mail']))//анти спам
{
if( $_GET['mail'] != eregi_replace("[^0-9]",null,$_GET['mail']))
{
exit();
}
else
{
$zapros="SELECT `mail` FROM `message` where id = '' ";
if(!($bdresult = @mysql_query($zapros , $bdlink)))
$mail=mysql_fetch_assoc($bdresult);
$mail=$mail['mail'];


$value=null;
for($i=0; $i< strlen($mail); $i++)
{
$temp='&#'.ord($mail[$i]);
$value.='\''.$temp.'\''.' + ';
}


$result='
<html>
<head>
<title></title>
<script language="javascript" type="text/javascript">
<!--
var value='.$value.'\' \';
setTimeout(location.href="mailto:"+value+"\"",0);
-->
</script>
</head>
<body>
</body>
</html>';
print $result;
exit();
}
}

//---------------------------------------------------------------------------------------


Правда я не совсем уверен в надёжности этого способа , но до другова я просто пока ещё не додумался.

Рассуждения о том, как убрать все почтовые адреса и оставить вместо них на сайте лишь формоотправитель.

 
 
 
    © 1997-2008 PHPClubTeam
[]