Brute-force mitigation using client proof of work.

Daniel Chatfield
2 min readMar 24, 2015

--

A common attack against websites is a simple login brute force, it is rumoured to have been behind the icloud hack that saw celebrity nudes leaked online.

This is commonly mitigated using rate limiting which is non trivial to implement and difficult to scale as it requires distributed state. I propose an alternative mitigation strategy.

When a user account is created or password changed instead of just storing a salted hash you store two hashes (using bcrypt or similar):

server_hash = generate_hash(password, salt=random_string)
client_hash = generate_hash(password, salt=username)

The server hash is exactly the same as the traditional hash you would have stored, it has simply been renamed to distinguish it from the client hash.

Then, when a user submits the login form the following happens (in browser):

var username = $('#username').val();
var password = $('#password').val();
var hash = generate_hash(password, username);$('#hidden_hash_field').val(hash);$('form').submit();

The server then first checks that the submitted client hash matches the one stored and only if it does continues to calculate and check the server hash.

This method ensures that for every password the attacker wants to try they have to do a not insignificant amount of work which makes a brute force attack infeasible.

Additional remarks

Instead of using the username as the salt in the client side hash, you could use a hash of the username and some public salt, this would ensure that if multiple websites used this technique and were breached it would not be possible to ascertain whether a particular user used the same password (although I’m not entirely sure how useful that information would be to an attacker).

You could even have a random salt per user and fetch it via ajax, but I’m not sure why this would be better.

--

--