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.

ThisGuyCantEven
  • 497
  • 4
  • 10
  • 1
    Related: https://security.stackexchange.com/questions/226935/write-a-python-or-c-program-to-guess-the-key – mti2935 Jul 24 '22 at 10:41
  • 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 '22 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 '22 at 18:28
  • 9
    why use a hash as a password over a true random gen password? Is this just curiosity? – CaffeineAddiction Jul 24 '22 at 19:08
  • 2
    What you're suggesting is called [key stretching](https://en.wikipedia.org/wiki/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. – Bruno Rohée Jul 25 '22 at 13:45
  • Answers are good at explaining how OP's method is wrong but don't address the question about the complexity check and the need for capital case characters. – Jérôme Jul 25 '22 at 14:53
  • 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 '22 at 17:30
  • To be brief: definitely not. See answers. Unless you keep the password-generation process secret (which is bad: security through obscurity is not sustainable), the hashing does not add any "randomness"... because it is deterministic. It is likely true that the hash output is not "compressible" (by standard compression algos), but that does not save you if/when someone knows your process. – paul garrett Jul 25 '22 at 22:11
  • if there's a timestamp that correlates with when this is done to within a second, there could literally be no entropy at all. adding in insufficient randomness doesn't hurt in itself though. you need way more than a timestamp. you should at least add a long random phrase or dice rolls. entropy need not have weird chars; just randomness. – Rob Jul 26 '22 at 02:14
  • example of "entropy". roll a 16-sided dice to get 4 bits. whether it's encoded as binary in base64, or as ascii A-F, or as words mapped to bit combinations does not matter. if you can write it down, 64 rolls of a "16-sided dice" is 256 bits of entropy. i added such entropy as a parameter to supplement a terrible random number generator in MySQL before. – Rob Jul 26 '22 at 02:20

6 Answers6

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.

CaffeineAddiction
  • 7,567
  • 2
  • 21
  • 41
Steffen Ullrich
  • 190,458
  • 29
  • 381
  • 434
  • 30
    Note: I would suggest using urandom instead of random, for the reasons explained [here](https://security.stackexchange.com/a/3939/72852). – Kevin Jul 24 '22 at 06:16
  • 1
    @Kevin What about using something like `/proc/sys/kernel/random/uuid` – ThisGuyCantEven Jul 24 '22 at 13:20
  • 3
    @ThisGuyCantEven That question is answered here: https://stackoverflow.com/questions/5873099/is-proc-sys-kernel-random-uuid-strong-keying-material TL;DR: still not secure. – Ruben_NL Jul 24 '22 at 13:50
  • @SteffenUllrich I have taken the liberty of combining your answer with the other correct one and providing two more possible solutions. – ThisGuyCantEven Jul 24 '22 at 16:32
  • 4
    what is wrong with `head -c32 /dev/random` (or urandom)? `dd` is a religion. – user253751 Jul 25 '22 at 11:28
  • Does the sha256 actually add anything here, given that the input is of the same length and coming from a (CSP)RNG? – Tomeamis Jul 25 '22 at 14:28
  • 1
    @Tomeamis: like I said, the sha256 does not add any entropy. So it was pure cosmetic when used with `date`, it is still pure cosmetic when used with a random source. The only value added is that sha256sum gives a text string and not binary data. – Steffen Ullrich Jul 25 '22 at 15:48
  • 1
    @Kevin If you update your Linux kernel, you will not find any significant difference between /dev/urandom and /dev/random. They are being merged together. – A. Hersean Jul 25 '22 at 16:00
  • 1
    Why not just `openssl rand -base64 33`? OpenSSL is present on pretty much any modern system, and base64 guarantees the output will be representable in ASCII. Or is the kernel random of a higher quality? – jaskij Jul 25 '22 at 16:06
  • 2
    @A.Hersean while you are correct, a lot of systems, especially server systems, are running older kernels. So the advice to use `/dev/urandom` is sound. – jaskij Jul 25 '22 at 16:07
  • @jaskij This is security.SE, where the first advice is to keep your system updated. – A. Hersean Jul 25 '22 at 16:13
  • @A.Hersean true, but one could still be on an older LTS release. They are, after all, still getting security fixes. Correct me, but from a security perspective 4.9.324 is as valid as 5.15.57, right? – jaskij Jul 25 '22 at 16:16
  • 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. – Steffen Ullrich Jul 25 '22 at 16:21
  • 1
    @SteffenUllrich you are completely right. My bad. – jaskij Jul 25 '22 at 16:32
  • 1
    i really like the suggestion of: `head -c32 /dev/urandom | base64` – Rob Jul 26 '22 at 02:39
  • 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`. – Steffen Ullrich Jul 26 '22 at 06:12
  • @Kevin: On a modern system `/dev/random` and `/dev/urandom` are identical in kernel. The distinction is passing away. – Joshua Jul 27 '22 at 02:23
  • @user253751 - `dd is a religion`, needs a minor clarification: there are actually valid technical reasons it's necessary to sacrifice a young goat to `dd`. – Jason Jul 27 '22 at 07:03
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.

Kevin
  • 916
  • 6
  • 12
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackexchange.com/rooms/138022/discussion-on-answer-by-kevin-is-a-sha256-hash-of-a-unix-timestamp-a-strong-pass). – schroeder Jul 25 '22 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
ThisGuyCantEven
  • 497
  • 4
  • 10
  • 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 – Steffen Ullrich Jul 24 '22 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 – Steffen Ullrich Jul 24 '22 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 '22 at 09:37
  • 1
    If anyone is wondering about the `${1:-64}` BASH notation in this answer (specifically the `:-`), see https://stackoverflow.com/a/15737116/241812 – parkamark Jul 25 '22 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.

Tom
  • 10,201
  • 19
  • 51
  • 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. – ThisGuyCantEven Jul 26 '22 at 13:43
  • @kirbyquerby the whole part is beside the point here, so I'll remove it. – Tom Jul 27 '22 at 04: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?).

foreverska
  • 1,712
  • 11
  • 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. – Gordon Davisson Jul 25 '22 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 '22 at 10:44
  • This doesn't answer the question. – A. Hersean Jul 26 '22 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 '22 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 '22 at 16:00
  • It's a bit rambly. In theory there's limited risk to a pseudo-random long password with a limited characterset. But the project isn't wrong for using the standard. – foreverska Jul 26 '22 at 16:00
  • The risk is in fact so limited that just about every cloud provider routinely uses them. – mckenzm Dec 06 '22 at 09:46
-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.

mckenzm
  • 487
  • 2
  • 6