|
Well first of all your "common scenario" terrifies me, and betrays an app developed by incompetent devs who wouldn't even know what a "hash" is, because in any sane situation: 1) The SQL database is not public (any more than it's common to have public anonymous FTP to your server's app deployment). It listens on a specific interface, specific port, from specific IPs with a specific user and password (which is not "root"/""). 2) Input isn't properly sanitized? Hello? If that's "common" then fix that first. It's not 1998 anymore, no one has an excuse for that level of ignorance. First of all "sanitize" is an incorrect term for what needs to be done. You either escape an SQL literal, or you pass it as a parameter to a prepared statement. You do this to all data, all DB layers provide escaping, and it's absolutely trivial to do. And for prepared statements, there is no way to do it wrong, because it's not you who does it. Data and query in prepared statements are separated at the protocol itself and injection is impossible, you can't possibly mess it up. All of this is "using databases 101". Heck, your app will break even with innocent data containing, say, a quote, if you fail those. 3) I mentioned twice already, there's public salt for hashing the password, and there's irreducibly slow hash to be used to protect against a weak password (like Blowfish). This is what breaks brute-force attacks, not HMAC. 4) Let's assume your exact scenario is indeed terrifyingly common. Still, HMAC does nothing at all here, that keeping part of the salt off-the-DB won't do. HMAC doesn't mean "when you have a key outside the DB". You don't need HMAC to keep part of the salt outside the DB. Just... keep part of the salt outside the DB, without HMAC. But if you feel the need to obfuscate your code like this, it means you're working in hell and some people don't deserve their jobs, and better fix that, before you start thinking about compensating for it at the wrong place of the app. |
I.e. User <-> App <-> Database
Input is simply not properly sanitized in the real world because mistakes happen. This isn't by design. This is a source of remote execution. The remote execution only yields read access since the app only needs read access (and thus the fewest privileges possible are read access). The attacker can read password hashes, but cannot update them.
As I mentioned before, HMAC is just an example of keeping all information necessary to login to the site out of the stored hash. Any non-constant value per password will do (feel free to maintain a lookup table of unique lists to active passwords in your app if you feel you must, I'll be HMAC'ing the user's input password against a constant secret key before sending to KDF). The idea is that an attacker who can read your database (but not the application code) cannot gain access as a user without first also compromising the application code.