Tag: information-security

Forget what everyone tells you makes a password strong

Yes, the title is a little bit click-baity. But please bear with me for a moment.

The Web is replete with the traditional advice on “how to create a strong password”. A quick web search for secure passwords brought up, among many others:

Really, I could go on. Except I won’t.

I’m here to tell you that adding random symbols to your password does not make it appreciably more secure. Even mixing letter case (lowercase and uppercase) doesn’t help a lot.

In my password tips, I mention a few different ways of generating passwords which have a work factor of approximately 277, which is plenty enough for most people even if the place where the password is used messes up the basics of handling passwords. In brief, the work factor is simply a number that expresses how hard a password (or other secret) is to guess; the higher the work factor, the more secure it is.

Assuming that a password is generated at random, mathematically, the work factor is simply the size of the symbol set to the power of the length of the password. The work factor is commonly expressed in bits (as a power of two), in which case you need to take the two-logarithm of this value. Really, this likely sounds more complicated than it is. Again, just keep in mind that as long as the password is generated at random, the larger the number, the more secure the password is.

An alphabetical password, using the lower-case English letters only (a-z), has a symbol set size of 26. An alphanumeric password with mixed case (a-z, A-Z, 0-9) has a symbol set size of 62 (which is 26+26+10). Assuming 20 symbols (for example, the set !?@#$%&{}[]+-*/\.,<>), this pushes us to a symbol set size of 82.

Now, what does it take to get to 277 with each of those?

With a simple alphabetical password, not varying case, 16 characters gives a 275 work factor, while 17 characters gives 280. Since we don’t have half-characters, I’ll call this 17 characters.

Mixing upper and lower case, 13 characters gives 274, and 14 characters gives 280. Again, lacking half-characters, I’ll go with 14.

Adding digits, 13 characters gives 277 for the upper- and lower-case case, as does 15 characters for single-case alphabetic plus digits.

Adding those 20 symbols to the mixed-case alphanumerics symbol set, 12 characters gives 276 (which I figure is close enough to our 277 target for a meaningful comparison).

Or, laid out as a table:

Symbol setLeast characters for ≥277Example password
a-z17quoakithoozafebau
a-z, 0-915leyie7aineih8mu
a-z, A-Z14voiWahnuuZuxuu
a-z, A-Z, 0-913Eu0ighaeJ2aex
a-z, A-Z, 0-9, 20 symbols12ye3M&e5rae{f
Password lengths for a given security level, by symbol set

Indeed, compared to only a lower-case English letters password, to keep approximately the same security level, with all of this we still only reduced the length required from 17 characters to 12 characters. And in doing so, we went from a password similar to kohthaephaeguahxe to one similar to Ee*ix&p0chFi.

Although not directly spelled out, this truth of mathematics is almost certainly a part of the reason why NIST (which sets information security standards for US government organizations) in 2017 changed their previous advice on password complexity, and now say, among else:

Verifiers SHALL require subscriber-chosen memorized secrets to be at least 8 characters in length. Verifiers SHOULD permit subscriber-chosen memorized secrets at least 64 characters in length.

[…]

Verifiers SHOULD NOT impose other composition rules (e.g., requiring mixtures of different character types or prohibiting consecutively repeated characters) for memorized secrets.

NIST Special Publication 800-63B, section 5.1.1.2, July 2017 (as updated through 03-02-2020)

Certainly, if you are using a password manager to handle that password (and you almost certainly should), including additional types of symbols in your password won’t exactly hurt. But doing so is not the password strength panacea it is often presented as.

If you are using a password manager to handle the password, then you shouldn’t be typing it in anyway, in which case the length savings for a similar security level is essentially irrelevant.

Also, when people think of “including digits and symbols in the password”, more often than not this means doing things like replacing the letter O with the digit 0, or replacing the letter A with the symbol @, or putting some easily typed symbol like ! or % at the end of the password. Password crackers have been on to this game for years and years. Technically, doing this does increase security, but it does so only by a miniscule amount.

For to go beyond even just a-z in passwords to provide any significant benefit, the password must actually be randomly generated, and it only really helps when character count is the limiting factor. Increasing password length provides huge returns in password security even without extending the character set; for example, a 20 characters single-case alphabetic password already has a work factor of 294 (219 or about 500000 times stronger than one 16 characters long; a mere four additional letters).

In the introduction to the documentary film Citizenfour about the 2013 Edward Snowden revelations, a passphrase attack rate of one trillion guesses per second is mentioned for PGP secret keys, and has likely served as a good rule of thumb since then. The PGP S2K (string-to-key) function is unfortunately notoriously weak by modern standards, and top-of-the-line CPU transistor count has increased by roughly a factor of 10 since then, so to at present assume a rate of ten trillion guesses per second for a highly motivated, highly resourceful adversary is probably not unreasonable. (Most people don’t need to worry about the NSA trying to figure out their social media password!) This is approximately 245/s. Because of how exponents work out, you can simply subtract this exponent from that of the work factor of your password to determine how long it would take to crack.

A 277 work factor password, at that attack rate (given present-day technology) would have a reasonably guaranteed breach in 277-45 = 232 seconds, and on average succumb to the attacker in half that time. Half of 232 seconds is approximately seventy years. And again, this is against a highly motivated, highly resourceful adversary.

To within experimental error, nobody is going to spend even 70 years on cracking that one password. And if you are worried, add two more letters to it for an 18-19 characters password; doing so brings the average out to about 270 years.

This is not to say anything but to make sure you use strong passwords. But do know that simply adding a non-alphanumeric character to a password won’t necessarily significantly increase the security of it, and doing so properly will likely make your password a good bit harder to type correctly.

Using per-account SSH key files with OpenSSH

OpenSSH is a SSH server and client, in current incarnations originating on OpenBSD but used on many Unix-like operating systems, including being a common choice of SSH server and client alike on many Linux systems.

Unfortunately, it (and perhaps other SSH clients as well) in the default configuration and typical use has a somewhat nasty information leak when used with key pair authentication.

This is because of the interaction between three things.

First, a SSH client will, during authentication, offer a series of keys to the server, effectively asking for each “will you let me authenticate as this user using this key?”.

Second, the initial exchange that offers each key in turn contains enough information that the key can, effectively, be uniquely identified. It must for the server to reach a meaningful answer.

Third, the OpenSSH SSH client will, by default, try every key that it knows about to find one that the server is willing to accept for a connection attempt.

All of this would already be bad enough from a potential information leak perspective, but in isolation, it still largely only allows a rogue server to learn what keys exist on the connecting system and user account while the user is actively connecting to it, but nothing more about them or what other context those keys exist within. Not great, but not horrible.

However, additional information exists. For example, as noted by Andrew Ayer, GitHub actually publishes each user’s authorized SSH keys. This in itself isn’t a huge problem either; only the public keys are published, so as long as the keys are secure enough, there’s no real risk of compromise of a person’s GitHub access.

Put all of this together, though, and it becomes quite possible for a SSH server to derive the GitHub username of a connecting user, if that person uses OpenSSH with its defaults.

All of a sudden, a SSH server can potentially deanonymize a connecting person by, with a rather high degree of certainty, associating the connecting user with a GitHub user account.

Similarly, if multiple services publish keys in this manner, it’s fairly easy to collate them together and look for matches. If the same key is authorized for more than one account, or for accounts with more than one service, there is a rather high probability that those accounts belong to the same person, even if there is nothing else to suggest this.

A necessary first step to protect against this information leak is to use different key pairs for each such service. ssh-keygen has -f to specify the base file name to which to save the newly generated key pair; ssh has -i to specify the identity file to use; and ssh_config (usually ~/.ssh/config and /etc/ssh/ssh_config) has the IdentityFile directive. However, this doesn’t necessarily prevent the SSH client from presenting other known keys during connection key exchange.

To prevent the latter, use the IdentitiesOnly yes directive in ssh_config. This causes the SSH client to only present any explicitly configured identities during public key authentication, protecting against the server you are connecting to learning more about what keys you have on the system you are connecting from than you intended.

Unfortunately, setting these on a per-host basis in the SSH client configuration quickly gets tiresome if you have multiple accounts, and is error-prone.

Thankfully, OpenSSH offers macro expansion in the IdentityFile value based on information about, among other things, your local user account and the connection you are making. (See the ssh_config(5) manual page for a full list and description of the macro expansion tokens.) This is especially useful in conjunction with wildcard Host stanzas to provide a set of defaults.

Putting all this together you can, for example, put at the bottom of your ssh_config something like

Host *
IdentitiesOnly yes
IdentityFile %d/.ssh/keys/%h/%r/current
PasswordAuthentication yes
PubkeyAuthentication yes
PreferredAuthentications publickey,password
User nobody

and together with it (I prefer above, with the Host * providing the defaults), a Host stanza to simply set the correct username

Host ssh.example.com
User myself

With this in place, when you connect to ssh.example.com, OpenSSH will offer only the key pair in ~/.ssh/keys/ssh.example.com/myself/current for authentication. (%d expands to the path to your local home directory; %h expands to the name of the host you are connecting to; and %r expands to the remote username.)

To then add keys for a new account, use something like

$ mkdir -p ~/.ssh/keys/sftp.example.net/u1234567
$ ssh-keygen -f ~/.ssh/keys/sftp.example.net/u1234567/current

and either specify the username when connecting (for example, sftp u1234567@sftp.example.net ...), or add another Host stanza to your ssh_config specifying the username

Host sftp.example.net
User u1234567

If you don’t do either, the OpenSSH client will try to read the key pair from ~/.ssh/keys/sftp.example.net/nobody/current (because of the Host * stanza’s User nobody), find nothing at that file location, and not offer any key pair at all for authentication to the server. In the example case above, it will then fall back to password authentication. Since nobody likely doesn’t have a valid password, this effectively blocks the login attempt in a non-destructive manner while leaking minimal information either over the network or to the remote server.

Setting this in your ssh_config as defaults like this also neatly fits into many tools’ SSH integration, where it can be tricky to pass additional parameters, especially if those are dependent on for example where you are connecting to.

With this in place, you can still use the same key pair for more than one account by putting the actual key pair files in some location and symlinking from the location expanded to based on the IdentityFile directive. However, instead of the same key pair being used by default for every account everywhere unless you take special care to use separate key pairs for each account, using the same key pair for multiple accounts now becomes the active, rather than passive and by default, choice.

It also becomes much easier to rotate a key pair if you ever have reason to, because with this in place, you don’t need to stop to consider where it’s used; where it’s stored locally tells you the one remote account for which it’s being used.

Someone could still look at your authorized SSH keys on GitHub, but now it’s very little more than an anonymous blob of encoded public key data that can’t be matched against any other keys that they might encounter.

Powered by WordPress & Theme by Anders Norén