I’ve found two easy ways to stop bots from signing up and infiltrating a freshly pressed web site. If you’ve got no advanced IP (Geo/blacklist) filtering or email address spam checking built into your web-app, you should at least be throttling or hindering bot efforts using the tooling you’ve got at hand – your web programming framework. It doesn’t matter if you’ve got a wordpress, drupal, or python web site – there are tools and configuration settings you can still make to protect yourself.
From Multiple Attempts per Day to Radio Silence
Here’s the scenario, a python django site is visited by bots, daily, and then more than daily. You see the account signups, then you see an immediate attempt to try a login.
Enforce Email Verification!
I employed one quick trick to ensure that this automated bot never succeeds to the point of login. Not to say that bots won’t become smarter in the future, but this particular one doesn’t know how to check their email! You see, I enforce email verification. My site is e-commerce, so i’d like to have a firm(er) handle on exactly who is turning over a credit card for services I provide. From a liability standpoint, this reduces abuse of site services with stolen credit cards, from a customer service perspective, I’d rather not have to enter into any dispute management with Stripe payments.
Damage done though…
So the fact is that these bots have already bypassed one protection, and have infiltrated my site to the point of account generation. The first protection, which is completely required, is the CSRF token that accompanies every form. This means that the old style of blast-away scripts have to be interupted, and they must actually “render” the page and form to get the CSRF token, to then turn around and submit with their username/password/email form payload. Now there’s a little overhead for these script0rs. and a minor slowdown factor has been introduced to their method of attack. Not enough.
The way our site is integrated with Stripe payments, a sign-up results in a syncronised account with Stripe. This happens at the point of signup, but before confirmation. After all, they need to handle the PII (personally identifiable information), not us (we really don’t want to hold your credit card details!!). So every signup resulted in an overhead of creating accounts at Stripe.
We’ve had to manually delete these accounts from our Stripe account, and our internal Django userbase. Let’s not leave any possible options open for a return visit by a more curious and interactive attacker.
Time to go into “delete” mode!
How did we find the bots?
- Their signup-to-login attempts are rapid-fire, a human user at this site would be advised to check their inbox, and require a physical press of the back button to navigate to the forms, several seconds of work and a distinct movement pattern through the views of the site.
- A normal NORMAL user would wait for the email at their inbox.
- The email addresses are research able at several spam listing sites
- Sometimes the automated emails sent outbound are rejected or blacklisted by our SMTP mailer provider. We watch all return mail.
- Similar patterns in the attempted username FirstcapitalizerealwordThr (3ee letters pattern)
- All manner of other logs related to the HTTP processing
Stop the bots even before the point of sign-up.
Add recaptcha to Django-User-Accounts. Bots can’t stand it.
Please. Do it. The code is so very easy to add, either to static web pages, or to web frameworks.
The following defensive procedure was tested on python 3.6 django 2.2 and Pinax Django User Accounts 2.1.0
cli pypi package
pip install django-recaptcha
##OVERRIDE url(r"^signup/$", SignupView.as_view(), name="account_signup"), path("account/signup/", views.SignupView.as_view(), name="account_signup"), ##BASELINE (original) path("account/", include("account.urls")),
class SignupView(account.views.SignupView): form_class = forms.SignupForm
class SignupForm(account.forms.SignupForm): captcha = ReCaptchaField(label="",widget=ReCaptchaV2Checkbox)
RECAPTCHA_PUBLIC_KEY = "something" RECAPTCHA_PRIVATE_KEY = "somethingprivate" INSTALLED_APPS = [ … "captcha", ….