Why you should limit password length

March 9, 2019
I try to bend the internet to my will.
Wizard 22 posts
Followers: 19 people
6

Why you should limit password length

I try to bend the internet to my will.
Wizard 22 posts
Followers: 19 people
March 9, 2019

It’s good practice to allow your users to have long passwords. These passwords can be stored as a hash and because the hashed version is a predictable length, the password can be stored in a database without worrying about it being too long for the column’s length limit.

Allowing long passwords turns out to be a double-edged sword – and one I’d never considered. I was reading about a denial-of-service attack that was used against a website (built with Django in this case), where an attacker had used the plain text login password as an attack vector to bring the site down. What the attacker was  doing, was posting really long passwords knowing that the encryption of the password was computationally expensive. By sending multiple login requests in a short period of time with long passwords they were able to max out the server resources preventing anyone from being able to access the site.

Django was using PBKDF2 to hash the password. PBKDF2 is designed to be computationally expensive so that password cracking attempts take longer. Bycrypt and other hash functions are also designed to work this way. Even with a simple MD5 hash, which is fast, it will get progressively slower the longer the given string it is hashing is.

Fortunately the solution is simple (and has been fixed in Django for a long time), check the length of the password submitted to the server. If the length of it is not something sensible then reject it before performing any computationally expensive operations on it. This of course is not just limited to passwords, it can apply to any data that you encrypt.

I’d allow passwords of at least 1,000 characters – some password generators I’ve seen will give you a 2,048 character password. The attackers were using passwords with millions of characters in. I can’t see why a real user would have a password longer than that long so would block based on that.

Using a password 1,000 characters long took 11ms with the PBKDF2WithHmacSHA1 Algorithm in a test I’ve just run. It’s when my ‘password’ is 10,000,000 chars long you start to see a noticeable impact (~300ms in my basic test). With no limit you can submit much longer password strings. Although 300ms may not sound like much, if you’ve got multi-requests coming in all taking 300ms you will start to run out of resource.

Comments (6)
2019-03-13 15:18:03
2019-03-13 15:18:03

Hi Charlie,

Good feedback – and I do that for brute force attacks (locking the account completely for set period of time after n failed attempts).

In this case the attack was a Denial of Service attack, so adding a sleep(n) would actually help the attacker as your thread is tied up for longer so you’d quickly hit the concurrent request limit and so nobody else can login. The attackers were not trying to gain access to the system, just take it offline by using up the server resources, hence why the used passwords over a million characters long, as those take longer to process.

Attackers are an inventive bunch!

For anyone else reading – I can highly recommend looking at Foundeo FuseGuard as way of reducing the number of attack vectors that can be used against your site.

Like
(2)
>
aliaspooryorik
's comment
2019-03-13 15:20:06
2019-03-13 15:20:06
>
aliaspooryorik
's comment

John, you’re asserting that the throttle of failed login requests would tie up resources, because you would do a sleep. Don’t do that. You don’t need to “tie up the thread”, nor sleep it. You just need logic that makes them wait the stated ms or secs before you would allow another login.

Like
(1)
>
Charlie Arehart
's comment
2019-03-13 16:09:20
2019-03-13 16:09:20
>
Charlie Arehart
's comment

Sorry Charlie, misunderstood your suggestion.

I do lock the account completely for set period of time after n failed attempts, that is similar to your suggestion although it does only protect when an attacker is targeting a single account.

With brute force attacks against a number of accounts, it’s much harder to prevent. You can use a session / cookie or IP to detect the ‘user’, but I’ve found that more often than not these types of attack use bots nets so you can’t rely on a session or cookies and the IP is not consistent.

You can use a CSRF token to get around that, so it all comes down to building up layers of defence. I hope it doesn’t sound like I’m suggesting in the post that limiting password length is all you need to do to defeat attacks.

Like
(1)
2019-03-13 03:39:53
2019-03-13 03:39:53

John, that’s interesting–though your last comment that a 10 million character password might take 300ms does kind of dampen the concern suggested in the post. 🙂

Still, you clarify that the problem was when a bad actor was “sending multiple login requests in a short period of time”. Fair enough. I’d propose a different solution (and valuable for reasons beyond your scenario, such as stopping brute force login attempts).

You could have your CF code (or that of any app server processing logins) start making the requester wait progressively longer and longer after each failed login.

It could be 100ms, then 200ms, then 400ms, then 800ms, then 1600ms, then 3200ms, then 6400ms, and so on. You see that a “normal” user gets a few tries with less than a second delay, but then they quickly get bogged down. And of course, one could throw another 0 on those, if they wanted even a few failed logins to become painful.

This may seem overkill for your particular problem, but your point was that they make a number of failed requests in a row. This would stop that, and more important it would stop brute-force password attacks.

Of course, you have to track the “requester” in some way (by IP, or via a cookie, etc.) and a clever attacker could spread their requests around. A system (application) could handle that as well, imposing an increasing failure wait for ALL requests if some large number of failed logins was being detected in a short time across many requesters (by which I mean if the ratio of bad to good logins starts to increase significantly in some short period of time.)

Hope that’s all helpful to someone. I’m open to feedback or comment, of course.

Like
2019-03-12 08:44:30
2019-03-12 08:44:30

Gary__F I’d allow passwords of at least 1,000 characters – some password generators I’ve seen will give you a 2,048 character password. The attackers were using passwords with millions of characters in. I can’t see why a real user would have a password that long so would block based on that.

Using a password 1,000 characters long took 11ms with the PBKDF2WithHmacSHA1 Algorithm in a test I’ve just run. It’s when my ‘password’ is 10,000,000 chars long you start to see a noticeable impact (~300ms). With no limit you can submit much longer password strings. Although 300ms may not sound like much, if you’ve got multi-requests coming in all taking 300ms you will start to run out of resource.

Like
2019-03-11 21:25:07
2019-03-11 21:25:07

How long is too long? Long enough to accept a pass phrase such as billygoatatemyredsocks. I would put a limit on the max length of between 24 and 36 chars. I don’t think it’s too stressful for CF to encrypt a password that long. It just depends on how many requests per second an attacker makes.

A developer shouldn’t have to make a choice between making their site less vulnerable to this type of attack or letting users choose a strong yet easy to remember password.

Like
Add your comment