Credential Stuffing Attacks and Protection for web frameworks (examples with Django)

Password Reusing..

So here we are talking about attackers knowing users passwords because they were breached in another website or system, and users were password-reusing, which is a horrible horrible practice. This is NOT about brute-forcing, this is NOT about easy/hard passwords. A user’s password might be the highest entropy password of the world, but if it has leaked in one system and user has used the same strong password in your system, now you are part of the problem.

Rating the solutions

Photo by Jack B on Unsplash


0. The dummy solution

Deleting all your database.

1. The easy solution! — Two Factor Authentication (2FA)

This is a very simple solution to grasp, everyone who signs up to your website should setup a 2FA besides their email and password. There are several solutions for this category, for example you can send an 8-digit SMS code on signup/login, or you can ask them to setup google authenticator.

2. The solution that doesn’t work — IP Rate-Limiting

One possible solution could’ve been limiting login attempts per IP, you can say an IP can only try 5 login attempts on a day. Why this doesn’t work? Because such attacks are orchestrated by bot-nets, so millions of IPs. If you allow them 5 accounts each, you are already in trouble. Another downside is there are many valid usecases where a single IP brings a lot of traffic/users to your website, it might be a university campus or a company office or your company’s office, etc. So while this solution does not work it also hinders valid use-cases.

3. The great tech (Facebook) Solution

If you have a huge team, do what Facebook does. In case you detect an unusual login, based on the unusualness level, ask for a login challenge. In case you are not familiar with this, if you login to Facebook from a new browser / IP or location, it pops up a quiz for you. In this quiz you have to name your friends from existing pictures of them on the platform. This kind of proves you are you. This is a simple task for you but a heroic challenge to anyone outside of your friend circle. A brilliant solution indeed.

4. Going forward solution —

I love this solution and it should be in the books of web development 101, right after the “Never store plain-text passwords” section. The solution is not to accept any password that was ever leaked and can be found online. That’s not an easy check, but thank god Troy Hunt went through the hassle to unify all the leaks so we can just query by password. This is an achievement of humanity, collective data and internet.

5. Deactivate Dormant Accounts with Pseudo 2FA — My Optimal Solution

As I mentioned if you are running an established website, the chances are the most of your database has been filled older than 1 year ago and most of your users are inactive or dormant, as I call it here. This segment is most susceptible ones to credential stuffing attacks. So my solution was to mark each user that hasn’t been on the website for 6 months as “dormant”, and apply special logic on login. This way the solution is completely transparent to the active and new users, while satisfying a pretty high A (Effectiveness). It’s very unlikely that a user suddenly comes back to the website after 6 months of total silence. But of course it can happen if you have millions of users. That’s why deleting old accounts is not the best solution, we have to do something a bit more complex.


My conclusion is that I’m glad to have met this problem and some possible solutions. This should make the internet a safer place for sure. Even if you don’t use the solutions I provide, it’s a good practice to think about the attack vectors and the UX. Maybe we together will come up with a new standard that will solve the credential stuffing attacks for good.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store