How frustrating do you find it when hackers or robots fill in your website forms with "Buy Viagra Now!" type spam? Sometimes they can even trick your email system into sending the spam to your own customers! Wouldn't it be nice if we could catch them in the act and block them?

How to stop web form spam - use a simple honey pot trap in Modsecurity

I'm going to assume you have a basic version of ModSecurity in front of your web site, or if you are a Loadbalancer.org customer simply add a WAF gateway to your existing configuration:

waf2

Then simply add a manual configuration to the newly created gateway:
waf2

So, what exactly have we done here?

First of all, we need to make sure that ModSecurity is processing the traffic in both directions i.e. both the request and response traffic.

We also need to turn off compression so that we can read all the data and enable content injection (because we are going to be altering the web servers responses):

SecContentInjection On 
SecResponseBodyAccess On 
SecStreamOutBodyInspection On 
SecDisableBackendCompression On

Next, we are going to start tracking the source IP of all web site users:

# Start collecting the client IPs.
SecAction phase:1,nolog,pass,initcol:IP=%{REMOTE_ADDR},id:999010

Now for the clever bit. We are going to look for ANY page with a tag and then insert a hidden field.

SecRule STREAM_OUTPUT_BODY "@rsub s/<form><input type="hidden" name="debug" value="false"></form>" "id:'999009',phase:4,t:none,nolog,pass"

Now we can test if anyone alters this field, no valid user ever would, so we can block them and flag the IP for 60 seconds:

SecRule ARGS:debug "!@streq false" "id:'999011',phase:1,t:none,log,pass,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-CustomRule,msg:'HONEY POT TRIGGERED!',setvar:ip.malicious_client=1,expirevar:ip.malicious_client=60"

And for every subsequent page they try and access in that 60 second countdown, lets block them again...

SecRule IP:MALICIOUS_CLIENT "@gt 0" "id:'999012',phase:1,t:none,log,block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-CustomRule,msg:'HACKERS IP DETECTED'"

Obviously, you can play with the 60 seconds timeout, or send them to a fake web site - what ever takes your fancy.

But you can see how this could be a powerful addition to the security of your website.

So, how do we test our simple honey pot trap?

Just setup a test page index.html on the web server behind ModSecurity with any simple form such as:

<html>
    <body>
        <p>HONEY POT TRAP TEST</p>
        <form action="/index.html">
            First name:<br>
            <input type="text" name="firstname" value="Mickey">
            <br>
            Last name:<br>
            <input type="text" name="lastname" value="Mouse">
            <br><br>
            <input type="submit" value="Submit">
        </form>        
    </body>
</html>

Now in my example if I use a web browser to connect to this page through ModSecurity I can see the test form.
Then if I then click on submit it doesn't do anything apart from post the contents of the fields to itself.
You can see the posted fields in the URL as follows:

http://192.168.64.29/index.html?firstname=Mickey&amp;lastname=Mouse&amp;debug=false

Notice the new field that has been inserted by ModSecurity?
This is our honey pot trap, so if you change the value of that field, for example to:

http://192.168.64.29/index.html?firstname=Mickey&amp;lastname=Mouse&amp;debug=true

Then hit refresh, you will instantly get an error 403 message...

Forbidden

You don't have permission to access /index.html on this server.
You then won't be able to access ANY other pages on the site until the 60 second timer has expired.

I'm sure that you can see many potential uses for honey traps, please feel free to open a discussion about ideas and code by leaving a message in the comments section below:

SecContentInjection On 
SecResponseBodyAccess On 
SecStreamOutBodyInspection On 
SecDisableBackendCompression On

# Start collecting the client IPs.
SecAction phase:1,nolog,pass,initcol:IP=%{REMOTE_ADDR},id:999010
# Add the hidden debug field just before the last form tag
SecRule STREAM_OUTPUT_BODY "@rsub s/</form><input type="hidden" name="debug" value="false"></form>" "id:'999009',phase:4,t:none,nolog,pass"
# Check if the cookie gets changed from the default value of debug 
SecRule ARGS:debug "!@streq false" "id:'999011',phase:1,t:none,log,block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-CustomRule,msg:'HONEY POT TRIGGERED!',setvar:ip.malicious_client=1,expirevar:ip.malicious_client=60"
# Block any future requests from that IP for 60 seconds
SecRule IP:MALICIOUS_CLIENT "@gt 0" "id:'999012',phase:1,t:none,log,block,setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-CustomRule,msg:'HACKERS IP DETECTED'"

Got a question? Just let me know by leaving a comment below and I'll be happy to help.