9

I'm beginning to think this is not as simple as it looks, and many "accepted" answers here and in SO have alternative answers that criticize them. Here is what I have gathered so far

Most of what I gathered is from this SO question

Using IP - not accurate

For ex. in countries like Singapore there are limited number of ISPs and a smaller set of IPs which are available for home users

Also I think this is not effective in distributed brute force attacks

Using session cookie - easily to overcome, doesn't take long to erase a cookie and not effective in distributed brute force attacks

Using the username - exponential increasing timeout - can have workarounds

If I have a list of 1000 usernames, I'll try user1+password1, user2+pasword1, user3+password1... user1+password2, user2+password2

Using recapcha - good but you still need to know it's the same "user" (which can be doing a distributed attack, clearing their cookie, etc)

So I assume there is no perfect solution, but is there a considerably "good" solution approbed by any organization such as OWASP for handing throttling of failed login attempts?

1
  • The best is to reject weak passwords and have username based cooldown (e.g. showing the recapcha after the third failed attempt.) So even if an attacker runs a list of popular passwords against all your users, none of your users have a password on his list. If your user's have weak passwords, then a resourceful attacker can always find a way to hack some of them.
    – Eloff
    Jul 2, 2013 at 15:39

4 Answers 4

6

I once considered using approach similar to Merkle's Puzzles. For example you could require every login attempt to be signed with HMAC using one time key. For example server could prepare puzzle in following way: - seed (long random value), - r (random integer value within some arbitrary range), - key = PBKDF2(seed, r)

Than server could send following puzzle to the client: (seed, hash(key)). In order to get valid key, client would have to brute force this puzzle (check sequentially r values, compute PBKDF2 for given seed, compare its hash to hash(key) received from server). When client finds correct key, it uses it to sign one login attempt.

In this approach amount of work is asymmetrical between client and server (client has to do more calculations). Moreover, server can adjust the "work factor" changing the range from witch r value is selected.

Of course this scheme would not prevent password brute forcing, but it would increase cost of such an attack.

As I said it is only rough idea, I'm not sure how good it would work in practice.

1
  • IMHO this is the ultimate solution assuming there's something in the client which can provide the work (e.g., javascript enabled in the browser). From what I've found, the right term is not Merkle's Puzzles, but Proof of work. One interesting example is Hashcash.
    – maaartinus
    Jun 16, 2017 at 12:50
3

For protecting against brute force password breaking, you should use essentially what you term "Using the username - exponential increasing timeout". For each username, keep a count of failures since last successful logon and a time value for when another logon attempt will be permitted. Before checking the submitted password, compare the current time to the username's lockout-time. If the time has not yet occurred, prevent the logon request from proceeding. You could do this by delaying the request, but if too many of those delays (which occupy server resources) are permitted, you will be easily subject to DDOS attack. So instead reply with http status 429 Too Many Requests when the lock-out hasn't expired on the username. Each time a logon is allowed to proceed past this, and then the password fails, the username's fail count is incremented, and based on that the lockout time is set to the current time plus the exponential delay based on the fail count. A successful logon resets the fail count and lockout time.

The "workaround" you show isn't particularly a problem. Whether the list of 1000 usernames is tried sequentially or in parallel, each of the usernames will have its own lock-out time being kept, and after a few rounds for each, each will be preventing quick servicing of the brute forcing attempts.

2
  • 2
    No, the point is if I know 1000 usernames I can try X passwords for each, using a list of the most common passwords. I can also use such a list to guess usernames too. Given I have large enough lists of usernames or can try enough passwords, I'm guaranteed to gain access to some number of accounts, even if X is 5, and I can only make 5 guesses per username.
    – Eloff
    Jul 2, 2013 at 15:29
  • @Eloff: The point is, if you're doing a good job of protecting one user account independent of activity over time or other accounts, then you're doing a good job for all accounts through that mechanism. If your users set feeble passwords like "password", then gentle or brute force will be able to break them. The password is generally the user's responsibility, but if you want to force them to secure their account better, you need to prohibit the most common passwords (whether or not your server even tries to thwart brute forcing).
    – mgkrebbs
    Jul 3, 2013 at 21:52
2

By "throttle" I assume you mean you'll immediately display a webpage (with any amount of functionality) or a 5xx error right? (opposed to simply sending the login page more slowly .. with a sleep() timer)

Perhaps you can use a hybrid approach of positive and negative weights. I use this to manage email spam, and maybe some lessons learned can be shared here.

To start, track all the data you listed above for both successful and failed logins. Then and assign a "confidence level" ranging from positive 10 to negative 10 to each variable.

Then when the user attempts to login, you can simply calculate the ratio of successful logins to failed logins and weight it by confidence level (multiply). Sum the result and use that to determine the degree to which the session is throttled.

Note the browser thumbprint and setting a cookie on successful login, and for each login attempt may also be of use to you in this endeavor.

I'm sure that corporate desktops, general consumers, and international audiences would create very distinct profiles that would weight each value differently. I'd be interested in hearing more about your project, your thoughts, and what you end up doing.

P.S. Any time I do any calculations with a login page I make sure that I always use a fixed length of time for the calculation (500 ms). This will help prevent Cryptographic Oracles from creeping up that have historically plagued such pages.

P.P.S When making the login page make sure you don't block threads with Delay operations (such as sleep()), or else this will DDOS your server quickly. Alternatively, return some HTML or 500 error to the affected user.

4
  • Hm... interesting, I wonder why not do a sleep() timer than, is it simply because it will kill my threadpool on a DDOS?
    – Eran Medan
    Nov 22, 2012 at 3:52
  • I'm an IIS/.NET developer and your profile mentions you do Java... so I can't speak to that or Tomcat. However, yes using Sleep() for extended periods can cause issues with the threadpool and DDOS the server. Imagine the additional threads that will be used in the Database calls to read and write the data that will be collected (IP, headers, etc.) Perhaps the .NET TPL can be used to make this better... Nov 22, 2012 at 5:41
  • Thanks, Used to be a sworn .NET guy, but I have long ago converted to Java, (then to Scala) but thanks to things like TypeScript, F# etc, I'm starting to think checking back the other side...
    – Eran Medan
    Nov 22, 2012 at 6:54
  • 1
    Related, just for kicks you should check out TPL... it makes Async IO so easy and easy to read. It handles both APM and event based Async (works well with ASP/IIS). Just a teaser to come back to the .NET side. Nov 22, 2012 at 14:48
1

I'm using an OTP - means my logins are based on three distinct keys :

  • username
  • password
  • OTP (One-time-password) provided by yubikeys.

I've also added, for one app, a counter - if X failed logins happen in a given interval, it :

  • redirects to some error page (forcing people to click on some link for the login - useless for bots)
  • blocks the account after several attempts.

The block may be based on the remote IP in order to prevent false-positive.

1
  • Could you explain the reasoning behind your technique?
    – user10211
    Nov 22, 2012 at 15:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .