Lighttpdでプロセスを起動せずにスパムを撃退する方法

キャッシュを有効に活かすことはmod_rewriteでも処理可能ですから不要なモジュールを使用しないという意味においては積極的にmod_cmlを導入する理由もみつからなかったのですが、こんな使い方も考えてみました。

mod_cmlの目的はサーバ内で処理できるリクエストはサーバ内で処理しできるだけrubyなりphpなりのインタプリタを起動しないで負荷を減らし高速化しようというものです。それでちょっと前に悩まされていたトラックバックスパムの撃退に利用できないか思いついた訳なんです。現在、このブログでもdrupalのtrackback.moduleにスパム撃退のコードを埋め込んでいますが、結局phpは起動されているわけでこういう不毛な処理をサーバ側追い出すことができれば実にうれしい。早速トライしてみました。

当初、現在Drupalのtrackback.moduleに組み込んでいるのはまちゅダイアリー - コメント SPAM 対策 - 日本語を含まないコメントを禁止なのでこれをそのままpower-magnet.cmlに追い出すことを検討したのですがLuaが文字列のマルチバイトに対応していないため断念。(時間があればこの部分をカスタマイズして再チャレンジしたいですが)代わりにキーワードを指定してスパム判定するオーソドックスなやり方を実装してみました。

まず、最初はtrackbackモジュールへのURLかどうか調べます。例えば、トラックバックURLが”http://example.com/trckback/id”の場合、キーワードとしてtrackbackをチェックします。power_magnet.cmlはすべてのリクエストに先立って実行されるのでこの判定を誤ると痛いメにあうかも。

ur = request["REQUEST_URI"]
if not string.find(ur,"trackback") then
   return CACHE_MISS
end

トラックバックリクエストの判定をした後、trackbackのtitle/excerptに指定したキーワードが含まれていたらこれをスパムとみなします。その場合、あらかじめ作成しておくerror.xmlを返します。OKであればCACHE_MISSを返しアプリケーションに処理を委ねます。

is_spam = 0
title = get["title"]
excerpt = get["excerpt"]
-- NGワードを指定
evil_words = {}
evil_words[0] = 's*x'
evil_words[1] = 'po**o'
evil_words[2] = 'v**lence'
:
-- excerptにNGワードが含まれていればspam
if excerpt then
  for key,value in pairs(evil_words) do
    if string.find(excerpt,tostring(value)) then
      is_spam = 1
      break
    end
  end
end
-- titleにNGワードが含まれていればspam
if is_spam == 0 and title then
  for key,value in pairs(evil_words) do
    if string.find(title,tostring(value)) then
      is_spam = 1
      break
    end
  end
end
if is_spam == 1 then
  dr = request["DOCUMENT_ROOT"]
  output_include = { dr .. "/spam.xml" }
  return CACHE_HIT
end
return CACHE_MISS

キーワードのメンテナンスが逐次必要となりますがphpモジュール側に組み込んでいるロジックと併せれば十分に負荷を減らすという目的は達成できると思います。

戻り値としてCACHE_HIT/CACHE_MISSを返すのはちょっと違和感があったのですが、mod_cml is dead, long live mod_cmlの記事を発見。たくさんのコメントがついていますが、僕的にはmod_logicが一番わかりやすいかな。

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/90

Comments