« Linux Wirelessドライバ IPW2200b2evolutionのモブログ機能 »

b2evolutionのスパム排除機能をenhance

2006/05/21

  01:07:53 by , Categories: b2evolution

Link: http://b2evolution.net/

AntiSpam NEO Deluxe
b2evolutionは、本サイトを構築するために利用しているブログエンジンですが、昨今のSPAMの多さに閉口して、改良を加えてみました。
AntiSpam Deluxeで紹介されているパッチを、昨年末に最新の安定版に移植したのですが、さらに基本のAntiSPAM機能と統合して、操作性をあげてみました。

このAntiSpam Deluxeの基本思想について紹介します。blacklist一本ではなくて、blacklist, whitelist, potential spam listの3本で管理します。リファラやコメントがあったときに、blacklist, whitelistと比較します。ヒットすれば拒否か、承認となります。どちらでもないときには、Potential リストに登録します。
適時、管理者がAntiSpam機能を利用したときに、Potentialリストをチェックして、white/blackの色分けをする、というわけです。
自動kick機能もあって、管理者がwhiteに振り分ける前に、事前に設定したカウントだけアクセスやコメントがあった場合には、そのURLを自動的にblacklistに登録する、という機能もあります。


パッチについて

patchは、0.9.1に対して開発されています。

まず、データベースのバックアップをとりましょう。また次のファイルのバックアップをとっておきましょう。
admin/b2antispam.php
conf/_advanced.php
b2evocore/_functions_antispam.php
b2evocore/_functions_hitlog.php

すでにb2evolutionを運用している場合は、次のようにmysqlにデータベースを作成します。

CREATE TABLE evo_potential (
spmd_ID integer(4) NOT NULL auto_increment,
spmd_string varchar(250) NOT NULL,
PRIMARY KEY spmd_ID (spmd_ID)
)
CREATE TABLE evo_authorised (
spmd_ID integer(4) NOT NULL auto_increment,
spmd_string varchar(250) NOT NULL,
spmd_logvisits char(1),
PRIMARY KEY spmd_ID (spmd_ID),
UNIQUE spmd_string (spmd_string)
)


もし、インストール前であれば、blogs/install/_functions_create.phpを次のファイルで置き換えれば大丈夫です。
_functions_create.php
アンインストール用のファイルには、次の行を追加しておきます。
function db_delete()
{
global $DB;
// -- Spam-Deluze hack
echo "Dropping Spam-Deluxe table...<br />\n";
$DB->query( 'DROP TABLE IF EXISTS evo_authorised' );
$DB->query( 'DROP TABLE IF EXISTS evo_potential' );
// --
echo "Dropping Antispam table...<br />\n";
$DB->query( 'DROP TABLE IF EXISTS evo_antispam' );


まず、conf/_advanced.phpをエディタで開いて編集します。

// ** DB table names **

/**#@+
* database tables' names
*
* (change them if you want to have multiple b2's in a single database)
*/

$tableposts = 'evo_posts';
$tableusers = 'evo_users';
$tablesettings = 'evo_settings';
$tablecategories = 'evo_categories';
$tablecomments = 'evo_comments';
$tableblogs = 'evo_blogs';
$tablepostcats = 'evo_postcats';
$tablehitlog = 'evo_hitlog';
$tableantispam = 'evo_antispam';
$tablegroups = 'evo_groups';
$tableblogusers = 'evo_blogusers';
$tablelocales = 'evo_locales';
$tablepotential = 'evo_potential'; //hack
$tableauthorised = 'evo_authorised'; // hack
$tablepotspamcom = 'evo_potspamcom';

/**#@-*/

/**
* Aliases for class DB:
*/
$db_aliases = array(
'evo_posts' => $tableposts ,
'evo_users' => $tableusers ,
'evo_settings' => $tablesettings ,
'evo_categories' => $tablecategories ,
'evo_comments' => $tablecomments ,
'evo_blogs' => $tableblogs ,
'evo_postcats' => $tablepostcats ,
'evo_hitlog' => $tablehitlog ,
'evo_antispam' => $tableantispam ,
'evo_groups' => $tablegroups ,
'evo_blogusers' => $tableblogusers ,
'evo_locales' => $tablelocales ,
'evo_potential' => $tablepotential , // hack
'evo_authorised' => $tableauthorised , // hack
'evo_potspamcom' => $tablepotspamcom ,
);


つづいて以下のファイルでblogs/admin/b2antispan.phpを置き換えます。
b2antispam.php

つぎに、blogs/b2evocore/_functions_antispam.phpを編集します。
Line27付近のantispam_create()について、


function antispam_create( $abuse_string, $aspm_source = 'local' )
{

global $DB, $querycount, $tableantispam, $Settings;

// Cut the crap if the string is empty:
$abuse_string = trim( $abuse_string );
if( empty( $abuse_string ) ) return false;

// Check if the string already is in the blacklist:
//Temporarily disable the antispamdeluxe;
$spamTemp=$Settings->get('spamEnabled');
$Settings->set('spamEnabled','');
$Settings->updatedb();
$known=antispam_check($abuse_string);

//Now return antispamdeluxe to its previous state
$Settings->set('spamEnabled',$spamTemp);
$Settings->updatedb();
if ($known ) return false;

// Insert new string into DB:
$sql = "INSERT INTO $tableantispam( aspm_string, aspm_source )
VALUES( '".$DB->escape($abuse_string)."', '$aspm_source' )";

$DB->query( $sql );
// remove banned string from potential list.
spamDeluxe_delete($DB->escape($abuse_string));
return true;
}
のように変更します。

つづいて、最後の方に、次のように関数を挿入します。

/* SpamDeluxe hack
* This function checks the url against it's "potential" table
* If $spamLevel = true then the url is also compared to the content of previous comments
* The url is then added to the "potential" table, for future posts
* If the url has appeared greater than $spamThreshold times the desired action is taken
* based on the value in $spamAuto
*
* $spamAuto = 0 reject the url, no other action
* $spamAuto = 1 reject the url,url is added to the ban list, the comments and hit logs are cleaned
*
* Happy anti-spamming
* Yabba
*
* Porting to 0.9.1
* Hiroshi Miura
*/

/* function spamDeluxe($string) - extends function antispam_check($string) */

function spamDeluxe($theSuspect)
{
global $DB,$Settings;
global $search_engines;


// first lets check that we're turned on
if (!$Settings->get('spamEnabled')) return false;

// reduce the string to just the domain bit of url
// if no URI scheme, it is ok.
if (! preg_match_all('|https?://([a-zA-Z0-9_.-]+)|', $theSuspect, $matches))
return false;

// first check that the parameters are at least set
$spamThreshold=$Settings->get("spamThreshold");
$spamLevel=$Settings->get("spamLevel");
$spamAuto=$Settings->get("spamAuto");
$potential = 0;
$doubt = false;

foreach ($matches[1] as $url) {
// check if it's on the search engine list
foreach($search_engines as $engine)
if (stristr($url, $engine)) return false;

// check if it's on the allowed list
$sql = "select spmd_string from evo_authorised where spmd_string like '%$url%'";
if ($DB->query($sql)) return false;

if (isset($spamThreshold) && isset($spamLevel) ){
$sql="SELECT spmd_string FROM evo_potential WHERE spmd_string LIKE '%$url%'";
$theResult = $DB->get_results( $sql, ARRAY_A );
$potential = $potential + $DB->num_rows;
}
if ($potential < $spamThreshold && $spamLevel){
//ok, they haven't hit us enough, but we're paranoid so lets check the potential comments
$sql = "SELECT comment_content FROM evo_comments WHERE comment_content LIKE '%$url%'";
$theResult = $DB->get_results( $sql, ARRAY_A );
$potential = $potential + $DB->num_rows;
}
if ($potential >= $spamThreshold){
if ($spamAuto) nuke_em($url);
// ok, they've hit us once to often, lets nuke 'em
// and now we have the pleasure of telling them to sod off
$doubt = true;
} else {
// ok, so far they're clean, now lets add them to the potential table for future reference
$sql = "INSERT INTO evo_potential (spmd_string) VALUES('".$DB->escape($url)."')";
$DB->query($sql);
}
}


// and go home
return $doubt;
}

/* function nuke_em($url) - removes spammers from the records */

function nuke_em($theSuspect){
global $DB,$Settings;

// ok time to clear up their mess
// first we'll tidy up the potential table

$sql="DELETE FROM evo_potential WHERE spmd_string like '%".$theSuspect."%'";
$DB->query($sql);

// next we'll add them to our local table and remove any occurences from hitlogs and comments
// Insert new string into DB:
$sql = "INSERT INTO evo_antispam( aspm_string, aspm_source ) VALUES( '".$DB->escape($theSuspect)."', 'local' )";
$DB->query( $sql );

$sql = "DELETE FROM evo_hitlog WHERE referingURL LIKE '%$theSuspect'";
$DB->query($sql);
$sql = "DELETE FROM evo_comments WHERE comment_author_url LIKE '%$theSuspect%' OR comment_content LIKE '%$theSuspect%'";
$DB->query($sql);
}

/*
* spamDeluxe_delete(-)
*
* Remove an entry from the potential list
*/

function spamDeluxe_delete( $string_ID )
{
global $DB;

$sql = "DELETE FROM evo_potential WHERE spmd_string like '%$string_ID%'";
$DB->query( $sql );
}

?>

つづいては、blogs/b2evocore/hitlogs.phpです。
135行め付近を次のように編集します。
if( $ignore == 'no' )
{ // identify search engines
foreach($search_engines as $engine)
{
// debug_log( 'Hit Log: '."engine: ".$engine);
if(stristr($ref, $engine))
{
$ignore = 'search';
debug_log( 'Hit Log: '. T_('referer ignored'). " (". T_('search engine'). ")");
break;
}
}
}


if ( $ignore == 'no' )
{
$sql="select spmd_string,spmd_logvisits from evo_authorised where spmd_string like '%$ref%' and spmd_logvisits='1'";
$yTemp=$DB->get_row($sql);
if ( !$yTemp->spmd_logvisites )
{
debug_log( 'Hit Log: '.T_('referer ignored').'( ('.T_('authorised as not logging').')' );
return;
}
}

if( $doubleCheckReferers )
{
debug_log( 'Hit Log: '. T_('loading referering page') );


あとは、アイコンファイルを2つblogs/admin/img/に追加します。
blogs/admin/img/searchban.gif
blogs/admin/img/eraser.gif


Trackback address for this post

Trackback URL (right click and copy shortcut/link location)

3 comments

Comment from: [Member]
momokuri

さらにエンハンスします。
b2evocore/_functions_antispam.php:440行め付近
if ($spamAuto) nuke_em($url);になっているところを以下のようにします。

if ($spamAuto){
nuke_em($url);
} else {
$sql = "UPDATE evo_comments SET comment_status = 'deprecated' WHERE comment_author_u
rl LIKE '%$url%' OR comment_content LIKE '%$url%'";
$DB->query($sql);
}

これで、閾値より多くのtrackbackが同一URLに来たら、自動的にコメントが表示されないようになります。
もし、白だったら、あとで、状態をpublishedに戻すことで、復旧できます。

2006/07/14 @ 01:37
Comment from: [Member]
momokuri

上記の自動deprecated機能ですが、以前は自動削除にしていたのです。でも、この機能がバグったときに正常な物も削除したりする危険があるので、フラグだけを変えるようにしてみました。

経験的には、同一URLが5つ来たらスパムと考えていいですね。

2006/07/14 @ 01:41
Comment from: [Member]
momokuri

上記の対処に合わせ、
b2evocore/_class_commentlist.phpの77行目に、
$this->request .= "comment_status IN ('published') AND ";
を挿入します。そうすると、最近のコメント一覧で、メンバーであっても、管理者であっても、スパムのおそれが高いコメントやトラックバックが表示されなくなります。
でも、全ブログの最新のコメント一覧(blog id 1)の場合は、表示されます。

2006/07/14 @ 16:40

This post has 1 feedback awaiting moderation...


Form is loading...