Block comment spam with bcSpamBlock

A while ago I installed Paul Butler’s JSSpamBlock on my WordPress blog here. His original idea is simple and brilliant: Spambots don’t (yet) execute Javascript. In fact, they usually post directly to the form without even displaying the form first. By having a hidden input field that is populated by javascript, you can verify that users are hitting the page without the user even noticing. For users with JavaScript disabled (are there any of you out there), they simply have to copy/paste a small string into a textbox for verification.

Since implementing a slightly modified version of it on this blog, I have gotten zero spam posts. Now, I wanted some way to implement the same logic on some of my own custom PHP sites to prevent spam on them as well.

While working on a way to re-implement Paul’s WordPress plugin in my own sites, I came up with something pretty clever. Instead of saving a row to a database every time that the form is displayed, you can use a little cryptography to make the client pass all of the data needed to validate the request back to you on its own. The idea is sortof merger between the JSSpamBlock plugin and TCP Syncookies, which use a similar method of having the client store the data for you.

Essentially, how it works, is that the function generates a Random ID. It then encrypts the current timestamp and the random ID using PHP’s crypt() function with some cryptographic salt that is unique to each server. All three of those values (the random ID, the timestamp, and the encrypted value) are then passed to the browser. The timestamp and the encrypted value are stored in hidden <input> fields, while the random ID displayed for the user to verification. If the user has JavaScript enabled, a few lines of JavaScript copy the random ID into another textbox, and then hide that prompt, so that it is never seen by the user. If the user doesn’t have JavaScript enabled, the would have to copy/paste that random ID into the textbox themselves, similar to a captcha.

When the form is submitted, it checks to make sure that the timestamp is not too old, and then re-encrypts the passed in timestamp and random ID using the same salt value to make sure it matches the crypted value passed in from the form. If everything matches, the comment is approved, otherwise an error is displayed to the user.

I wrote this up into a simple include file that can be used for any PHP application. I also implemented a quick WordPress plugin that uses the generic version. More information about it can be found on my new bcSpamBlock home page

25 thoughts on “Block comment spam with bcSpamBlock”

  1. Just so you know, although bcSpamBlock works effectively at blocking spam comments I realized today that it’s been blocking every trackback that’s been sent to my various posts. I found out about this when incoming links were shown in my WP 2.3.1 dashboard from both Google’s blog search and Technorati.

    I tested thoroughly using my WordPress.com blog to send trackbacks to my custom install WP blog and with bcSpamBlocker activated, the trackbacks never showed up. With it deactivated all trackbacks came through okay.

    Thought you might want to know.

  2. just modify with a add_filter to avoid trackback/pingback block:

    function bc_checkfilter($content)
    {
    //not deal with trackback or pingback
    if ( $content[‘comment_type’] == ‘trackback’ || $content[‘comment_type’$
    if (bcspamblock_verify()) return $content;
    die(‘Your trackback has been rejected.’);
    }
    // Actions
    if(function_exists(‘add_action’)){
    add_action(‘comment_form’, ‘bcspamblock_doform’);
    //add_action(‘comment_post’, ‘bcspamblock_checkcomment’);
    }
    if(function_exists(‘add_filter’)){
    add_filter(‘preprocess_comment’,’bc_checkfilter’,2,1);
    }

  3. sorry, mis-copyinig.

    function bc_checkfilter($content)
    {
    //not deal with trackback or pingback
    if ( $content[‘comment_type’] == ‘trackback’ || $content[‘comment_type’]==’pingback’) return $content;
    if (bcspamblock_verify()) return $content;
    die(‘Your trackback has been rejected.’);
    }
    // Actions
    if(function_exists(‘add_action’)){
    add_action(‘comment_form’, ‘bcspamblock_doform’);
    //add_action(‘comment_post’, ‘bcspamblock_checkcomment’);
    }
    if(function_exists(‘add_filter’)){
    add_filter(‘preprocess_comment’,’bc_checkfilter’,2,1);
    }

  4. Thanks wlx. I have made those same changes on my own blog here and test for a day or two before committing the changes to the official wordpress plugin.

  5. hi,

    thanks, works great.

    Im using it in a custom php script.

    however, the comment in line 37 should be:
    if(! bcspamblock_verify()) {

    not:
    if(! bcspamblock_validate()) {

    regards
    lt

  6. hi,

    thanks, works great.

    Im using it in a custom php script.

    however, line 37 should be:
    if(! bcspamblock_verify()) {

    not:
    if(! bcspamblock_validate()) {

    regards
    lt

  7. This is a great approach in principle, and should be sufficient to block any automated bot. But, there appears to be a vulnerability in that the salt value is actually appended to the front of the bcspamblock_hidden field. On the demo page it’s $1$77dbddc7$

    This means that a malicious user could theoretically generate a new bcspamblock_hidden field using the current time, and therefore avoid being timed out.

    Before sending the bcspamblock_hidden field to the output page, remove the seed from the front of it

    substr(bcspamblock_hidden,CRYPT_SALT_LENGTH)

    and then compare only the appropriate characters in the validate function.

  8. Pingback: LiangXu Wang
  9. Just to let you know that I’ve discovered a problem. In version 1.3 bcspamblock stops any trackbacks and pingbacks from reaching the site.. I’ve now tested this on three of my sites.
    All of them are hosted with Dreamhost so perhaps this is related to their setup in case you haven’t heard anyone else having the same issue.

    For now necessarily I’ve disabled the plugin

  10. I’ve noticed different behaviour since wordpress 2.7 update – even if user is logged (as admin), sometimes comments are held for moderation. a bit annoying

  11. I did notice a problem when adding/editing comments from the admin screens in WP 2.7. I’ve changed the code to automatically approve comments if logged in to wordpress as an administrator. I have just committed a new version to the wordpress plugin repository.

  12. @Siegfried, I do see that behavior with my blog and never noticed that it wasn’t functioning as intended. I don’ t think that bcspamblock is causing it though. The function that checks the validation either returns the comment as-is or dies with an error message. I don’t see how that could cause it to be flagged for moderation.

  13. This plugin works fantastically, it does need an update however, I cannot post from the admin screen as I “fail the security check” or whatever. Could you please fix this?

  14. I had trouble finding a plugin that would work with a theme I recently purchased that had a custom comment form and didn’t use the comment_form() function. I had all but given up. Then I found your plugin, bcSpamBlock. It appears to run flawlessly with my comment form despite not being updated in years, and has stopped SPAM completely (100%) so far. The particular theme I purchased has a thousand or more of purchases and I posted a link to your website/plugin in the support area for this theme. You might notice a big increase in downloads.

    I just want to thank you for this plugin, and to let you know about the possible increase in downloads.

    Thanks!
    Chris

Leave a Reply

Your email address will not be published. Required fields are marked *