How can we validate login credentials at the client-side itself without involving the server of a website?
The reason is that you can't trust the client at all. An attacker can modify the client as they wish, and circumvent any and all security measures you may have put in place.
But what if we digitally sign our code? The attacker can't modify it then, right?
Yes, they can. If you sign your code, the machine of the attacker needs to validate the signature and refuse to run it if the signature of the client does not match. Nothing stops the client from disabling this signature check and simply run code with a wrong signature or no signature at all.
Furthermore, if you don't want to involve the server at all after sending the website, then all the potentially confidential content needs to be sent to the client first (before knowing if they are authorized to see it), and later revealed to them.
Nothing stops an attacker from simply looking at the raw content being sent to them over the network, without any client-side code being run.
But can't you encrypt the data with the user credentials?
Yes, you could. But your goal is to authenticate the user, which means you confirm if the user is actually who they claim to be. The scheme suggested by user9123 would work as follows:
- User claims to be user "foo".
- Website encrypts payload for "foo" with credentials for that user, e.g. "foo:bar".
- User enters their credentials, which locally decrypt the payload.
This scheme does not authenticate the user to the server in any way. The server does not know if the user is really "foo" or not. Furthermore, if the user has a weak password, the attacker can attempt to crack it. Yes, a key-derivation function can make this process slow, but it is still essentially a credential leak.
What I am curious is why you would want to attempt this scheme, instead of the traditional tested method?
There is a long history of software with client side authentication. The best example is probably operating systems. Microsoft Windows authenticates users with an NT Hash in a special file called SAM; Linux authenticates users with crypt and the /etc/shadow file.
The design is:
- Receive the identifier from the user
- Securely receive the password from the user
- Look up the username and receive the salt and rounds for that user (optionally, reserve or create dummy user settings for usernames not found)
- Generate the hash of the password, using the salt, rounds and pepper
- Compare the generated hash against the stored user hash
- Check whether the user is locked out or other criteria
- Log the user on or fail the login, based on the criteria
This is the same workflow that works in the web paradigm. But steps 3-7 work on the server and not on the client.
When the user logs in, grab their password in the client-side code.
Hash the password and salt with a secure, long-running hash algorithm. You need something that takes sufficiently long to run that it makes brute-forcing the password given the hash impractical, even when the attacker has access to a lot of computing power.
Have the client-side code hash the user's password with the same salt and algorithm when the user attempts to log in next. If the hashes match, your client-side code has some evidence that the user has entered the correct password. If the hashes don't match, the user might have entered the wrong password. (The reason you can't be sure is because the user may have changed their password from another machine.)
But, as MechMK1 notes above, the fact that you even want to try and validate the password client-side suggests that you may be making really poor security design choices, such as doing something client-side that you expect a user without the correct password not to be able to interfere with. Plus, this whole scheme comes at the cost of leaving a hashed copy of the user's password laying around on their computer, waiting to be stolen and brute-forced if it turns out you picked the wrong hashing scheme.
A local password validation scheme could safely be used to prevent the user from wasting time or login attempts sending typo-d passwords to the server. However, since the user controls their local machine, they could easily bypass it by, among other things, deleting the cached password hash, or by replacing the hash that is stored with their own pre-prepared hash for a known password, or even by bypassing the code that checks the hash entirely. So this is not a viable way for the client-side code to actually authenticate the user. The client-side code is ultimately under the user's control and necessarily operates as the user's agent, not yours.
A related and potentially good design option would be encrypting locally cached user data with a key based on the user's password (with a sufficiently slow derivation algorithm to deter brute-force attacks). In this case, the client-side code doesn't need to try and authenticate the user; the encryption itself ensures that only the user has access to their local data.