15

Is it okay to use the primary key as the salt in a Users table?

The only disadvantage that I can see is if the PK changes (unlikely), then the passwords break.

What are your thoughts?

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
  • 2
    You may end up round-tripping the database too much if you use auto-incrementing keys to save the user, get the id back, then hash and save the password. Plus, its just as easy to create a salt and store an extra column, so why not? –  May 16 '11 at 14:45
  • What data do you use as primary key? – Gumbo Oct 02 '11 at 13:21
  • A primary key is not unique across different systems, they are not evenly distributed (low number values are more likely) and high value accounts (admin, root, etc) typically have a bigger chance of being stored at a lower number. So by using a PK as 'salt' you allow an attacker to perform more than one attack at the cost of a single attack. – Jacco May 16 '12 at 09:28

6 Answers6

10

I see no immediate problems with that approach. Especially if you use a per website salt in addition to a per user salt. So that your combined salt is complex enough. The main function of a salt in password hashing is preventing rainbow tables. And you don't need a highly random salt for that.

I still wouldn't do it that way, since using a random salt is standard practice. And inventing your own crypto is usually a bad idea, because it's easy to get wrong. So I'd simply follow the standard practice unless there is a really good reason not to.

IMO it's more important to use a KeyDerivationFunction with enough iterations to slow down brute-force attacks than to worry about the randomness of your salt. Having some salt is essential, but only one of the things you need.

CodesInChaos
  • 11,964
  • 2
  • 40
  • 50
  • Good answer - especially the bit about not inventing your own crypto! An unpredictable salt is best, but strong randomness isn't that important. Though you should be a bit clearer that it is most important to make sure that your salt is not just locally unique, but globally unique, to avoid pre-computation of hash tables e.g. for accounts with common keys like "john" or "root". – nealmcb May 28 '11 at 06:00
  • Sorry, but I'm down-voting this, for "no ... problems". The "primary key" (PK) is a database entity, and it tends to be implemented different from project to project. However, it is very common that the primary key is *a)* a small 32-bit (or 64 bit) integer value, and *b)* starts at zero and then increases by one for each added user (0,1,2,3,4,...etc). In this common case, the primary key has low entropy, and is predictably tied to the user account creation time. That's not good enough for a password salt. A PK should *not* be used as a salt, unless it is highly random (type 4 UUIDs fx). –  May 29 '11 at 19:12
  • @JesperMortensen unpredictability isn't an important property of a salt. Global uniqueness/rareness is enough. – CodesInChaos Feb 13 '12 at 23:02
6

Salt should always contain random bits generated by a cryptographically sound method. The primary key is anything but random; don't do it!

EDIT: What I am getting at here is that your primary key on its own won't contain enough entropy. It's possible to generate a separate rainbow table for each salt value. Your salt needs to contain enough bits of entropy such that it's infeasible to generate enough tables to enable an attacker to precompute your hashes.

  • 2
    I don't think a salt used in password hashing needs to be random. It's main purpose is just being a (relatively) unique value that prevents pre calculated tables(such as rainbow tables) with many commonly used passwords. –  May 25 '11 at 21:08
  • 1
    Ridiculous. Do you not realize that the reason that (proper, cryptographically random) salt is used to defend against rainbow tables is because it makes it computationally difficult to compute the table in the first place? Throwing in k-bit values where k is too small and most of those k bits are not random is not going to help you! –  May 25 '11 at 21:28
  • As long as the salt is globally unique per user that's enough. It doesn't need to be random. So some long enough(high enough entropy) per website salt combined with a locally unique user id should be enough to prevent rainbow tables. I see no weakness in for example concatenating my domain with the userid and making that the salt(like `stackoverflow.com-79656`). It's absolutely not random, and it's bad style. But I see no immediate problem with it. –  May 25 '11 at 21:33
  • Not "reverse" your hashes, rather "precompute" your hashes. –  May 26 '11 at 03:22
  • 4
    @CodeInChaos: Using a predictable hash salt like that enables an attacker to target you by doing an offline or distributed generation of partial or complete rainbow tables. That's a significant gift to the attacker when storing a per user crypto-random salt is so dead trivial. Plus the latter won't break the password encryption on all users when you change your domain name. –  May 26 '11 at 03:25
  • Yes, hashes aren't reversible, but a mapping from a precomputed hash to the original string has the same effect. That's what I was getting at. –  May 26 '11 at 22:19
  • 3
    Lots of high-quality entropy just isn't important for a salt. But it should be unpredictable and probably globally unique. And it isn't usually hard to get some good randomness, so that is often the best approach. – nealmcb May 28 '11 at 06:03
  • 3
    @Anonymous, the salt *does* need to be random. It should be unpredictable and unique. Unique, so that you can't share effort across users; unpredictable, so that an attacker can't precompute a table to break keys. – D.W. May 29 '11 at 21:46
4

Is it okay to use the primary key as the salt in a Users table?

It can be acceptable, in a few rare occasions, but even then it is unlikely to offer any real benefits. Basically, don't do this.

The situations where it might be okay are where the primary key is a) a large value, and b) a random value. A somewhat contrived example of this might be were a UUID Type 4 is used as primary key.

The only benefit you would get from this is saving a few bytes per user. This is completely negligible, no current database engine would even notice this saving -- even if you have millions of users.

However, there are major drawbacks to using the primary key as a salt, in the areas of software development needs and security:

In software development:

  • Good dev teams will use an OR/M, and good OR/M's really like to have exclusive control of the primary key. This opens up good performance optimizations. An example is the NHibernate Hi/Lo algorithm, which enables NHibernate to 'lazy write' to the database, speeding up things.

  • Good databases like to have exclusive control of the primary key too. And they often structure their data files by the primary key, leading to major performance gains with the right primary key.

  • Many database like the primary key to be small, fx a 32-bit integer, because the primary key is often included in indexes held in RAM.

In security:

Final answer: It depends on what you are actually using for primary key. But in almost all cases, this is a bad idea.

3

Is it okay to use the primary key as the salt in a Users table?

It definitely not OK. Use a random salt for each user. Use blowfish (the standard) or something equivalent.

In addition to accepting a random salt, blowfish is adaptive, meaning you can make it lengthier to compute as CPUs get faster.

  • blowfish is just a blockcypher. By itself it isn't fit for password hashing. It can be used in a higher level algorithm to build a KDF, and that higher level functions like crypt, pkdf2,... have the variable iteration count that allows you to adapt the hashing speed. –  May 25 '11 at 21:31
  • You're confusing blowfish as a cypher and blowfish used for password hashing. The latter is used in FreeBSD. –  May 25 '11 at 21:38
  • 2
    I think you mean `bcrypt` which is based on blowfish. But `bcrypt` isn't blowfish. –  May 25 '11 at 21:40
  • Quite possibly, even if [google](http://www.google.com/search?q=bcrypt) and [wikipedia](http://en.wikipedia.org/wiki/Bcrypt) both suggest what I believe it is... My guess is you're probably right though. BF != bcrypt but merely based on it. (And still good.) –  May 25 '11 at 21:44
  • 1
    The comments are right - bcrypt (which is based on blowfish) not just blowfish – nealmcb May 28 '11 at 06:04
2

Edit: sorry, got it wrong: I thought of "primary key" as a kind of server private key (e.g. in a HTTPS context), not in the database-SQL meaning. However, the database primary key is still unique in that database but if the software is used in several distinct server installations then the same "primary key" values will most probably occur in all of them. So a random (long) salt is still to be preferred, security-wise (randomness ensures uniqueness with high probability, if the salt is big enough, e.g. 16 bytes or more).

Original answer:


Not good. The salt shall be unique per instance: each hashed password for each user should have its own salt value. That's the whole point of the salt: to be such that each password is hashed with a specific scheme, distinct from the way other passwords are hashed, so that an attacker cannot share attack costs across several attacked passwords.

On the other hand, the salt needs not be secret (otherwise it would be called a "key"). It is conceivable to have a password hashing scheme which depends on a key (basically, a MAC) but this involves a different threat model, in particular with key management, which is known to be a difficult problem. Use a per-password random salt, stored along the hashed password, with no key whatsoever, and you will be happier.

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
  • How is a primary key not unique? The RDBMS shouldn't allow multiple entries in a table with the same primary key. – getahobby May 29 '11 at 00:23
  • @getahobby: you are mostly right, I misinterpreted the term "key"; however there could still be issues → I have edited my answer. – Thomas Pornin May 29 '11 at 13:06
  • FYI, "primary key" (PK) in a SQL database will be implemented differently from project to project, depending on the programmers. However, two very common approaches are UUIDs, and auto-incrementing 32- or 64-bit integers. The latter is most common, and here the primary key would be: Only 32 (or maybe 64) bits large; starts at zero; is incremented by 1 for each new user added (0,1,2,3,4,.. etc); and definitely shared with other installations (any installation which uses the same common primary key scheme). I don't think you want that type of primary key used as a salt. :-) –  May 29 '11 at 19:05
1

I would not recommend using the primary key as the salt. That practice is brittle.

Good designs should be robust-under-maintenance. Systems are not static; we often need to maintain them over time, to add new features, fix bugs, improve performance, etc.

Using the primary key as the salt is poor practice because it makes security reliant upon something that it is out of our control. There's no guarantee that a primary key will be unpredictable and have sufficient entropy for a salt; the requirements for a salt (uniqueness across sites, unpredictable) are different from and a superset of the requirements for a primary key (uniqueness within a single database). Using a primary key for a purpose which it wasn't designed for seems imprudent.

Even if using the primary key as salt happens to be secure when initially implemented, it would be easy for it to silently become insecure at some point in the future, as the software is maintained. Suppose the database or application changes how it chooses primary keys. That might not affect database correctness, and might seem like an innocuous change to some database designer or software developer, but it could subtly reduce the security of your password salting.

To be clear, I don't view this as an egregious violation. If I saw it in an existing application, I wouldn't jump up and down to fix it now, now, now. But if you're writing a new application, it seems like poor practice and I wouldn't recommend it. It is too clever by half.

D.W.
  • 98,860
  • 33
  • 271
  • 588