Анти-спам (практическая часть)
|
|
Опубликовано: 540 дней назад (20 августа 2010)
Блог: Записи Alex’а
Рубрика: Без рубрики
Редактировалось: 4 раза — последний 20 августа 2010
|
+9↑ Голосов: 11 |
Предыдущая теоретическая тут.
В этой статье рассмотрен наиболее простой способ ограждения юзеров от спама, а именно введение captcha (блокировка отправки сообщений) при жалобах от других пользователей. А также введение captcha при слишком частой отправке.
1. Итак, первое с чего нужно начать, добавить в таблицу с юзерам столбец
Spam_detected. Выполняем следующий SQL-запрос
-100 – для администраторов и, например, модераторов, чтобы их случайно не зафильтровать.
0 – означает, что юзер не спаммер.
1 – означает, что есть подозрения, что юзер спаммер (мера воздействия отсутствует)
2 – считаем, что юзер спаммер (мера воздействия: включаем капачи)
4 – считаем, что юзер злостный спаммер (мера воздействия: отключаем возможность писать сообщения)
По дефолту полю spam_detected можно назначить либо 0, либо 1.
2. Создаем таблицу cms_user_abuse (жалобы одного пользователя на другого)
(id, from_user, to_user, spamdate, msg_id, type, description).
from_user – кто пожаловался
to_user – на кого пожаловались
spamdate – время жалобы
msg_id – id мессаги, которую расценили, как спам.
Type – это тип жалобы, сразу можно предусмотреть например жалобы не только на спам, но и на мат и т.д.
description – в этом поле также можно принимать описание юзера, на что он конкретно жалуется.
Выполняем следующий SQL-запрос:
3. (необязательно, дабы не перегружать статью все операции над таблицей убраны) Создаем таблицу cms_user_spammer (id, id_user, reg_mail, date_spam, ip, description) Тут, думаю, все понятно.
Вообще, стоит добавить, что спаммеры бывает 3-ёх типов.
1) Аккаутн специально созданный для спама
2) Пользователя взломали
3) Пользователь-идиот, который верит в письма счастья и т.д.
Ясно, что первых сразу стоит банить, отсылать письмо провайдеру с указанием IP и удалять из таблицы. 2-ой и 3-ий тип нужно заносить в таблицу, чтобы в случае повтора их банить.
4. Добавляем каждому пользователю кнопку для жалоб и обработчики.
4.1. Кнопка в профиль.
4.2. Кнопку к каждой мессаге.
4.3. Кнопка к комментариям.
В данной статье мы ограничимся только кнопкой к мессагам, так как она самая сложная, имхо. Все остальные делают аналогично.
Остальное делается аналогично.
4.2.1. Начнем с user/frontend.php
Допишем туда:
В файле User/messages.php изменяем.
4.2.4 В css добавить стиль для msg_spam. Это уже по вкусу.
5. Производим действия над юзерами, подозрительными на спам.
5.1. Выводим captcha (или блокирует отправку) при отправке личных сообщений.
А также если юзер пишет чаще, чем раз в минуту, будем показывать captcha.
Для этого в файле user/frontend.php ищем процедуру if ($do==’sendmessage’){
И правим ее, чтобы она выглядела так.
Добавляется аналогично, как и для сообщений, даже проще.
6. Админка
Можно также сделать что-то для админки (но честно говоря, я не делал), может быть позже реализую.
6.1. Вынесение всего добра в конфиг и настройка в админке.
6.2. Вывод в админке списка спам-месаг и проч.
7. Что делать с юзерами.
Собственно, после того как начнут поступать жалобы на спам, spam_detected будет расти, и как видно из кода алгоритма его уменьшения не предусмотрено. Поэтому каждая жалоба обрабатывается в ручную, если она по дело, то баним юзера. Если нет, то возвращаем юзеру его spam_detected = 0, через БД.
Можно написать отдельную кнопку и привязать к ней запрос:
$inDB->query("UPDATE cms_users SET spam_detected = 0 WHERE id = ’$id’);
Собственно, я надеюсь, что это кому-то будет полезно.
Просто по ходу выяснился существенный (на мой взгляд) недостаток сообщений, когда юзер удаляет входящее, автоматически удаляется исходящее, поэтому пришлось это дело переписывать, но это уже совсем другая история...
В следствии чего был реализован более сложный алгоритм, с буферными таблицами и прочим (см. теор. часть), но соотв. он ориентирован под мою переделку. Поэтому выкладывать просто не вижу смысла.
Если кто-то хочет поучаствовать в дальнейшей разработкой, пишите в личку, буду рад.
Поиск багов и косяков приветствуется. У меня вроде все работает, тестировал долго и упорно.
20.08.10 Обновлено, исправлена небольшая ошибка. В if ($do==’sendmessage’).
В этой статье рассмотрен наиболее простой способ ограждения юзеров от спама, а именно введение captcha (блокировка отправки сообщений) при жалобах от других пользователей. А также введение captcha при слишком частой отправке.
1. Итак, первое с чего нужно начать, добавить в таблицу с юзерам столбец
Spam_detected. Выполняем следующий SQL-запрос
Код PHP:
Данное поле будет иметь в нашем случае целочисленный тип.ALTER TABLE cms_users ADD COLUMN spam_detected INT NOT NULL AFTER is_deleted
-100 – для администраторов и, например, модераторов, чтобы их случайно не зафильтровать.
0 – означает, что юзер не спаммер.
1 – означает, что есть подозрения, что юзер спаммер (мера воздействия отсутствует)
2 – считаем, что юзер спаммер (мера воздействия: включаем капачи)
4 – считаем, что юзер злостный спаммер (мера воздействия: отключаем возможность писать сообщения)
По дефолту полю spam_detected можно назначить либо 0, либо 1.
2. Создаем таблицу cms_user_abuse (жалобы одного пользователя на другого)
(id, from_user, to_user, spamdate, msg_id, type, description).
from_user – кто пожаловался
to_user – на кого пожаловались
spamdate – время жалобы
msg_id – id мессаги, которую расценили, как спам.
Type – это тип жалобы, сразу можно предусмотреть например жалобы не только на спам, но и на мат и т.д.
description – в этом поле также можно принимать описание юзера, на что он конкретно жалуется.
Выполняем следующий SQL-запрос:
Код PHP:
CREATE TABLE IF NOT EXISTS `cms_user_abuse` ( `id` int(11) NOT NULL AUTO_INCREMENT, `from_user` int(11) NOT NULL, `to_user` int (11) NOT NULL, `spamdate` datetime NOT NULL, `msg_id` int(11) NOT NULL, `type` int(11) NOT NULL DEFAULT '1', `description` varchar(200) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251_general_ci AUTO_INCREMENT=1
3. (необязательно, дабы не перегружать статью все операции над таблицей убраны) Создаем таблицу cms_user_spammer (id, id_user, reg_mail, date_spam, ip, description) Тут, думаю, все понятно.
Вообще, стоит добавить, что спаммеры бывает 3-ёх типов.
1) Аккаутн специально созданный для спама
2) Пользователя взломали
3) Пользователь-идиот, который верит в письма счастья и т.д.
Ясно, что первых сразу стоит банить, отсылать письмо провайдеру с указанием IP и удалять из таблицы. 2-ой и 3-ий тип нужно заносить в таблицу, чтобы в случае повтора их банить.
4. Добавляем каждому пользователю кнопку для жалоб и обработчики.
4.1. Кнопка в профиль.
4.2. Кнопку к каждой мессаге.
4.3. Кнопка к комментариям.
В данной статье мы ограничимся только кнопкой к мессагам, так как она самая сложная, имхо. Все остальные делают аналогично.
Остальное делается аналогично.
4.2.1. Начнем с user/frontend.php
Допишем туда:
Код PHP:
4.2.2. Допишем в user/router.php
/////////////////////////////// SMAP ///////////////////////////////////////////////////////////////////////
if ($do=='spammessage'){
if (usrCheckAuth()){
$sql = "SELECT * FROM cms_user_msg WHERE id = '$id' LIMIT 1";
$result = $inDB->query($sql) ;
if ($inDB->num_rows($result)){
$msg = $inDB->fetch_assoc($result);
if ($msg['to_id']==$inUser->id){
//записываем сообщение в таблицу cms_user_abuse
$message_admin = $msg['message'];
$sql = "INSERT INTO cms_user_abuse (from_user, to_user, spamdate, msg_id, description)
VALUES (".$msg['to_id'].", ".$msg['from_id'].", NOW(), '$id', '$message_admin' )";
$inDB->query($sql) ;
//повышаем уровень spam_detected для отославшего юзера
$inDB->query("UPDATE cms_users SET spam_detected = spam_detected + 1 WHERE id = ".$msg['from_id']." LIMIT 1");
$message_admin ="СПАМ!
[url=/users/".$msg['from_id']."/messages-sent.html]Тут[/url] можно посмотреть исходящие сообщения потенциального спаммера!
--------------------------------------------
".$msg['message']."
--------------------------------------------";
//отсылаем уведомлению админу
$sql = "INSERT INTO cms_user_msg (to_id, from_id, senddate, is_new, message)
VALUES (1, -2, NOW(), 1, '$message_admin')";
$inDB->query($sql);
//удаляем мессагу из входящих
$inDB->query("DELETE FROM cms_user_msg WHERE id = '$id' LIMIT 1") ;
}
}
}
header('location:'.$_SERVER['HTTP_REFERER']);
}//do
///////////////////////////END SPAM//////////////////// Код PHP:
4.2.3 Дополним мессаги кнопкой с жалобой на спам.
//antispam
// RewriteRule ^users/([0-9]*)/spammsg.html$ /index.php?view=users&do=spammessage&id=$1
$routes[] = array(
'_uri' => '/^users\/spammsg([0-9]+).html$/i',
'do' => 'spammessage',
1 => 'id'
);
// end antispam В файле User/messages.php изменяем.
Код PHP:
Опять же вставить можно в любом месте.if ($opt=='in'){
if ($record['sender_id']>0){
echo '<td class="usr_msg_title" width="80" align="right"><a class="msg_reply" href="/users/'.$record['from_id'].'/reply'.$record['id'].'.html">'.$_LANG['REPLY'].'</a></td>';
echo '<td class="usr_msg_title" width="80" align="right"><a class="msg_history" href="/users/'.$id.'/messages-history'.$record['from_id'].'.html">'.$_LANG['HISTORY'].'</a></td>';
////////////////////Дописано АНТИ-СПАМ
echo '<td class="usr_msg_title" width="90" align="right"><a class="msg_spam" href="/users/spammsg'.$record['id'].'.html">Этом спам!</a></td>';
////////////////////Дописано АНТИ-СПАМ (конец)
}
}4.2.4 В css добавить стиль для msg_spam. Это уже по вкусу.
5. Производим действия над юзерами, подозрительными на спам.
5.1. Выводим captcha (или блокирует отправку) при отправке личных сообщений.
А также если юзер пишет чаще, чем раз в минуту, будем показывать captcha.
Для этого в файле user/frontend.php ищем процедуру if ($do==’sendmessage’){
И правим ее, чтобы она выглядела так.
Код PHP:
5.2. Выводим captcha при добавлении комментариев. if ($do=='sendmessage'){
if (usrCheckAuth() && $inUser->id!=$id || isset($_POST['massmail'])){
$from_id = $inUser->id;
$to_id = $id;
$sql = "SELECT * FROM cms_users WHERE id = '$id'";
$result = $inDB->query($sql) ;
$usr = $inDB->fetch_assoc($result);
if ($usr || isset($_POST['massmail'])){
if (usrCheckAuth()){
////////////////////Дописано АНТИ-СПАМ
// если у юзера spam_detected >=2, то будем показывать ему captcha
$sql = "SELECT spam_detected FROM cms_users WHERE id = '$from_id'";
$result = $inDB->query($sql) ;
$usr1 = $inDB->fetch_assoc($result);
$need_captcha = ($usr1['spam_detected'] > 1);
//также проверяем не слишком ли часто мы шлем месаги
if(!$need_captcha)
{
$sql = "SELECT senddate FROM cms_user_msg WHERE from_id = '$from_id' AND senddate >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)
LIMIT 1";
// Здесь можно изменить "INTERVAL 2 MINUTE" или "INTERVAL 30 SECOND" и т.д. для любителей можно отделить в конфиг
$result = $inDB->query($sql);
$need_captcha = ($inDB->num_rows($result)>0);
}
// если у юзера spam_detected <5, то он еще может отсылать сообщения
$can_send = ($usr1['spam_detected'] < 5);
if($_REQUEST['code']) { $code = $_REQUEST['code']; }
////////////////////Дописано АНТИ-СПАМ (конец)
$inPage->setTitle($_LANG['SEND_MESS']);
$inPage->addPathway($usr['nickname'], cmsUser::getProfileURL($usr['login']));
$inPage->addPathway($_LANG['SEND_MESS'], $_SERVER['REQUEST_URI']);
if(!isset($_POST['gosend'])){
if (isset($_REQUEST['replyid'])) { $replyid = (int)$_REQUEST['replyid']; }
else { $replyid = 0; }
if ($replyid){
$sql = "SELECT m.*, u.*
FROM cms_user_msg m, cms_users u
WHERE m.id = $replyid AND m.from_id = u.id AND m.to_id = $from_id";
$result = $inDB->query($sql) ;
if ($inDB->num_rows($result)>0){
$msg = $inDB->fetch_assoc($result);
echo '<div>';
echo '<div class="con_heading">'.$_LANG['ORIGINAL_MESS'].'</div>';
echo '<div class="usr_msgreply_source">';
echo '<div class="usr_msgreply_sourcetext">'.$msg['message'].'</div>';
echo '<div class="usr_msgreply_author"><a href="'.cmsUser::getProfileURL($msg['login']).'">'.$msg['nickname'].'</a>, '.$msg['senddate'].'</div>';
echo '</div>';
echo '</div>';
} else {
die();
}
}
////////////////////Дописано АНТИ-СПАМ
if ($can_send)
{
////////////////////Дописано АНТИ-СПАМ (конец)
echo '<div class="con_heading">'.$_LANG['SEND_MESS'].'</div>';
echo '<table width="100%" cellpadding="0" cellspacing="5"><tr>';
echo '<td width="200" height="200" valign="top">
<div style="background-color:#FFFFFF;padding:5px;border:solid 1px gray;text-align:center">
'.usrLink(usrImage($usr['id'], 'big'), $usr['login']).'
</div>
<div style="padding:5px;width:100%">
Кому: '.usrLink($usr['nickname'], $usr['login']).'
</div>
</td>';
echo '<td valign="top">';
echo '<form action="" method="POST" name="msgform">';
echo '<div class="usr_msg_bbcodebox">';
echo cmsPage::getBBCodeToolbar('message');
echo '</div>';
echo cmsPage::getSmilesPanel('message');
echo '<textarea style="font-size:18px;border:solid 1px gray;width:100%;height:200px;" name="message" id="message"></textarea>';
if ($inCore->userIsAdmin($inUser->id)){
echo '<input name="massmail" type="checkbox" value="1" /> '.$_LANG['SEND_TO_ALL'];
}
////////////////////Дописано АНТИ-СПАМ
// вставляем капачу если нужна
if ($need_captcha) {echo cmsPage::getCaptcha();}
////////////////////Дописано АНТИ-СПАМ (конец)
echo '<div style="margin-top:6px;"><input type="submit" name="gosend" value="'.$_LANG['SEND'].'" style="font-size:18px"/> ';
echo '<input type="button" name="gosend" value="'.$_LANG['CANCEL'].'" style="font-size:18px" onclick="window.history.go(-1)"/></div>';
echo '</form>';
echo '</td>';
echo '</tr></table>';
////////////////////Дописано АНТИ-СПАМ
}
else
{
echo '<span style="color: red;">Возможность отсылать личные сообщения для Вас приостановлена!<br/>
Возможно, на Вас поступили жалобы от других пользователей! В ближайшее время данный случай рассмотрят модераторы сайта.</span>';
}
////////////////////Дописано АНТИ-СПАМ (конец)
} else {
$message = strip_tags($_POST['message'], '<a><img><b><u><i><table><tr><td>');
$message = htmlspecialchars($message, ENT_QUOTES, 'cp1251');
if (!isset($_POST['massmail'])){
//send private message
////////////////////Дописано АНТИ-СПАМ
//(если нужна captcha и она верна, или не нужна) и мы можем слать мессаги тогда отправляем
if ((($need_captcha && $inCore->checkCaptchaCode($code)) || !$need_captcha) && $can_send)
{
////////////////////Дописано АНТИ-СПАМ (конец)
$sql = "INSERT INTO cms_user_msg (to_id, from_id, senddate, is_new, message)
VALUES ('$to_id', '$from_id', NOW(), 1, '$message')";
$inDB->query($sql) ;
$msg_id = dbLastId('cms_user_msg');
//send email notification, if user want it
$needmail = dbGetField('cms_user_profiles', "user_id='{$to_id}'", 'email_newmsg');
//Проверяем, если юзер онлайн, то уведомление на почту не отправляем.
$isonline = dbGetField('cms_online', "user_id='{$to_id}'", 'id');
if (!$isonline){
if ($needmail){
$inConf = cmsConfig::getInstance();
$postdate = date('d/m/Y H:i:s');
$to_email = dbGetField('cms_users', "id='{$to_id}'", 'email');
$from_nick = dbGetField('cms_users', "id='{$from_id}'", 'nickname');
$answerlink = HOST.'/users/'.$from_id.'/reply'.$msg_id.'.html';
$letter_path = PATH.'/includes/letters/newmessage.txt';
$letter = file_get_contents($letter_path);
$letter= str_replace('{sitename}', $inConf->sitename, $letter);
$letter= str_replace('{answerlink}', $answerlink, $letter);
$letter= str_replace('{date}', $postdate, $letter);
$letter= str_replace('{from}', $from_nick, $letter);
$inCore->mailText($to_email, $_LANG['YOU_HAVE_NEW_MESS'].'! - '.$inConf->sitename, $letter);
}
}
$inCore->redirect('/users/'.$inUser->id.'/messages-sent.html');
////////////////////Дописано АНТИ-СПАМ
}// конец if с капача captcha
else
{
//когда captcha в веден неверно
echo '<span style="color: red;">Вы не правильно ввели проверочный код!<br/>
Пожалуйста, вернитесь назад и повторите отправку!</span>';
}
////////////////////Дописано АНТИ-СПАМ (конец)
} else {
if ($inUser->is_admin){
$userlist = dbGetTable('cms_users', ' id > 0 AND is_locked = 0 AND is_deleted = 0');
foreach ($userlist as $key=>$usr){
$sql = "INSERT INTO cms_user_msg (to_id, from_id, senddate, is_new, message)
VALUES ('".$usr['id']."', '-2', NOW(), 1, '$message')";
$inDB->query($sql) ;
}
}
$inCore->redirect('/users/'.$inUser->id.'/messages-sent.html');
}
}
}
}
} else {
usrAccessDenied();
} //usrCheckAuth
}//do Добавляется аналогично, как и для сообщений, даже проще.
6. Админка
Можно также сделать что-то для админки (но честно говоря, я не делал), может быть позже реализую.
6.1. Вынесение всего добра в конфиг и настройка в админке.
6.2. Вывод в админке списка спам-месаг и проч.
7. Что делать с юзерами.
Собственно, после того как начнут поступать жалобы на спам, spam_detected будет расти, и как видно из кода алгоритма его уменьшения не предусмотрено. Поэтому каждая жалоба обрабатывается в ручную, если она по дело, то баним юзера. Если нет, то возвращаем юзеру его spam_detected = 0, через БД.
Можно написать отдельную кнопку и привязать к ней запрос:
$inDB->query("UPDATE cms_users SET spam_detected = 0 WHERE id = ’$id’);
Собственно, я надеюсь, что это кому-то будет полезно.
Просто по ходу выяснился существенный (на мой взгляд) недостаток сообщений, когда юзер удаляет входящее, автоматически удаляется исходящее, поэтому пришлось это дело переписывать, но это уже совсем другая история...
В следствии чего был реализован более сложный алгоритм, с буферными таблицами и прочим (см. теор. часть), но соотв. он ориентирован под мою переделку. Поэтому выкладывать просто не вижу смысла.
Если кто-то хочет поучаствовать в дальнейшей разработкой, пишите в личку, буду рад.
Поиск багов и косяков приветствуется. У меня вроде все работает, тестировал долго и упорно.
20.08.10 Обновлено, исправлена небольшая ошибка. В if ($do==’sendmessage’).
| # 20 августа 2010 в 04:31 0 |
| # 20 августа 2010 в 11:30 0 |
| # 20 августа 2010 в 06:16 0 | ||
|
| # 20 августа 2010 в 11:37 0 | ||
|
| # 20 августа 2010 в 15:11 0 | ||
|
| # 20 августа 2010 в 10:55 0 | ||
|
| # 20 августа 2010 в 11:36 +1 |
| # 23 февраля 2011 в 16:58 0 | ||
|
| # 8 декабря 2011 в 13:18 0 | ||
|
некий процент доверия и возраста. Но не должен полностью быть отключён, потому как есть вероятность "угона" аккаунта, ну тут уже будет вступать механизм предложенный автором данного анти-спама. =)