Spamproofing for Jot
There are comment spamming robots that can get around Captcha mechanisms. This MODx Evolution snippet demonstrates a way to use the Project Honey Pot blacklist to further protect Jot input forms against known comment spammers. The blacklist is constantly updated by the robots themselves when they post to dummy guestbooks and blogs. It can be queried by submitting a suspect IP address in a specific format.
You need to contribute a honeypot to the project to obtain an API key for the blacklist. If you have a blog page or guestbook that is plagued by spammers, it is an ideal candidate for donation. Set up a honey pot at that address, and move your active page to a new URL. The Project Honey Pot site provides full details on setting up a trap and obtaining an API key.
Contents |
A simple manual switch
Before going into the details of IP address checking using the blacklist, an even simpler technique to prevent comment spam is to switch off the comments on old items! The Jot comments part of my "single post" blog item template originally looked like this:
[!Jot? &subscribe=`0` &pagination=`25` &sortby=`createdon:a` &numdir=`0`
&placeholders=`1` &output=`0` &canmoderate=`bloggers` &captcha=`1`
&validate=`name:Name is required,content:You have not entered any comment!`
¬ify=`2` &badwords=`{{blogBadwordList}}` &bw=`1`!]
<div id="blogComment">
<h4 id="blogCommentTop">Comments ([!Jot?&action=`count-comments`!])</h4>
[+jot.html.comments+]
[+jot.html.form+]
</div>
To preserve existing comments and add a "comments closed" line that can be activated manually, a radio options TV called "comments" was added:
Template Variable Name: comments Input Type: Radio Options Input Option Values: On==[+jot.html.form+]||Off==(Comments closed) Default Value: [+jot.html.form+]
With [*comments*] instead of the placeholder [+jot.html.form+], you can now disable comments on ancient posts at a time of your choosing, while preserving the comments added so far. The snippet assumes you have created a TV like this.
Querying the blacklist
In order to check whether a visitor has been logged as a comment spammer, you use the PHP gethostbyname() function with an argument made up from your API key, the IP address you want to check and the address of the blacklist (dnsbl.httpbl.org). This is all explained on the project site, and is dealt with by the snippet. The site returns a result in IP address format, with 127 as the first element if the lookup has been a hit. The remaining three elements represent:
- age: number of days since the IP was last logged (0-255)
- threat: a logarithmic value estimating the spam activity level (0-255)
- type: a "bitset" with binary digits indicating type of activity:
- 0 = search engine
- 1 = suspicious activity
- 2 = address harvester
- 4 = comment spammer
Most comment spammers come back as 5 (1+4 = suspicious + comment spammer)
The BlCheck snippet
The snippet is called BlCheck. It uses a function defined in a separate file, allowing for use by other snippets and for future expansion. The PHP file containing the function is called checkpoint.functions.php, and is stored in the folder /assets/snippets/checkpoint. (There's a link to a Zip download for both files at the foot of this page).
BlCheck snippet
<?php // BlCheck // check IP address of visitor or querystring IP against Project Honeypot blacklist return 'You must set the key!'; } include_once $modx->config['base_path'] . 'assets/snippets/checkpoint/checkpoint.functions.php'; $ip = $_SERVER['REMOTE_ADDR']; } else { $ip = $_GET['ip']; } } if (checkDnsBl($apiKey, $ip, $threshold, $age, $type) === FALSE) { $output = $modx->getTemplateVar($comments); $output = $output['value']; } else { $output = $banned; } return $output; ?>
checkpoint.functions.php
<?php function checkDnsBl($key, $addr, $threat=10, $age=90, $type=4) { // check IP of visitor against httpl.org database // return True if lookup identifies a bad guy, else False global $modx; $lookUp = $key . '.'; $lookUp .= '.dnsbl.httpbl.org'; $modx->setPlaceholder('blResult', $result); if ($valid == 127) { $output = ( $blAge <= $age && $blThreat >= $threat && ($blType & $type) != 0); } else { $output = FALSE; } return $output; } ?>
Snippet call
The snippet call replaces the original Jot form placeholder in the template
<div id="blogComment"> <h4 id="blogCommentTop">Comments ([!Jot?&action=`count-comments`!])</h4> [+jot.html.comments+] [!BlCheck?apiKey=`--your_api_code--` &comments=`comments` &banned=`blacklisted.tpl` !] </div>
Parameters
| Parameter | Usage | Notes |
|---|---|---|
| &apiKey | your Project Honeypot API key | (required) |
| &comments | TV specifying Jot input form placeholder or "comments closed" message | (required)
(edit snippet lines 25-26 if you don't want to use the TV) |
| &threshold | threat level at which to disallow comments | default: 10 |
| &age | timeframe in days to consider spammer as "active" | default: 90 days |
| &type | kind of activity you want to ban | default: 5 (suspect behaviour or comment spamming) |
| &banned | chunk containing message to show when comments are not allowed to this visitor | default: "Comments closed (BL)" |
| &ip | IP address to check (for tests). You can also submit an IP in URL as ?ip=N.N.N.N for tests | default: current visitor's IP address |
Limitations, expansions, tips
- the main function has been kept in a separate file with the intention of expanding options to include using other blacklists, such as Akismet or Mollom
- if you don't want to use the TV to manually disable comments, adjust lines 25-26 of the snippet, e.g. replace with
$output = '[+jot.html.form+]';
- you could replace line 28 of the snippet to issue a 403 (access denied) header instead of the blog post. This would require some output buffering so the header is the first thing you send.
- the placeholder set in line 12 of the function is for testing - you can see what the blacklist is returning by using the placeholder in your output chunk
- if your site will have heavy traffic, you'll need some way to avoid too many calls to the blacklist database, such as cookies for OK visitors and a short-term local database to check first
- if a spammer with a particular IP address keeps coming back, you can ban them from the site using a line in .htaccess reading Deny from N.N.N.N
- Disallowing links in comments by adding http to Jot's &badwords list is quite effective at keeping spammers' comments from publication
Links
==> File:BlCheck.zip download PHP snippet and function files
==> Jot main page