36

Say I had a database that looked like this:

Name   Password hash (bcrypt)                                          Status
--------------------------------------------------------------------------------
Dave   $2y$10SyyWTpNB.TyWd3nM hQ41frOtObcircAb3nJw1Cf9dC6CT7tVIEb6XS   Standard
Sarah  $2y$10$fUJrNA200sXgWUJAP7XEiuq4itHa43Y8QVIpc/YWscgVJ PYWbLLV.   Admin
Mike   $2y$10$01jx7u7hnfKOzBYyjNWskOPQ23w1Cf1gNiv42wsKqXKOf8filzS02    Standard 

If an attacker gained access to this database, then they would immediately see that Sarah is an admin, and would probably focus on breaking that password, so they could have more power. Is there any way I could somehow hide whether or not someone is an admin in the database so that an attacker would not know who the admins are? I could simply hash the value (standard or admin) but that would only give 1 bit of entropy, and I would hope to get a bit more security than that.

TRiG
  • 609
  • 5
  • 14
Melkor
  • 1,285
  • 2
  • 10
  • 12
  • 118
    An attacker could also simply look at the oldest entry. In most systems this will be the admin account :) – Mikescher May 02 '17 at 12:06
  • 1
    @Nat - How exactly could they log in using only the hash? That doesn't make sense to me, although it does make sense to just log in as every user until you find an admin. – B00TK1D May 02 '17 at 13:13
  • A long time away in a universe far far ago, I had to implement something similar. The way I did it was: prepend a letter to the password when hashed (actually multiple letters, it was a "group id") and have the authentication mechanism try out all combinations. – PlasmaHH May 02 '17 at 14:14
  • 4
    It would be simpler and you'd be better off to add 1 bit of entropy to the password (hash), effectively doubling the average effort of a successful brute force attack, than to deprive the attacker of 1 bit of reconnaissance information. Also, it doesn't take that much longer to brute-force a pre-image for 1 million hashes than it takes for a single one (assuming equal actual pre-image entropy). – David Foerster May 02 '17 at 16:20
  • Is this column readable for normal users? – eckes May 02 '17 at 19:25
  • 1
    @DavidFoerster It is more than one bit of information because there can be a lot of users. And breaking a password hash is not the same as finding a pre-image of a hash value for two reasons: `1.` Most passwords have a lot less entropy than the size of the hash output. `2.` These hash values look like they are salted. – kasperd May 02 '17 at 21:00
  • 2
    @kasperd: You make a good point about password entropy which I considered but left out for the sake of brevity and the following reasonable assumption: the admin password will have a much higher entropy than the average account password and will likely be among the last ones to be found during a typical dictionary attack that tries short passwords before longer passwords and common words before less common words before random character sequences. – David Foerster May 02 '17 at 21:12
  • @kasperd: About the bit of information: There may be more than 2 account types but in this scenario the attacker only cares about the binary distinction between admin vs. non-admin. – David Foerster May 02 '17 at 21:17
  • 1
    @DavidFoerster My point is that the information the adversary gets from knowing up front which users are admins is closer to 1 bit per user than to 1 bit overall. And what the adversary cares about is only the passwords of the admins. If all passwords in the database were equally strong that 1 bit of knowledge per user could help the adversary a lot. However as you point out, the admin passwords are likely stronger on average than the other passwords. And that means knowing which users are admins is worth a lot less to the attacker. – kasperd May 02 '17 at 21:27
  • 1
    Why would one need to crack the admin pasword when already aquired system access? – BlueWizard May 03 '17 at 06:58
  • 2
    @JonasDralle Attacker may have acquired the hashes from a leaked backup. The admins might have used the same password for more than one system. – kasperd May 03 '17 at 07:19
  • Perhaps instead of obfuscating your data enforce Certificate-based Authentication. – BlueWizard May 03 '17 at 07:22
  • 24
    If the attacker can scan your database you already have a much bigger problem than this. – user207421 May 03 '17 at 10:55
  • 1
    @JonasDralle TLS client certificates have their own problems. See e.g. https://utcc.utoronto.ca/~cks/space/blog/tech/TLSClientCertificateWhen – user May 03 '17 at 15:24
  • Isn't that basically Kerberos? :) – Sobrique May 03 '17 at 15:37
  • If the hacker has access to you database why not try to hack all accounts and then just change the status to Admin? – Matthew Whited May 03 '17 at 16:44
  • 1
    @MatthewWhited: It could be read-only access. – David Foerster May 04 '17 at 10:20
  • Adding more entropy to the hash is also of little value ... the real problem with passwords is that people use easily-guessed ones or write them down if forced to use random(ish) ones. How about implementing two-factor authentication instead? Google Authenticator is free to anyone who carries a smartphone. Or even just retire "Dave" etc. and insist on a random choice from 1.6 billion IDs of the (reasonably memorable) form aannaann. – nigel222 May 04 '17 at 10:53

9 Answers9

127

I would say this is a bit too much trouble considering what you get out of it. I think when the attacker has access to the database you have way bigger problems. Obfuscating the admin status of a user will just cost the attacker some extra time, but an APT (Advanced Persistent Threat) would probably not be deterred by this fact.

Wayne Conrad
  • 103
  • 3
Black Magic
  • 1,212
  • 1
  • 10
  • 15
  • 70
    Exactly. Obfuscating the admin status is as useless as trying to tape your belongings to the floor so burglars can't get it - they still can and will do it. You want to prevent the burglar from entering instead. – James Cameron May 02 '17 at 10:04
  • 12
    @JamesCameron unless your 'belongings' consist of 10 inch nails. Then, I think the burglar might just wonder what is wrong with you... and report you as insane. – user64742 May 02 '17 at 22:07
  • 22
    @TheGreatDuck - whereas nine-inch-nails would of course be perfectly reasonable. – Simba May 03 '17 at 12:12
  • 6
    @TheGreatDuck: I tell my wife they are 10" nails, but they are really only 8.5" nails. – Pieter Geerkens May 03 '17 at 20:26
  • 6
    @PieterGeerkens: And that is why she cannot parallel park. – dotancohen May 04 '17 at 09:02
  • @PieterGeerkens that is still overly optimistic... ;) – Burgi May 05 '17 at 09:48
26

Security through obfuscation has limited effectiveness at best - to determine if it is suitable, you need to understand what threats you want to counter. If a threat actor can read your database directly, what benefit is there in hiding a particular stored detail?

If there is benefit in obfuscation (make sure you can really prove this), then employ the type of obfuscation that addresses that threat (encrypted values, off-line data sources, hashing, etc.).

schroeder
  • 123,438
  • 55
  • 284
  • 319
5

I agree with Black Magic that it's probably not worth doing, but if you wanted you could use a key derivation function to make an encryption key based on the password, and use that to encrypt the content of the Status column.

Potentially the status would have to be kept in memory for any open user sessions, so those could still be vulnerable to the attacker.

This would mean you would have the same restrictions as your attacker, assuming you don't know your users passwords. You wouldn't be able to read status from the DB, and if you wanted to change a user status you would have to change their password at the same time.

bdsl
  • 595
  • 3
  • 7
  • 1
    Actually you could change a status to non-admin without knowing the password - just enter some random value in the field and rely on the practically zero probability that that could happen to match the ciphertext for 'admin'. The code that reads it would have to tolerate unexpected values. – bdsl May 03 '17 at 12:44
  • Or you could have a 'newStatus' db column and set that instead, in plaintext, then clear it when the user logs in and you update the encrypted status. – bdsl May 03 '17 at 12:45
  • 6
    It also means you can't have a password recovery feature without losing the status of the account. – user May 03 '17 at 15:27
  • 1
    Good point @MichaelKjörling that would probably be a deal breaker. – bdsl May 03 '17 at 15:47
3

Many modern systems actually do separate the user's login (how they authenticate) from their "profiles" (permissions they have), implemented as two or more discrete systems. Your login server could just have a GUID, a hashed username, and hashed password; on a successful login, transfer the session to the application server. As long as your application server isn't compromised, the login database is useless even if it gets dumped.

As an added step, you could also encrypt the user's data with a key from the login server (stored as part of the session), making the application server more secure as well. Two systems is typically harder to defeat than one. However, if you're not willing to set up two servers (or clusters), and it all sounds like too much work, then you're probably better off with your current design anyways. Simply knowing which accounts to target doesn't make the job any easier; if the attacker can crack one, then they can crack all of them with parallel computing.

phyrfox
  • 5,724
  • 20
  • 24
2

The suggestion from PlasmaHH was to : "prepend a letter to the password when hashed (actually multiple letters, it was a "group id") and have the authentication mechanism try out all combinations."

Though it is somewhat security by obscurity, and needs to be paired with good practice like :

  • a strong work factor on bcrypt
  • admins having a strong password
  • ways to prevent the attacker from having a copy of the database in the first place

It is a good way to slow down an attacker enough so that the password is changed before it is found.

Cracking one non trivial password (assuming you used a strong work factor) may take a few days to a few months, so it is doable, but if they don't know which account is worth hacking, it makes them have to hack each account.

So unless they are lucky, or you named an admin account "admin", they will have to try multiple accounts, that will make their costs at least an order of magnitude bigger, making the attacker either wait more, buy more power, or give up.

In conclusion, it is not worthless, as it is a cheap deterrent that doesn't bother the user.

Note that if you have hints of someone being an admin, like a post from someone else edited by them (if only admins can do that), masking their status in the db is useless.

As others have mentioned, this has gotchas like preventing you from making an user admin without changing or at least asking for his password.

If available, requesting 2 factor authentication for admins would probably be a better way to secure admin accounts.

satibel
  • 433
  • 2
  • 8
2

Yes you can. Just add the admin status as part of the password.

like: HereIsMe!65371 = admin HereIsMe!65370 = regular

Then at login, try regular first then admin, like this:

if (sha512($password . "0") eq $hash) {
blabla user functions
} else {
if (sha512($password . "1") eq $hash) {
blabla admin functions
}
else
{
show incorrect password message
}
}

IMPORTANT: Make sure you ensure somebody cannot edit their last char of their own password. Eg, make sure registration form, forgot password form, and change password form, always append a 0 or 1 at the end of the password depending on their real status. Store the status in a server-side session, preferable encrypted using a client-side session cookie.

This makes it practically impossible to deduce the admin status without successfully cracking the password.

sebastian nielsen
  • 8,779
  • 1
  • 19
  • 33
  • 1
    knowing the scheme and looking for 1's breaks your system - if you have a separate table listing who the admins are, why not use that instead of mangling passwords? and then if you have this table, how do you protect it from being read along with the mentioned table in the question? – schroeder May 04 '17 at 14:04
  • also, this is very similar to satibel's answer – schroeder May 04 '17 at 14:05
  • How? The 1 is hashed part of the password. Yes you could tell your hashcracker to append 1 to the password, but you would still not know which account is admin so you would still have to crack all accounts. – sebastian nielsen May 04 '17 at 14:07
  • If I'm logging in as an Admin, how would the system know to append a 1 to my supplied password before hashing? – schroeder May 04 '17 at 14:29
  • @schroeder As long as hash(password + '0') != hash(password + '1') this will work just fine, although it seems pretty dangerous to go badly wrong. And it means you can't reset the password of a user without resetting their access rights and similar problems. – Voo May 04 '17 at 21:07
  • @schroeder If you check the example code, you see that it will try logging in as normal user first, if hash mismatch, it will test admin. The trick is that its not possible to know beforehand which user is admin, without knowing their password. – sebastian nielsen May 04 '17 at 21:10
  • @Voo Yes you are true that you cannot do a "forgot password" on a user without having their admin access right reset to user. But hey, thats actually a good security feature, because if some hacks the reset password feature for example by hacking a email account, the admin rights are still safe. At password change, you already know by the session if the logged in user is admin or user. – sebastian nielsen May 04 '17 at 21:13
  • So, adding a 0 for users isn't necessary, you can simply add the 1 for admins, but how does the system know that the user should have this extra bit added in the first place? Why not just hardcode the admin hash to your example code? Your suggestion seems unmaintainable and certainly not scalable. – schroeder May 04 '17 at 21:15
  • 1
    @schroeder Its neccessary to add 0 to users, else you run into risk that the user add 1 to their password and become admins. By hardcoding the admin hash, you can deduce the admin by looking at code + db. But with my idea, you cannot deduce who is admin, even with access to both. You can try cracking the password and check if 0 or 1 matches the hash. – sebastian nielsen May 04 '17 at 21:19
  • 1
    @schroeder What is not scalable about the solution? You can extend this to as many permissions as you want, even allowing for bitflags. It's rather fragile and has some disadvantages but it solves the given problem. – Voo May 04 '17 at 21:22
  • 1
    Another problem with solutions like this is it becomes difficult to implement an interface for higher level admins to revoke admin status from other users who become problematic on the fly, since any sane implementation of this would store only the admin status itself in the session data on login and thus couldn't check roles on every relevant request, and so revoking admin access requires forcefully deleting login session data so that the user has to log in again. – Jason C May 05 '17 at 03:47
  • This is the only answer, that properly responds to the question. – user1643723 May 05 '17 at 11:46
0

If your database supports it setup a LDAP or similar authentication server, and then the credentials won't be stored locally.

cybernard
  • 518
  • 2
  • 10
  • The question is about hiding authorisation, not authentication - and making that queryable from a remote source can make it worse if not implemented correctly (the authorisation info need only be accessible on successfull authentication!) – rackandboneman May 04 '17 at 21:54
  • @rackandboneman The server in question will have no credentials on the server, so they will be hidden. If you have your own network, and you make your authentication server visible to the internet you deserve to be hacked. Obviously you have to use TLS 2048 bits or more and blah blah or whatever it allows. – cybernard May 04 '17 at 23:09
0

There are several interesting technical suggestions here, but it needs to be mentioned that even if you implement them perfectly this approach will quite literally gain you nothing in the event of an intrusion for the following reasons:

  • If someone has database access (though sql injection or something like that), it's a given that they can pretty much do whatever they want on your server with the permissions of whatever user your database service is running under since most database management systems provide functionality for manipulating files and running processes on their host. That means the intruder can modify your web pages or server-side processing to capture plaintext passwords during login and very quickly gain unencrypted passwords for your active users. I'm assuming your administrator account is an active user.
  • If someone gains access to your password hashes, they are probably not going to dial in on which ones they should attempt to crack first. They'll just run a bulk cracker to process all of them at once and in each pass it will check against all of the hashes in the table they are processing.
  • Even if you kept your admin password hash in a separate table or outside of the database entirely, the compromise of less privileged accounts will likely lead to privilege escalation as long as the intrusion has gone undetected since the intruder will be able to impersonate trusted users to gain access to more information (by using a moderator account to talk with the admin and kick off cookie stealing or some other malicious activity, for instance).
  • If your site has any social capabilities it's very likely that it already exposes other ways to identify administrative users.
S.C.
  • 180
  • 1
  • 8
-4

If the attacker gained access to the database, then they can just make their own bcrypt hash and replace the one in the database. There's no need to crack the hash.

  • 14
    Not if they only had read access, or e.g. a data dump or something. – Jason C May 02 '17 at 15:27
  • 2
    Also - even if they do have write access, it wouldn't help them to insert random bcrypt hashes into the database. They would have to understand the cryptography of the authorization system in order for it to accept the hashes, and if they can do that, then they can just decrypt the existing hashes much more easily. – B00TK1D May 02 '17 at 15:29
  • 3
    Does not answer the question. Even if what you propose is true, the attacker would have to know which one to replace. – schroeder May 02 '17 at 16:33
  • @KernelStearns Even I know the cryptography of the original scheme. You just have to look at the hash. It's bcrypt with cost of 10. – a20 May 03 '17 at 03:46
  • 2
    @Schroeder He can replace all the hashes in the table (if he has write access) So I think this is a valid answer to the question. – Ajay Brahmakshatriya May 03 '17 at 08:55
  • 3
    @AjayBrahmakshatriya only if the attacker wants to announce himself so loudly. If the attacker wants to be more tactical (and quiet), knowing which account to target is important. So, no, this answer *bypasses and dismisses* the question, it does not answer it. – schroeder May 03 '17 at 09:00
  • 1
    @Schroeder What I meant is he could replace one by one (and replace back if it is not admin). This is way easier than trying to crack each hash one by one. So hiding the admin status doesn't really work if the attacker has write access on this table. – Ajay Brahmakshatriya May 03 '17 at 09:03
  • @AjayBrahmakshatriya for a system with thousands of users, that's quite a bit of work. – schroeder May 03 '17 at 09:15