25

I am setting up a postgres db that will never be used by humans. In fact, I really don't need to know it myself ever. I assumed that just using a 256bit(64 alphanumeric chars) hash of a unix timestamp IE:

date +%s%3N | sha256sum

A very important detail is I am not "hashing a password"... I am hashing a timestamp and using the sha256 hash as the password in the db connection string.

would be pretty damn strong. An example of one I could use has 31 lowercase chars and 33 integers, for an entropy of ~330 bits, which is.... well... I'd say pretty damn solid, if not completely insanely overkill. The reason I ask is because it STILL got flagged by chainlink's password complexity check for only having lowercase chars and numbers.

So... My question is, are they right? Is there something wrong with a 64 character alphanumeric password just because it doesn't have fancy capital letters? Is there something inherently wrong with using sha256 algo with a timestamp like this?

I am contemplating raising an issue on their github stating that I should not have to set their SKIP_DATABASE_PASSWORD_COMPLEXITY_CHECK=true flag for such a password, and that they should consider the actual entropy of the password instead of just applying a set of simple rules.

10
  • 5
    Considering that the timestamp fed to sha256sum is only 14 digits, the absolute maximum entropy is 46 bits. And in practice much less, if attacker has any guess of the time.
    – jpa
    Jul 24, 2022 at 16:46
  • 12
    "... sha256sum [...] An example of one [...] for an entropy of ~330 bits ..." - 330 bits of entropy in a 256 bit hash output? I think you need to redo your math :P
    – marcelm
    Jul 24, 2022 at 18:28
  • 9
    why use a hash as a password over a true random gen password? Is this just curiosity? Jul 24, 2022 at 19:08
  • 2
    What you're suggesting is called key stretching and is only as strong as the initial key space. This can be made stronger with a stronger key stretching function (e.g. the use of PBKDF2 in WPA) but is inherently weak. Jul 25, 2022 at 13:45
  • 4
    You'd be better off looking away, slapping your keyboard with one hand while you tap "shift" to the melody of a song you're listening to
    – TCooper
    Jul 25, 2022 at 17:30

6 Answers 6

97

... for an entropy of ~330 bits, ...

The question is not how strong a password looks like but how strong it actually is. SHA-256 does not add any entropy at all, so it all depends on what the input to SHA-256 was. And the entropy of the chosen input is pretty low: Assuming that the attacker knows how the password was created, they can test all possible inputs around the time the password might have been created.

A much stronger input would be to use real random data as input:

dd if=/dev/random bs=1 count=32 | sha256sum

While the output might look similar strong, it is practically impossible to predict the input by the attacker.

18
  • 30
    Note: I would suggest using urandom instead of random, for the reasons explained here.
    – Kevin
    Jul 24, 2022 at 6:16
  • 3
    @ThisGuyCantEven That question is answered here: stackoverflow.com/questions/5873099/… TL;DR: still not secure.
    – Ruben_NL
    Jul 24, 2022 at 13:50
  • 4
    what is wrong with head -c32 /dev/random (or urandom)? dd is a religion. Jul 25, 2022 at 11:28
  • 7
    @jaskij: The answer was designed to show the problem of the OP's approach and how to improve on it, i.e. show that a low entropy source needs to be replaced with a high entropy source. Showing on how to use a completely different tool as you propose would focus away from the essence of what need to be fixed. Jul 25, 2022 at 16:21
  • 6
    @Rob: Like I said in a previous comment - the point here is not to find the best way to express a specific statement but to focus on what really needs to be changed, i.e. replacing a low entropy source with a high entropy source. Using base64 instead of sha256 makes a change on a point where no problem was and thus takes the focus away from the real problem. Using head -c32 could be done but does not actually makes the point more clear than using dd. Jul 26, 2022 at 6:12
46

Password complexity is not a matter of having a bunch of random-ish characters.

The purpose of password complexity is to make your password harder to guess, not to make your password "look random." As a result, password complexity meters are not a good way of measuring password complexity, because it is simply not possible for a computer to figure out how an attacker will go about attacking your password.

Similar to Kerckhoffs's principle, it is good practice to assume that the attacker knows how you generated your password. Even if you don't like that assumption, you have now revealed this method in a public forum, so a resourceful attacker could find this Stack Exchange question and deduce that you have used this method to generate passwords.

Under that assumption, this method is potentially problematic. For starters, the SHA-256 hashing algorithm is public knowledge, so if an attacker can guess the input you used, then they can easily compute the hash of that input. Therefore, the hash adds nothing from a security perspective, and may be disregarded (besides which, the database should be doing its own password hashing on top of your sha256sum, and their hashing is probably a lot more thorough than that). Your question is equivalent to "Should I use the output of date +%s%3N as a password?"

An attacker may have a good idea of approximately when you generated this password. Your method does go to millisecond precision, so an attacker must try 1000 guesses for each second of uncertainty. But the exact time that you set up the database is probably not a secret! Or at least, you're probably not going to treat it like a secret. Unless you generate the password months in advance (which I doubt), there are all sorts of people who might plausibly know when you set up the database, such as:

  • Coworkers or colleagues.
  • The hosting provider, if any.
  • Your own provisioning system or other records.

In conclusion, this is a bad plan and you should not do it. Generate your password from scratch using a cryptographically-secure random number generator instead, such as using the code in Steffen Ullrich's answer.

1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – schroeder
    Jul 25, 2022 at 19:03
13

To bring some of the answers together in a more concise way. The short answer is NOT AT ALL.

The reason is that the entropy of the UNIX timestamp is entirely dependent on the time interval an attacker can assume contains the timestamp, once they've determined this was the method used for generation. If they know the date, they can generate every sha256sum that could be created within that window in a matter of seconds. Even if they only know within a 30 day interval, they could guess all the hashes in a few mins.

The correct way would be to use a cryptographically secure RNG to generate the password. One linux native option would be to use urandom to generate a 256bit string of utf8 chars IE:

cat /dev/urandom | tr -dc '[:alnum:]' | fold -w ${1:-64} | head -n 1

Another (more secure) option would be to use a tool specifically designed for generating secure random keys (IE OpenSSL):

openssl rand -base64 48
4
  • 4
    "256bit string of utf8 chars" - your code provides a string with 64 alphanumeric chars. No utf8 is involved here, except that each of the 64 chars is from a very small subset of utf8 where one characters takes only one byte. This subset is a-zA-Z0-9 - i.e. 62 different characters. This means it is not 256 bit effective size but 64 * log(62)/log(2), i.e. 381 bits Jul 24, 2022 at 17:00
  • 1
    "Another (more secure) option ... openssl rand -base64 48" - it is more secure by 3 bits compared to the more complex version, i.e. 48*8 = 384 Jul 24, 2022 at 17:32
  • Why the -w ${1:-64} instead of just -w 64? There's no context here to make $1 relevant, and fold would likely squeak if it contained a non-numeric string. (plus word-splitting would make funny things happen if it contained whitespace)
    – ilkkachu
    Jul 25, 2022 at 9:37
  • 1
    If anyone is wondering about the ${1:-64} BASH notation in this answer (specifically the :-), see stackoverflow.com/a/15737116/241812
    – parkamark
    Jul 25, 2022 at 16:00
5

There are so many misconceptions about passwords and security, and many of them are in this question.

tl;dr: Your choice is weak and predictable.

The main thing a password should be is not complex or full of special characters or anything like that, but hard to figure out. That's why your name is a bad password, even if you have a long name full of foreign accent characters. If you have such a name, go ahead and put it into five or six of the "online password strength metres" you find in Google and half of them will probably tell you that's a good password. It clearly isn't.

First of all, what is your threat model? - or in simpler terms: What is it that you are defending against whom? Is this database your personal gym log that nobody really cares about, including you; or is it your $200 Mio. crypto currency wallet, the only photographs of your late grandmother or a commercial database where people could lose their jobs? All different scenarios with different use cases and different levels of "secure".

We don't know your use case, so we can only give you generic advise:

  • The hashes might look random, but they aren't. In fact, they are perfectly predictable by anyone who knows your method. You could just as well use the timestamp directly and I think you'd agree that's a crappy password.
  • Generating a random password (simply get /dev/urandom) would be a much better idea. Among other things you can map it to the whole ASCII space, not just 0-9a-f. It's also not predictable.
  • Why would you want to use a timestamp at all? Does it serve a purpose? Or is it just a cheap source of randomness? In which case, why don't you use a real source of randomness?
  • If you thought of putting all that into a script, you've probably shot yourself in the foot as that makes it a) easy to find for an attacker who managed to get some level of access and b) highly predictable because with a bit of log or bash_history reading, said attacker can probably make an educated guess at when that was executed and narrow down the possible timestamps to be within reasonable brute-force territory.

So please do what every install script does: Simply generate a random password of sufficient length.

Finally:

I am contemplating raising an issue on their github stating that I should not have to set their SKIP_DATABASE_PASSWORD_COMPLEXITY_CHECK=true flag for such a password, and that they should consider the actual entropy of the password instead of just applying a set of simple rules.

Before doing that, please check the actual source and you'll find that your hash should already pass the checks almost every time (except the one-in-a-million where the hash is completely numeric or alphabetical). Unless your distro includes CrackLib, there isn't really much checking going on and the functionality is included as an example so you can write your own checks.

2
  • I'm aware of what threat modeling is but believe best practices should be followed at any scale where it's technically feasible. Using a secure password generation method over a dumb one requires almost no extra work on my end and costs me a massive boost in my infosec stackexcange reputation, not bad IMO. Also, while I have not scripted out the password generation, using a secure generator, it wouldn't matter if they knew how it was generated because they still wouldn't be able to reproduce it. Jul 26, 2022 at 13:43
  • @kirbyquerby the whole part is beside the point here, so I'll remove it.
    – Tom
    Jul 27, 2022 at 4:41
-1

There's a lot of moaning about how you're deriving your password. It is a little suspect but answers assume an informed attacker. Depending on the value of the thing being protected, it's likely fine. Even if you sourced the password from the most complex of randomness, if it randomly spat out only lower case letters, your actual question would still stand.

"Does the password contain [x,y,z]?" is easier to program and explain to users than entropy. So we're left with a well meaning but ultimately blind set of rules. Is randomly choosing only lower case letters from a larger set less good? Against, the attacker that is playing by the original rules, it's exactly the same. It does open one to an attacker playing by a lesser set of rules. But there is a password length which is likely too much to guess by anything other than an offline attack, if that.

Should the project loosen their standards? Probably not when the user could instead add an instance of each missing type to the end of the password instead. Or in this case choose an encoding which likely has all of the required character types (Base64?).

7
  • 3
    Assuming your attackers are uninformed is known as security through obscurity, and has a long history of being a bad idea. It's much safer to assume that, as Claude Shannon put it, "the enemy knows the system", and use systems that remain secure even when that's true. Jul 25, 2022 at 18:40
  • 1
    Objection to your 2nd paragraph. Complexity is a misconception created by lack of work on the subject in the 60s, the guy who proposed it has apologized for the mistake, and we're slowly unraveling the damage it's done. There's absolutely no point in telling people a password should contain X, least of all that it's "easy to explain" (it isn't, it's just technobabble people swallow, but TELLING is not explaining).
    – Tom
    Jul 26, 2022 at 10:44
  • This doesn't answer the question.
    – A. Hersean
    Jul 26, 2022 at 11:49
  • All threat models have to make a decision on how informed of an attacker they defend against, scale to threat.
    – foreverska
    Jul 26, 2022 at 15:59
  • I'm not wholly defending "does it contain" rules. The general public would opt for a 4 character password. Does forcing a rule set encourage bad patterns with reduced entropy compared to optimal? Yup, but it's better than the former. The general public need another solution than passwords.
    – foreverska
    Jul 26, 2022 at 16:00
-1

No, and not because of the Unix Timestamp. A hash digest is a hex string.

A hash digest has a limited character set (16). This is low hanging fruit for a brute force attack.

An informed attacker need only cycle through timestamps from time a to time b, given he can ballpark the year(s) of the timestamp this may be trivial.

In addition, it will be hard to remember, and therefore likely to be exposed by saved copies, vaults notwithstanding.

However it is suitably complex for a database connection string and transport neutral. Providing you secure access to the database with a tunnel to a private endpoint that is also firewalled, it is OK.

You would not use the unhexed value as it may not be transport neutral and may lead to unpredictable translations, escape sequences also notwithstanding.

The key here is not to share how this is generated at all, your own people would prefer not to know, as it grants the gift of plausible deniability.

A string is a string is a string. Too many academic answers here. If you do not tell anyone, it is not predictable. I defy anyone given a arbitrary hex string to reverse engineer the document it was generated from.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .