DEV Community

Cover image for Create honeypot against spam bots in Rails
marelons1337
marelons1337

Posted on • Originally published at blog.rafaljaroszewicz.com

2 1

Create honeypot against spam bots in Rails

google recaptcha in it's prime

I was trying to implement something that is less annoying than google recaptcha. Everyone knows that it's quite exhausting for some users. Also I would like to reduce the amount of requests made to google with all gtags, analytics, ads etc. are already slowing the whole internet down.

I found this very old article on how to stop those simpliest bots(in the app I am working on most of the spam came from these basic crawler/spammer types) using a honeypot technique.

Basically whole idea behind honeypot is that you can add some fields to the form that are not visible to the user, but if those simple bots scraping your website will see them, they would probably fill them out.

This article inspired me to try it with a little twist, and here's how it went.

Of course this will be of no use against real human spammers. So you should probably also invest in Akismet.




Let's add some of these strategies mentioned in the article into the controller that is responsible for creating Posts.
before_action :check_honeypot, only: [:create]
private def check_honeypot
time = Time.now.to_i
if params[:status]
timer = params[:status].to_i/123321 # clarify time
else
timer = 0
end
time_reached = time - timer < 5
if time_reached || params[:street_name].present?
logger.info("spam forbidden !!! params[:street_name]: #{params[:street_name]} (timer): #{time - timer} ")
return render :js => "alert('#{tt('post.spam_timer')}');", status: :ok
end
end



# clarify time will make more sense later on. I am using regular names like status and street_name for my trap fields, they will be invisible to the user anyway, but bots might have a list of fields to fill out.

Notice how I send status: :ok when the alert is shown(means it got caught either by timer or by filling the field that should be empty). So for normal human being nothing will really change, but bot will see response 200 OK meaning that he was successful in his posting and will move on.

You should also consider adding blocking IP's after certain amount of tries within short period of time. I have noticed that these bots usually send hundreds of requests/sec, so these should be relatively easy to catch.

You can easily test it as well.

test 'honeypot against bots' do
# street_name not empty
assert_difference 'Post.count', 0 do
post :create, params: { post: { title: 'new title', content: 'new content' }, street_name:"spam"}
end
# form filled in under 5 seconds
time = Time.now.to_i*123321
travel 1.second do
assert_difference 'Post.count', 0 do
post :create, params: { post: { title: 'new title', content: 'new content' }, status: time}
end
end
end



Now, let's create a partial that will be used in our views for rendering this honeypot using <%= render 'posts/honeypot' %> later on.
<%
def css_strategy
[
"display:none;",
"position:absolute!important;top:-9999px;left:-9999px;background-color:#ffff;border-color:#ffff;",
"position:absolute!important;bottom:0;height:0.01px;width:0.01px;overflow:hidden;background-color:#ffff;border-color:#ffff;"
].sample
end
%>
<div id="general-ackbar">
<input type="text" name="street_name" autocomplete="nope" tabindex="-1" style=<%=css_strategy%>>
<input readonly type="text" id="status" name="status" autocomplete="nope" tabindex="-1" class="" style=<%=css_strategy%> value="<%=Time.now.to_i*123321%>">
</div>



#general-ackbar { display: none;} will hide out our div, but I am still using css_strategy to change it as I assume some bots might read css and just ignore some of the fields if they're for example hidden. These are just some ways to obfuscate your fields.

Now, I also obfuscate the time so I can check it once it gets back to the server. In the previous gist you saw that timer is set to 5 seconds.

This can be just changed to any number, just try to fill out your form as fast as you can and then add this time as a value under which you will display the alert.




To summarize, this method will not protect against any advanced bots and human spammers, but it might help you fight those basic robots.

You might also want to add blocking IP's that are sending too many requests and other anti-spam tools.

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay