DEV Community

Discussion on: How to securely hash and store passwords in your next application

Collapse
 
gamma2653 profile image
Christopher De Jesus
  1. This would not be considered a vulnerability (on the backend at least) because if a malicious user had access to the runtime, the program would already be compromised. (After all, python functions are values/variables themselves). As for client side, it really depends on the use case. A use case where it would be vulnerable, can potentially be in my answer for 2.

  2. Yes/No. The actual encrypting is fine, though unconventional and i would consider bad (and even perhaps dangerous?) practice. That is, of course, assuming login authentication still happens servers side. Otherwise, NO, that is in no way secure for reasons I'm sure you know.

TlDr; Do all authentication tasks serverside to save the trouble and simplify design. Doing otherwise does not accomplish much. If you are afraid of sending plaintext passwords over HTTPS, no need to be- it is already encrypted as per TLS and encrypting the password further would not accomplish much in terms of added security. (See security.stackexchange.com/questio...)

Collapse
 
kmistele profile image
Kyle Mistele

Yeah, this is correct. Passing a password as an argument to an encrypt function necessarily has to happen somewhere, otherwise how would you encrypt it? To Christopher's point, if someone can mess with your runtime or source code, you have bigger problems.

Encrypting client side is uncommon and probably considered bad practice. Most back-end languages have libraries for performing hashing and so forth, but I'm not aware of many implementations to be used with JavaScript on the front end. You'd either have to roll your own (never roll your own cryptography), or copy/paste someone else's which would be bad. Doing it on the back end also will ensure standardization. As long as you force HTTPS (TLS/SSL) for authentication and authorization, which most browsers will require (many will automatically upgrade from HTTP to HTTPS where possible), you're fine.

Collapse
 
dwd profile image
Dave Cridland

Encrypting on the client side leads to a subtle attack, actually - the encrypted password is now a "plaintext equivalent", and the temptation then on the serverside is to do a encrypted_password == stored_hash. And then the attacker can work through, byte by byte, with a timing attack and ultimately find the entire encrypted password.

Whoops.

This is because the typical string comparison code - such as the C library strcmp() call - works through byte by byte in a for loop and bails at the first mismatch. An attacker can time the rejections carefully, and slowly by surely increase the matches.

Yes, it's a slow method - but much faster than brute force, and surprisingly plausible.

As you've noted, libraries like the Python bcrypt provide a check function that - if you dig into the code - you'll probably find will take the same time on any failure or success. These are known as "constant time" functions, and they're useful things.

So, don't encrypt on the client-side - or rather, you can but you should always encrypt server-side as well.

Typically, though, we can trust TLS and skip doing much client-side. Indeed, if you're about to send over a plaintext equivalent - a stable, repeatable transformation of the original input password - there's little point worrying - if an attacker can see "inside" the TLS channel, they can just re-use the plaintext equivalent you're sending anyway.

But in some cases that's not a valid assumption. For example, some bizarre corporate security systems essentially MITM the TLS channel with a root certificate imposed on the client system. If this is within your threat model, look at the design of SCRAM, and use that - that uses a simple, hash-based, mechanism to encrypt and transfer a plaintext equivalent hash and then verify the server knew it, all without storing plaintext passwords (or password equivalents) on the server.

And, of course, also look at implementing TOTP and getting a cheap 2FA system up - whether or not you're worrying about plaintext equivalents.