loading...

How to create a simple Honeypot to protect your Forms against Spammers

felipperegazio profile image Felippe Regazio Updated on ・3 min read

I think this post will be short and useful. The goal here is to demonstrate a simple technique to help you block spammers and bots that could attack your website forms. This meant to be an extra layer in spam prevention, not the main resource to. Use it with another tools like reCaptcha, etc. Due its simplicity, i really recommend you to follow this form pattern, so, lets code:

Imagine you have the following form structure:

<form id="myformid" action="/myformaction">
    <label for="name">Your Name</label>
    <input type="text" id="name" name="name" placeholder="Your name here" required maxlength="100">
    <label for="email">Your E-mail</label>
    <input type="email" id="email" name="email" placeholder="Your e-mail here" required>
</form>

Most of simple bots will search form common patterns, like label common names, input id's, input common attributes, required fields, etc, and than the bot will fill 'em with fake info to try send you, and your customers, spams or some malicious codes. The most common fields to search are fields named like "email, phone, address"...

So, lets cheat on that and create a simple honeypot by changing our form structure to:


<style>
    .ohnohoney{
        opacity: 0;
        position: absolute;
        top: 0;
        left: 0;
        height: 0;
        width: 0;
        z-index: -1;
    }
</style>

<form id="myformid" action="/myformaction">
    <!-- Real fields -->
    <label for="nameaksljf">Your Name</label>
    <input type="text" id="nameksljf" name="nameksljf" placeholder="Your name here" required maxlength="100">
    <label for="emaillkjkl">Your E-mail</label>
    <input type="text" id="emaillkjkl" name="emaillkjkl" placeholder="Your e-mail here" required>
    <!-- H o n e y p o t -->
    <label class="ohnohoney" for="name"></label>
    <input class="ohnohoney" autocomplete="off" type="text" id="name" name="name" placeholder="Your name here">
    <label class="ohnohoney" for="email"></label>
    <input class="ohnohoney" autocomplete="off" type="email" id="email" name="email" placeholder="Your e-mail here">
</form>

Lets see the changes:

First we created a class to hide things. The .ohnohoney class. Important to point some things now:

  1. Dont use display:none, some bots cant access fields with display none, other simply know that they should'nt fill the display none fields. Dont use "hidden" in the class name, some advanced bots can recognize it.

  2. Than we created the "Real fields". This are the visible fields and the ones which must be relevant to your backend in terms of data. This fields must have the identifications changed to hashes. Commonly i use the pattern "nameHASH" all together. Dont use "name-hash" or variations of that, a simple split would expose the real field name. Now, a bot cant recognize what this fields are, they're just know that the form has some fields which must be filled, maybe following the "type" as pattern.

  3. By creating the "h o n e y p o t" fields we will be able to identify the Spammer. Important to: Let the label empty, use your 'ohnohoney' class to hide all those fake inputs. Turn your fake input the most simple, generic and attractive as possible. Use simple and common names as "email, phone, name, etc", disable the autocomplete (so, browser will not fill it), disable rules, but keep the types.

Now we have 2 parts in our form: Real fields with our inputs protected by hashes and strange names (you can implement the hash or strange names as you prefer). And our honeypot (dont write "honeypot", prefer split the letters to avoid any recognition). Now on your backend:

  1. Verify if any of the "h o n e y p o t" fields came filled. If yes, congrats, you trapped a spam. Most of them will fill all this fields without differentiate them. So, all you have to do is to check if any of your "h o n e y p o t" fields came filled, if yes, its a spam. If you prefer, you can do this check on the client, in case of an ajax form, this will avoid use server resources to compute unuseful data (but keep the backend validation anyway). When you catch a spam, just dont send the data and do whatever you want with it. If names as "email, phone, etc" are important to your backend, just transcript the names using arrays.

Here is a single-file repo with a simple implementation of this technique:
https://github.com/felippe-regazio/php-honeypot-example

Remember: this is just a simple layer to prevent attacks in a simple way, some technologies can identify even this patterns, so use all the weapons you can against it. But i believe that this simple pattern can avoid at least 50% of spams in your webpage.

Discussion

pic
Editor guide
Collapse
qm3ster profile image
Mihail Malo

Good job, now LastPass won't fill my form data into your site and you lost a customer.
I highly recommend no one do this.

Collapse
atif089 profile image
Atif Mohammed

If the functionality of LastPass on a webpage is the basis of your judgment on whether you purchase a product or not then maybe there is something questionable about your judgment criteria itself.

Collapse
felipperegazio profile image
Felippe Regazio Author

I understand your point, but i believe you can drive it to your needings, without lose a customer. If you want to integrate with last pass, for example, just keep the inputs you need and creating only one to use as honeypot (phone for example, i dont know), which is hidden, not required and not used by anything. One single input is enough to catch some spammers : )

Collapse
qm3ster profile image
Mihail Malo

Then LastPass will fill the invisible field, especially after the lengths you went through to make them hidden in a special way, not the conventional way.
It's basically the same thing as your bots 😄

Thread Thread
felipperegazio profile image
Felippe Regazio Author

so, what i mean is to you to use names that lastpass didnt use or adapt the core ideia on the post to your needings. last pass will not fill your entire form, and you can configure autofill on lastpass or use flags from their api like 'data-lpignore' which will tell the lastpass to not fill some fields. however, hope this to be useful to someone.

Collapse
digitalcake profile image
Josh Chernoff

Tells everyone to not do this but says nothing as a better opinion. Sure buddy I will totally follow your recommendation 🙄

Collapse
qm3ster profile image
Mihail Malo

Relying on normal spam protection that doesn't impact usability?

Collapse
danigirl329 profile image
Danielle Greaves

I think this is great. Question about accessibility: What is your opinion on using an aria attribute to hide this, so that screenreaders don't come across this and confuse users? Do you think bots are smart enough to recognize and skip this field altogether? Is there some sort of flag we could use instead?

Collapse
felipperegazio profile image
Felippe Regazio Author

Thats a great question Danielle. I think that the most configurations you add to the elements, the most hints you give to bots and spammers. So, we have to balance. Once we are talking about accessibility, there is no way to say no, we have to be careful.

Some alternatives i can think are:

Wrap the elements on a fieldset element that is aria-hidden and has . ohnohoney can be a good approach.

But, to tell you the truth, i dont see a problem with the aria. The "hidden" attr means hidden to everyone, but "aria-hidden" means hidden to screen readers and similar tools. I think the aria should not warm the technique cause bots should consider those elements too.

Would be cool to let a test running for a while. A form with aria and one without, and compare the spam incidence. If i was writing a bot, i would consider the aria-hidden inputs also, cause we never know the possible pages architectures, but im just guessing.

Sorry if my answer was not so complete as you could be expecting :/

Collapse
danigirl329 profile image
Danielle Greaves

No, I think it's a great thing to consider and have a discussion about. I'm just implementing something similar and thought it was something I should throw out there. Thanks!

Collapse
redrego profile image
red-rego

What if the bot checks for required field? in that case this would fail

Collapse
felipperegazio profile image
Felippe Regazio Author

thats true, and thats can be a good point to think about how to solve. i use this code in a lot of systems, and it works well for most of cases. but, with no doubt, it has a lot of lacks, as more complex bots would be able to submit the form. i like to think in it as an extra layer of security.

Collapse
willsheppard profile image
Will Sheppard

If you want to remove the "required" HTML keyword, you could use javascript to implement the feature instead.

Collapse
farbcafe profile image
das FarbCafé 💭von Instagram und Youtube

What do I have to add in the php to check, if the honeypots are filled?

I would like to add a honeypot to an existing form but I am just a php-noob.

Collapse
felipperegazio profile image
Felippe Regazio Author

Hello das FarbCafe.

I made this repository implementing a simple example of this techinique:
github.com/felippe-regazio/php-hon...

:)

Collapse
wutangpaul profile image
Paul McClean

type="emaillkjkl" ?

Collapse
felipperegazio profile image
Felippe Regazio Author

haha omg. fixed.

Collapse
wutangpaul profile image
Paul McClean

Was implementing some of your ideas this morning and noticed. Thanks for article!