(new Soapbox())->shout(array_map('strtoupper', $opinions)); //Shaun's blog


Me, elsewhere

GitHub
parseword
Miscellaneous public code

Twitter
@parseword
I don't tweet much

XMPP chat
xmpp@shaunc.com
(Pidgin, Miranda, Swift, etc.)

SFSQuery, a PHP class to query the StopForumSpam API and DNSBL

Posted June 27, 2018 by shaun

If you have a web application that accepts any user input, you're probably dealing with spam bots. There's been a steady increase in automated spamming of blog comments, contact forms, order forms, and other types of interactive web resources. If they can post to it, they're trying to spam it, even in cases where it makes no sense, like submitting advertising pitches to API endpoints or search forms where no human will ever see the message.

Web spammers have been busy escalating and evolving. The adversary is no longer some guy in Elbonia running XRumer over his dial-up connection; these days you're likely to encounter dedicated and distributed web spamming networks. In these cases, the spammer spins up multiple VPSes at different providers, all communicating with one another as part of the spam operation. Often a recon visit will come from one IP address, followed immediately by several POST requests from other hosts in the spam network. This method attempts to fly under the radar of rate limiting and other anti-abuse tactics:

85.185.238.214 - - [25/Jun/2018:12:32:20 -0500] "GET /about/contact-us/ HTTP/1.1" 200 9439 on "-"
85.185.238.214 - - [25/Jun/2018:12:32:43 -0500] "POST /about/contact-us/ HTTP/1.1" 403 3384 on "-"
188.35.167.7 - - [25/Jun/2018:12:32:50 -0500] "POST /about/contact-us/ HTTP/1.0" 403 3384 on "-"
103.85.240.114 - - [25/Jun/2018:12:32:53 -0500] "POST /about/contact-us/ HTTP/1.1" 403 3384 on "-"

In the above log excerpt, you can see that a scouting bot showed up to verify that the "Contact Us" page was still there; over the following 10 seconds, that bot and two others tried to spam the form. Tried to being the operative term. All of the spam attempts resulted in a 403 Forbidden response and the messages were disregarded thanks to SFSQuery.

SFSQuery PHP Class

One effective way to mitigate web spam is to use a community-based blacklist of spammer IPs. There are several of these lists available, but StopForumSpam is my favorite because it's free, it's tailored specifically to web spam, and its large user base ensures that a lot of spammers get reported.

I created the SFSQuery PHP class to make checking StopForumSpam's database as easy as possible. You can call this class from any PHP script or application to help gauge whether or not an IP address is likely to belong to a spammer. The Github page has more thorough documentation, but the most basic implementation is via an anonymous object, like this:

<?php
require_once('SFSQuery.php');
use parseword\SFSQuery\SFSQuery;

if ((new SFSQuery($_SERVER['REMOTE_ADDR']))->wasReportedInPastDays(3)) {
    //Possible spammer, reject the action
    header('HTTP/1.1 403 Forbidden');
    echo "Sorry, you don't have access to this resource.";
    exit;
}
else {
    //Process the action
}

Or you can instantiate an SFSQuery object if you want to base your acceptance decision on multiple data points about an IP. This can help eliminate false positives:

<?php
require_once('SFSQuery.php');
use parseword\SFSQuery\SFSQuery;

$sfs = new SFSQuery($_SERVER['REMOTE_ADDR']);
if ($sfs->wasReportedInPastDays(30) && $sfs->getConfidence() > 25) {
    //Likely spammer, reject the action
    header('HTTP/1.1 403 Forbidden');
    echo "Sorry, you don't have access to this resource.";
    exit;
}
else {
    //Process the action
}

When querying StopForumSpam's web API, there are six data points available, all of which are exposed by SFSQuery:

  • appears: Whether or not the target IP appears in the StopForumSpam database
  • frequency: The number of times the IP has been reported as a spammer
  • lastSeen: The date and time that the IP was last reported as a spammer
  • confidence: A spammer confidence level from 0-100 calculated by StopForumSpam
  • country: The country to which the target IP is allocated
  • asn: The Autonomous System Number (ASN) that announces the target IP

I've recently added support for querying StopForumSpam's DNSBL as well as their web API. The DNSBL service is generally faster than the web API (smaller packets, no TCP overhead), and responses get cached by the DNS infrastructure which improves performance and reduces load. The downside is that DNSBL responses don't include the IP's country or ASN.

Check out SFSQuery on Github or SFSQuery on Packagist to start blocking spammers in your PHP script or application.



Recent articles

📰 SpamAssassin 3.4.2 fixes security problems, adds HashBL and phishing plugins

📰 Bug or turf war? ICQ via Pidgin now fails with "startOSCARSession: Request Timeout"

📰 🎂

📰 SFSQuery, a PHP class to query the StopForumSpam API and DNSBL

📰 Resolving portmaster error "pkg-static: automake-1.16.1 conflicts with automake-wrapper-20131203"

📰 Resolving LibreNMS error "RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths"

📰 1.1.1.1: Fast, but not so accurate (yet)

📰 autodiscover.xml as an Indicator of Attack

📰 Blocking Facebook's Tracking and Surveillance: A Comprehensive Approach

📰 Let's Encrypt Readies for Certificate Transparency with Embedded SCTs

📰 Evaluating DNSBL Effectiveness with Postfix Logs

📰 Resolving subversion error E145001: Node has unexpectedly changed kind

▲ Back to top | Permalink to this page