I don't think a unique derived salt is any worse than a random unique salt. The only purpose of a salt is to confound discovery of the passwords when the table of hashes is obtained.
For a password to be discovered from a hash, it has to be somewhat guessable in the sense that it found in an existing rainbow table, or (for example) identical to another password in the data set.
+--------------------------------------------------+
| password | hash |
+---------------+----------------------------------+
| freaky | 33ca4223307e2fa4fd77c394ceb4e37b |
| freaky | 33ca4223307e2fa4fd77c394ceb4e37b | <- identical to previous
| Freaky Friday | 852d2f614f08a63911f8944df6df40df |
| ...
What that in mind, let me restate the purpose with one further grain of precision:
The only purpose of a salt is to confound discovery of easily guessable passwords when the table of hashes is obtained.
Even the worst possible salt supports that objective pretty well. Let's say for argument that I were to salt every row with the predictable and rather obvious 8 bytes "Salted__
" (noting, please do not actually do this).
In Crackstation.net today I don't even find "Salted__123456
", so presumably the attacker would have to identify or create a custom rainbow table before they could begin the attack. But note, weak passwords such as "freaky
" would still have the same hash and would therefore still be an initial focus for the attacker to try the "top X passwords" or whatever. And once the rainbow table was built, the attack could continue for the entire data set.
The next most powerful choice of salt, therefore, would be unique per row. That would mean the attacker would have to build a new rainbow table for each password. This means if the attacker is only after one of your users, the effort is the same as the static salt above. But, if the attacker wants your entire table the time complexity of cracking has gone way up.
I don't believe it makes a difference whether the salt is unique and random; or just unique.
Imagine you are the attacker and you have the hashes. You know you are going to have to build a rainbow table to attack each and every row. Does it matter what the salt values are? Whether you see the unique salt value in the hashes table; or whether you know the salt is the customer_id or whatever, doesn't change the amount of work you have to do.
Next imagine you are the attacker and you do NOT have the hashes. What if you learned that the passwords are salted with the customer id? I guess this means you could precompute all of the rainbow tables prior to effecting a theft of the hashes, but this doesn't lessen the difficult part of your workload, so I would claim that it is insignificant.