続SPAM対策メモ
※以前別の場所で書いた文章を備忘的に書き記しておきます。
【投稿年月日】2011-03-29 【ジャンル】PHP/MySQL
弊社ホームページに、今日の9時20分前後、コメントスパムがやってきた。参考までに、その前後の時間帯のアクセス数は以下の通り。そのせいで一時サイトが繋がらなくなったが、ほどなくサーバー側でスパムを弾くようになったので無事に復旧。わずか10分間ほどのことだったが、今後も同様のことが生じる可能性があるので対策をすることにした。
参考にしたのは以前書いた「SPAM対策メモ」。弊社サイトで使用している「Nucleus CMS」向きにカスタマイズしてみた。
NP_CommentSpamBlock.php
<?php
if(!function_exists('sql_table')) {
function sql_table($name) { return 'nucleus_'.$name; }
}
class NP_CommentSpamBlock extends NucleusPlugin {
function getName() { return 'CommentSpamBlock'; }
function getAuthor() { return 'jun'; }
function getURL() { return 'http://ma-bank.com/'; }
function getVersion() { return '0.1'; }
function getDescription() { return 'Comment Spam Block.'; }
function supportsFeature($id) { return ($id=='SqlTablePrefix') ? 1 : 0; }
function getEventList() { return array('PreAddComment'); }
// コメントがデータベースに追加される前に処理
function event_PreAddComment(&$data) {
$date_id = md5($_POST['date_id']);
$body_jd = base64_decode($_POST[$date_id]);
if($_POST[$date_id] && $body_jd+3600>date('U') && $body_jd<date('U')) {
return;
}else {
exit("Time out error.");
}
}
// スキン変数
function doSkinVar($skinType) {
global $itemid, $CONF, $member;
switch(TRUE) {
case($member->isLoggedIn()) :
$memid = $member->getID();
$mem = quickQuery('SELECT mname as result FROM '.sql_table('member').' WHERE mnumber = '.intval($memid));
$body = 'ユーザー名: '.$mem;
break;
default:
$body = '<label for="nucleus_cf_name">お名前:(※必須)</label>
<input name="user" size="40" maxlength="40" class="formfield" id="nucleus_cf_name" style="display: block;" />
<label for="nucleus_cf_mail">あなたのサイトのURL:</label>
<input name="userid" size="40" maxlength="60" value="" class="formfield" id="nucleus_cf_mail" style="display: block;">
<label for="nucleus_cf_email">メールアドレス:</label>
<input name="email" size="40" maxlength="100" value="" class="formfield" id="nucleus_cf_email" style="display: block;">
<input value="1" name="remember" id="nucleus_cf_remember" type="checkbox">
<label for="nucleus_cf_remember">情報を記憶しておく</label>';
}
$date_id = md5(date('U').date('Y-m-d'));
$message_id = md5($date_id);
echo '<script type="text/javascript">
function setbg() {
if(!document.getElementById("'.$message_id.'").value) {
document.getElementById("'.$message_id.'").value = document.getElementById("message_body").value;
}
}
</script>
<form method="post" action="#nucleus_cf">
<div class="commentform" id="nucleus_cf">
<input name="action" value="addcomment" type="hidden" />
<input name="url" value="'.$this->h($_SERVER['PHP_SELF']).'" type="hidden" />
<input name="itemid" value="'.intval($itemid).'" type="hidden" />
<label for="nucleus_cf_body">コメント:(※必須)</label>
<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body" onfocus="setbg();"></textarea>
'.$body.'
<input value="コメントを追加" class="formbutton" type="submit" />
<input id="message_body" value="'.base64_encode(date('U')).'" type="hidden" />
<input name="date_id" value="'.$date_id.'" type="hidden" />
<input id="'.$message_id.'" name="'.$message_id.'" type="hidden" />
</div>
</form>';
}
function h($str) {
if(!is_numeric($str)) {
$str = htmlspecialchars($str, ENT_QUOTES, _CHARSET);
}
return $str;
}
}
?>
「Nucleus CMS」において、上記プラグイン「NP_CommentSpamBlock.php」を読み込んで、「<%commentform%>」の代わりに「<%CommentSpamBlock()%>」を、個別アイテムページのスキンに書き込めばOK。一時間以内に、コメント欄にフォーカスされていたらコメントの書き込みが可能になります。JavaScriptを切っていたら書き込めませんが、スパム被害のことを考えると致し方がないと割り切ります。if(!function_exists('sql_table')) {
function sql_table($name) { return 'nucleus_'.$name; }
}
class NP_CommentSpamBlock extends NucleusPlugin {
function getName() { return 'CommentSpamBlock'; }
function getAuthor() { return 'jun'; }
function getURL() { return 'http://ma-bank.com/'; }
function getVersion() { return '0.1'; }
function getDescription() { return 'Comment Spam Block.'; }
function supportsFeature($id) { return ($id=='SqlTablePrefix') ? 1 : 0; }
function getEventList() { return array('PreAddComment'); }
// コメントがデータベースに追加される前に処理
function event_PreAddComment(&$data) {
$date_id = md5($_POST['date_id']);
$body_jd = base64_decode($_POST[$date_id]);
if($_POST[$date_id] && $body_jd+3600>date('U') && $body_jd<date('U')) {
return;
}else {
exit("Time out error.");
}
}
// スキン変数
function doSkinVar($skinType) {
global $itemid, $CONF, $member;
switch(TRUE) {
case($member->isLoggedIn()) :
$memid = $member->getID();
$mem = quickQuery('SELECT mname as result FROM '.sql_table('member').' WHERE mnumber = '.intval($memid));
$body = 'ユーザー名: '.$mem;
break;
default:
$body = '<label for="nucleus_cf_name">お名前:(※必須)</label>
<input name="user" size="40" maxlength="40" class="formfield" id="nucleus_cf_name" style="display: block;" />
<label for="nucleus_cf_mail">あなたのサイトのURL:</label>
<input name="userid" size="40" maxlength="60" value="" class="formfield" id="nucleus_cf_mail" style="display: block;">
<label for="nucleus_cf_email">メールアドレス:</label>
<input name="email" size="40" maxlength="100" value="" class="formfield" id="nucleus_cf_email" style="display: block;">
<input value="1" name="remember" id="nucleus_cf_remember" type="checkbox">
<label for="nucleus_cf_remember">情報を記憶しておく</label>';
}
$date_id = md5(date('U').date('Y-m-d'));
$message_id = md5($date_id);
echo '<script type="text/javascript">
function setbg() {
if(!document.getElementById("'.$message_id.'").value) {
document.getElementById("'.$message_id.'").value = document.getElementById("message_body").value;
}
}
</script>
<form method="post" action="#nucleus_cf">
<div class="commentform" id="nucleus_cf">
<input name="action" value="addcomment" type="hidden" />
<input name="url" value="'.$this->h($_SERVER['PHP_SELF']).'" type="hidden" />
<input name="itemid" value="'.intval($itemid).'" type="hidden" />
<label for="nucleus_cf_body">コメント:(※必須)</label>
<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body" onfocus="setbg();"></textarea>
'.$body.'
<input value="コメントを追加" class="formbutton" type="submit" />
<input id="message_body" value="'.base64_encode(date('U')).'" type="hidden" />
<input name="date_id" value="'.$date_id.'" type="hidden" />
<input id="'.$message_id.'" name="'.$message_id.'" type="hidden" />
</div>
</form>';
}
function h($str) {
if(!is_numeric($str)) {
$str = htmlspecialchars($str, ENT_QUOTES, _CHARSET);
}
return $str;
}
}
?>
カスタマイズ方法について少しだけ解説。
コメントの書き込みは一時間以内なので、例えば10分以内の書き込みに限定したい場合は、「3600」を「600」に変更します。
また、「$body_jd = base64_decode($_POST['message_id_']);」や「<input id="message_body" value="'.base64_encode(date('U')).'" type="hidden" />」に関しては、「urldecode」と「urlencode」を組み合わせたり、一定の数字を乗除を組み合わせたりすれば、更に難読化することができます。
これでもスパムが続くようなら、別の方法を試す予定。
EDIUNET | PHP/MySQL | 独り言 | 提供サービス | JavaScript