5 anti-spam measures for phpBB 3.0

This is an Eng­lish trans­la­tion of my Ger­man blog post. I up­dated it so the meas­ures de­scribed here are com­pat­ible to the latest phpBB 3.x ver­sion.

phpBB is an open-source forum soft­ware that is very pop­u­lar and widely used. This makes it an ideal tar­get for spam­mers. The phpBB de­velopers there­fore im­ple­men­ted an im­proved Captcha in ver­sion 3.0. But spam­mers have already ad­ap­ted to this and have im­ple­men­ted im­proved bots that are able to break the new Captcha and to auto­mat­ic­ally cre­ate junk posts. In the fol­low­ing I will de­scribe five anti-spam meas­ures that ef­fect­ively re­duce spam in every phpBB 3.x in­stance. The main goal of these meas­ures is to block as many spam posts as pos­sible without af­fect­ing nor­mal forum users.

Typ­ic­ally spam­mers try to ad­vert­ise cer­tain web­sites. About 95% of all spam posts con­tain links or URLs. The most ef­fect­ive way to block those posts is to com­pletely for­bid links. However, this would also af­fect nor­mal forum users.

Spam­mers usu­ally sign in to a forum and then im­me­di­ately start post­ing junk. We can make use of this and for­bid links only to guests and users with less than a cer­tain num­ber of posts. Once a nor­mal user has reached this num­ber of posts links will be en­abled. Typ­ical spam bots will never reach this num­ber since all their posts will be blocked.

To for­bid post­ing links you have to add the fol­low­ing to the func­tion submit_post() in the file includes\functions_posting.php.

//Define the minimum number of posts for "good" users
//Users below this threshold are considered potential spammers
$user_posts_threshold = 3;

//strip whitespace characters in the post body
$msgwows = $data['message'];
$msgwows = str_replace(" ", "", $msgwows);
$msgwows = str_replace("\n", "", $msgwows);
$msgwows = str_replace("\r", "", $msgwows);
$msgwows = str_replace("\t", "", $msgwows);

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, 'http://') !== FALSE ||
      strpos($msgwows, 'ftp://') !== FALSE ||
      strpos($msgwows, 'www.') !== FALSE ||
      strpos($msgwows, '[url') !== FALSE) {
    trigger_error("You are not allowed to post URLs!");
  }
}

This code should be put at the be­gin­ning of the submit_post() func­tion to check all posts be­fore they are saved to the data­base.

Measure #2: images

Spam­mers of­ten try to trick spam fil­ters by post­ing im­ages in­stead of text. They put their junk mes­sages and links into im­age files and then at­tach them to forum posts. You can use the same tech­nique as the one de­scribed in meas­ure #1 to block im­ages for guests and users with less than a cer­tain num­ber of posts. Put the fol­low­ing code in the func­tion submit_post() in the file functions/functions_posting.php.

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (strpos($msgwows, '[img') !== FALSE) {
    trigger_error("You are not allowed to post images!");
  }
}

Measure #3: Russian and Chinese posts?

A lot of spam posts are writ­ten in Rus­sian or Chinese or simply con­tain a lot of spe­cial char­ac­ters and garbage. If your forum is tar­geted to Eng­lish users you can check if a post is writ­ten in Eng­lish be­fore it is sub­mit­ted. Posts that mostly con­tain spe­cial char­ac­ters or for­eign char­ac­ters can then be treated as spam.

Cory Mawhorter has de­veloped a PHP funk­tion (is_english()) that is able to re­cog­nise spe­cial char­ac­ters. You can use this func­tion to dif­fer­en­ti­ate Eng­lish posts from any other.

if (!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) {
  if (!is_english($msgwows, 0.75)) {
    trigger_error("Only English posts are allowed here!");
  }
}

Measure #4: http:BL

Pro­ject Honey Pot of­fers an ef­fect­ive sys­tem to keep spam­mers and mail ad­dress har­vesters away from web­sites. http:BL matches the web­site vis­it­or’s IP ad­dress against a data­base. If the IP ad­dress is known to be used by a spam­mer the vis­itor will be blocked be­fore the web­site is even rendered. The sys­tem uses DNS which makes quer­ies very fast.

In or­der to use http:BL you first have to sign up for Pro­ject Honey Pot. You will re­ceive a spe­cial key that is used to au­then­tic­ate against the sys­tem. They already of­fer a MOD for phpBB but it is only com­pat­ible to ver­sion 2.0. You may be able to make it com­pat­ible to phpBB 3, but al­tern­at­ively you can simply put the fol­low­ing code at the end of the file common.php.

Up­date (2013-08-06): As Paul M. Ed­wards poin­ted out in the com­ments there is an up­dated http:BL MOD that sup­ports phpBB3: https://www.phpbb.com/customise/db/mod/advanced_block_mod/ Thank you very much, Paul!
//configure your http:BL Access Key here
$httpblkey = "xxxxxxxxxxx";
$httpblmaxdays = 21;
$httpblmaxthreat = 25;

//if you already configured a honey pot on your website use this line:
//$httpblhoneypot = "http://xxxxxxxxxxx";

function httpbl_check() {
  global $httpblkey, $httpblmaxdays, $httpblmaxthreat, $httpblhoneypot;

  $ip = $_SERVER["REMOTE_ADDR"];

  $result = explode(".", gethostbyname($httpblkey."."
    .implode(".", array_reverse(explode(".", $ip)))
    .".dnsbl.httpbl.org"));

  if ($result[0] != 127) {
    //something went wrong or the IP is not in the database.
    //ignore this one.
    return;
  }

  $days = $result[1];
  $threat = $result[2];

  if ($days < $httpblmaxdays && $threat > $httpblmaxthreat) {
    if ($httpblhoneypot) {
      header("HTTP/1.1 301 Moved Permanently");
      header("Location: ".$httpblhoneypot);
    }
    die();
  }
}
httpbl_check();

Please make sure to put your http:BL ac­cess key in the vari­able $httpblkey.

Measure #5: Akismet

An­other tech­nique to block In­ter­net spam is Akismet. This sys­tem is usu­ally used in Word­Press blogs to block com­ment spam­mers. Just like for Pro­ject Honey Pot you need to sign up to re­ceive an API key.

You can use Akismet to block posts in phpBB 3 for­ums as well. The sys­tem may pro­duce false pos­it­ives (nor­mal posts ac­ci­dent­ally iden­ti­fied as spam). I there­fore re­com­mend to only check the first posts of a new user un­til he or she has reached a cer­tain num­ber of posts. The fol­low­ing code uses the file Akismet.class.php that can be down­loaded from Alex Pot­sides’ Git­Hub re­pos­it­ory. Put the code in the func­tion submit_post() in the file includes/functions_posting.php.

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';

//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';

include('Akismet.class.php');

$akismet = new Akismet($akismet_url, $akismet_key);
if (!$user->data['is_registered'])
  $akismet->setCommentAuthor($username);
else
  $akismet->setCommentAuthor($user->data['username']);
$akismet->setCommentContent($data['message']);
$akismet->setUserIP($user->ip);
if ($user->data['is_registered'])
{
  $akismet->setCommentAuthorEmail(strtolower($user->data['user_email']));
  $akismet->setCommentAuthorURL(strtolower($user->data['user_website']));
}

if ((!$user->data['is_registered'] ||
    $user->data['user_posts'] < $user_posts_threshold) &&
    $akismet->isCommentSpam()) {
    trigger_error("Akismet says your post is spam");
}

Put your Akismet API key into the vari­able $akismet_key. The URL you entered dur­ing sign-up has to be put in the vari­able $akismet_url.

Akismet can also be used reas­on­ably to block spam­mers who try to sign up to your forum. Put the fol­low­ing code into the func­tion user_add() in the file includes/functions_user.php.

//configure your Akismet API key here
$akismet_key = 'xxxxxxxxxxx';

//the URL you entered when you registered for a Wordpress account
$akismet_url = 'xxxxxxxxxxx';

include('Akismet.class.php');

$akismet = new Akismet($akismet_url, $akismet_key);
$akismet->setCommentAuthor($username_clean);
$akismet->setUserIP($user->ip);
$akismet->SetCommentAuthorEmail(strtolower($user_row['user_email']));

if($akismet->isCommentSpam()) {
  trigger_error("Akismet says you are a spammer");
}

Conclusion

The meas­ures presen­ted here help drastic­ally re­duce spam in phpBB 3.0-based for­ums. Since I im­ple­men­ted them in the Spami­hil­ator forum a couple of years ago only a very small num­ber of spam­mers were ac­tu­ally able to post. However, none of their mes­sages con­tained links, URLs or im­ages. They mostly con­sisted of a num­ber of mean­ing­less and mot­ley words.

For­bid­ding links and im­ages is in my ex­per­i­ence the most ef­fect­ive way to block spam­mers. Search­ing for spe­cial char­ac­ters and for­eign lan­guages blocks all other spam posts that do not con­tain links or im­ages. Nor­mal users are typ­ic­ally not af­fected by these meas­ures. As soon as a nor­mal user reaches a cer­tain num­ber of ‘good’ posts the anti-spam meas­ures are dis­abled. Up to now, in the Spami­hil­ator forum no spam­mer was able to reach this limit. 3 or 5 posts is in my ex­per­i­ence a good threshold. If ever needed, this limit can eas­ily be raised.

Spam­mers of­ten try to put links and im­ages into sig­na­tures. I highly re­com­mend to dis­able this in phpB­B’s ad­min­is­tra­tion area. You may also try to ap­ply the link and im­age fil­ters from meas­ure #1 and #2 re­spect­ively to sig­na­tures.

Many phpBB for­ums plagued by spam­mers dis­able guest posts. Users have to be re­gistered to post. For sup­port for­ums like Spami­hil­at­or’s this can be te­di­ous for users who would like to eas­ily post sup­port re­quests without have to go through the com­plete sign-up pro­ced­ure. The meas­ures presen­ted here al­low forum ad­min­is­trat­ors to leave guest posts en­abled.


Posted by Michel Krämer
on March, 30th 2013.