27

With arguments expressed in this answer, there is a few seconds delay between user enters an incorrect password and when he/she actually learns, that password was incorrect. This security solution is implemented in an operating system (here an elementary OS) and in console commands like sudo etc.

Should I implement the same mechanism in my website or web service? Or may I easily assume, that a typical delays in exchanging information between browser and server will be enough to block bloated brute-force attacts (in takes more than one second even on local system between pushing Login button on my site until an information about an incorrect password is returned; this seems enough long AFAIK).

There is a similar question on this matter. However, both answers (this and this) are not satisfying my question or are even a bit off-topic. I'm not asking about suspension or temporal locking of user account after each failed login (and thus arguments about locking attacker preventing real user from login are off). I'm talking only about possible delay between displaying login form again.

6
  • 3
    Adding a short, random delay may also keeps you from string comparison timing attacks Jul 20, 2015 at 7:44
  • Probably I'm misunderstanding: elementary OS?
    – muru
    Jul 20, 2015 at 12:45
  • 1
    @trejder ah, sorry. Shame on me for not checking what "operating system" linked to, and the article an before elementary compounded my confusion.
    – muru
    Jul 20, 2015 at 12:52
  • 5
    @WhiteWinterWolf: The post you linked to says the opposite. With enough requests, the randomness will be ironed out. Much better to always make your response after a set number of seconds (e.g. processing + artificial delay = 3s). Also see Could a random sleep prevent timing attacks?. Jul 20, 2015 at 18:31
  • 1
    @SilverlightFox: AFAIK the post I linked do not mentions adding a random delay on server side, it only deals with the delay caused by network latency. However, thank you for your link which is very informative and explains the need of constant time string comparison functions to correctly address such threat, even if as Jeremy French commented in my first linked post we may finally be dealing here with just a few CPU cycles, so a timing hardly exploitable through the Internet which would need some LAN access to begin becoming usable. Jul 21, 2015 at 8:48

4 Answers 4

40

I assume that your intention with the failure delay is to prevent brute force attacks: if an attacker is trying to guess a user's password, she will first fail many times; if we can make those failures take a substantial amount of time longer, then it will make the attack an order of magnitude harder, and thus unlikely to succeed (in a reasonable time frame).

However.

This assumes that the attacker waits patiently between login attempts. And, as we all know, cyberhackers are a very polite and patient folk.

That said, some attackers may choose NOT to wait, and simply send many requests in parallel. If a login attempt doesn't receive a response immediately, the attacker can interpret that as a failed attempt, kill that request, and move on the next one.

An extra benefit of this scheme is that it would be that much easier for an attacker to create unreasonable load on the server (just send a lot of failing login requests, each one will occupy a thread for several seconds...), and possibly even succeed in DoSing the server.

In fact, the main problem with this solution is that it precisely does NOT prevent many parallel requests. If an attacker is attempting an online brute force attack, she is not going to sit in front of the keyboard typing in many passwords, one after the other, as fast as Hugh Jackman possibly can - if that was the case, you would only be at risk if the user has a dead simple password.

In reality, she will have a script or automated tool send (almost) as many requests as the server can handle, and then keep going. The risk is not that someone will try 30 different passwords a minute, it's 1000 passwords a minute, or 10,000.

The only way to prevent that is user throttling / account lockout / incremental suspension - call it what you will, this is all basically the same idea of allowing X number of login attempts per account within a given timeframe.

So even though this doesn't cut down to "a single login attempt at a time", it does get close enough.

9
  • 2
    Great answer, thank! A side question. Why "she"? You don't like girls and that's why you claim, that most hackers are women or is this some kind of English form, that I don't know (I'm not a native English speaker)? :>
    – trejder
    Jul 20, 2015 at 8:08
  • 18
    @trejder Heh. Quite the opposite, often guys just use "he" all the time, as if women are not capable of hacking, or as if some of the top people in the field aren't women... Anyway, often in crypto stories (e.g. "Alice wants to send a message to Bob") the intruder is either "Eve" or "Mallory" - so I usually tend to go with those :-)
    – AviD
    Jul 20, 2015 at 8:11
  • 3
    there's a problem with account lockout if the attacker tries 5 passwords and then tries another 5 on a different username. you have to lock them out of everything.
    – Jasen
    Jul 20, 2015 at 12:13
  • 3
    Doing account lockout properly does entail a short timed lockout, i.e. automatically releasing the account after some X number of minutes. And, in the case of the attacker that keeps trying to lockout many accounts (or the same account over and over again) - here is where you need to get fuzzy, and maybe implement a "gray list". I.e. usually not a great idea to lock by IP, but sometimes you need to, or maybe you slow that specific IP down some more. Point is that if an IP is doing so many failed logins - that IP needs some "special" attention.
    – AviD
    Jul 20, 2015 at 12:42
  • 1
    @trejder Most refinements have further workarounds but you can do things like also tracking requests per IP and after ,say, locking out 2 accounts for 5 minutes each lock out the IP for longer. Of course someone with a lot of IP's or running on IP 6 will cycle between them etc. You want the lockouts to be short in human terms but long in machine terms, a few minutes or so. As long ad you avoid permanent lockouts or long term lockouts, they're nothing but a pain in the ass.
    – Murphy
    Jul 20, 2015 at 18:20
8

Part of the problem is that keeping the connection open while you wait for the delay to expire uses precious resources, particularly under certain popular configurations where the number of simultaneous connections allowed is pretty minimal.

An ideal solution is to architect your system as follows:

  • Design the logic first into the UI. A failed login returns the failure status immediately, but there's a delay before the UI resets to allow an additional login attempt. This isn't to enforce the rule, but rather to ensure that the a well-behaved user never sees an error message.

  • Enforce the logic on the backend by immediately returning an error status for any login attempts during the "cool-down" period. Don't even check to see if the password was correct, just fail immediately while consuming as few resources as possible.

  • To test to see whether a login attempt is allowed yet, the best solution is to use something lightweight, like memcached. For example, after a failed attempt with a given username, store in memcached the time that the cool-down expires. Then, when fielding new password attempts, check the entry in memcached to see if the cool-down period is up yet.

  • Enforce the same logic on a per-IP basis, not just per username basis. I shouldn't be able to guess thousands of passwords a second just by rotating through usernames.

  • Implement an exponential backoff. This is a bit of extra credit, but 2 attempts in 1 second isn't a big deal, but 50 attempts in 5 minutes is a big problem. This may be a bit harder to design, but repeated failures should trigger longer reset times. This could be as simple as keeping a failure counter (again, in memcached) and calculating the next cool-off as a function of that counter. The per-IP logic would have to be a bit different, though, since you don't want the attacker to be able to reset his counter just by sending a known user's credentials.

5
  • memcached may not be the best option as an script could easily rotate through usernames and or IP address to fill up your memcache. Jul 21, 2015 at 11:58
  • @IanRingrose most installations don't have enough users for that to be possible. Those that do probably don't need this sort of advice.
    – tylerl
    Jul 21, 2015 at 14:30
  • I would at least prefill memcached with a last logon attempt of -1 for all users at startup time. Jul 21, 2015 at 14:52
  • @IanRingrose AS_DESIGNED
    – tylerl
    Jul 21, 2015 at 16:31
  • 1
    @tylerl well put, however the only problem I have with this is the consideration for IPs. The problem with that is often IPs are not used by a single user - corporate proxies, shared IPs, rotating DHCP for some dialups, heck some ISPs even use NAT for their users. So cooldowning by IP could effectively DoS all other users on that IP.
    – AviD
    Jul 22, 2015 at 8:09
6

You want your server to do as little work as possible, to avoid DoSing yourself. Account lockout is great for DoSing your users.

if count(unsuccessful authentications for username U) > threshold then demand solved CAPTCHA

if count(unsuccessful authentications for password P) > threshold then demand solved CAPTCHA

if dislike CAPTCHA then demand Proof of Work

(make the client calculate the prime factors of a real big number)

1
  • 1
    "Proof of Work" is a really interesting concept. It might even help with DDoS attacks because it slows down the attacking systems significantly. Aug 26, 2016 at 17:22
4

A traditional delay would mitigate web browser based attacks, for example if someone uses phantomjs to automate login attempts the normal delay (in your case "more than one second") would be enough to stop anyone from trying to brute force a password, it just takes too long.

However, most brute force attacks are not ran in web browsers but in scripted environments where they can issue multiple requests at the same time.

The way I would implement it is by having an intentional delay on the server side after an unsuccessful login, plus a throttling mechanism (something like this) and a front end message or spinner that informs the user that the credentials are being checked (nobody wants a blank page for a reload or a system seemingly hanging for a long time)

You must log in to answer this question.

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