5

I need to generate random passwords when importing new users from an external source. I'm currently doing it by taking a random assortment of 8 lowercase/uppercase letters, and numbers. I am also using Ruby's rand as a PRNG. Is this cryptographically secure?

123
  • 235
  • 1
  • 6
  • 13
  • 1
    The popular web comic XKCD did a very amusing and informative post [ [Link](https://xkcd.com/936/) ] on this once. There has also been a lot of discussion [ [Link](https://security.stackexchange.com/questions/62832/is-the-oft-cited-xkcd-scheme-no-longer-good-advice) ] over how accurate the information was. Regardless of the opinions on the matter, a few decent passphrase generators have arisen from the post and discussion, such as [XKpasswd](https://xkpasswd.net/s/) – 0xSheepdog May 22 '17 at 15:19
  • 1
    Your edit changed your question, somewhat invalidating existing answers (mine among them). In cases like these, I would generally recommend asking a new question instead of changing an existing one (it seems that you really have two or even three questions; is Ruby's rand cryptographically secure, is generating 8 char alphanum passwords a good idea, and possibly one about the password generation system as a whole (we would need more information about it to answer that though)). – tim May 22 '17 at 17:59
  • 1
    I think you may be asking the wrong question. Are you sure you "need" to generate random passwords? There are likely better alternatives when importing users from another system. – TTT May 22 '17 at 18:05
  • @tim Fair enough, probably should have asked an additional question. Although I don't think the edit invalidated your answer - it was valuable to me, hence the upvote :) – 123 May 22 '17 at 18:11
  • 1
    @123 Ok, maybe not invalidated, it's probably still somewhat related to the question. Either way, I'm happy that it helped :) And yes, my comment was more of an fyi for the future. As there are now additional answers, rolling the question back and asking a new one would invalidate them, which wouldn't be good. – tim May 22 '17 at 18:17
  • What is your threat model, and how good are your users at changing passwords? When I was an admin, I would pick a random 2 digit number, and set their initial password to `UnsafePassword43` or something like that. Figured it'd remind them that they should change it because I know it. Also, by making it that weak, it was easier to later to a scan to see who had actually changed their password -- identified trouble users before the trouble arrived! – Cort Ammon May 22 '17 at 20:40
  • If you generate a random password, how is the user going to know it? Are you going to write them down in plain text somewhere and provide it to them? If they're just going to reset their passwords anyway (which I hope you're forcing them to), why do you need *any* password stored? Couldn't you just put an invalid hash in and let the authentication system fail? – jpmc26 May 22 '17 at 23:07

8 Answers8

8

First of all, you need to use a secure random number generator, like Ruby's SecureRandom.

Second, you should choose a target security level for the generated passwords, i.e., how hard should they be to crack? Security levels are often given in bits, i.e., the base 2 logarithm of the number of distinct equiprobable passwords. In simpler words:

  • A 64-bit security level means that there are 2^64 distinct passwords, and your system is just as likely to be choose one as any of the others;
  • A "random assortment of 8 lowercase/uppercase letters and numbers" is 62 distinct characters, which means that choosing one such character at random provides log2(62) ≈ 6 bits of security. Choosing 8 such characters independently at random provides log2(62) * 8 ≈ 48 bits of security.

48 bits is crackable in practice for a really dedicated attacker; I would recommend about a 64-bit security level as the bare minimum for passwords, and I prefer about 80 bits for my own. With lowercase/uppercase letters + digits, you need 11 random characters for a 64-bit security level, and 13 characters gives you a 78-bit security level.

Before an edit your question asked about the effect of adding symbols to your passwords as well bumps the alphabet size to about 95 characters, and log2(95) ≈ 6.6, which brings those password sizes down by one character: 10 characters for a 64-bit password and 12 for a 79-bit password. If you're generating passwords at random, you can therefore see that it's not a huge effect.

Luis Casillas
  • 10,181
  • 2
  • 27
  • 42
  • where is your math showing the speed of various attacks vs the strength of a password? – atk May 23 '17 at 03:21
  • 1
    @atk: That's very straightforward. If the password guessing speed is `s` guesses/second, and the password strength is `n` bits, then `(2^n / s)` is how long the attacker takes to try all passwords. On average the attacker succeeds halfway through, so `2^(n-1)/s` is the average time to crack an `n`-bit strong password. – Luis Casillas May 23 '17 at 17:27
  • that's the formula for time taken, not actual time taken. What really matters is *the amount of time it actually takes to crack the password of the length you recommend, vs the amount of time that the password will be live*. hashcat provides good baseline attack speeds for various algorithms, from which time can be calculated. – atk May 24 '17 at 02:36
  • also, that's only for offline attacks. it's equally important to calculate the speed at which the attacker can test a single password across all users. If, for example, you have 2^(n-1) users with live randomly generated passwords at any given time, then one of them is likely to have the guessed password. If the server(s) can support all of those users logging in simultaneously, then the attacker can use the server's computing resources to perform the attack. – atk May 24 '17 at 02:41
6

In Ruby, you can simply use SecureRandom.hex for random passwords that the user needs to change.

[1] pry(main)> require 'securerandom'
=> true
[2] pry(main)> SecureRandom.hex
=> "c3c4fe04dcc0d388fa37fc5991423a5d"
[3] pry(main)> 

It uses the OS-provided secure random number generator, while the rand() function is a Mersenne Twister (easy to predict once you see the output).

The default length is perfectly fine as well.

Riking
  • 304
  • 1
  • 9
5

8 lowercase/uppercase letters, and numbers

This is the bare minimum of a weak password policy. Especially 8 characters are not enough.

As you are generating your passwords, why restrict yourself to passwords which are quite weak and easily bruteforced? I would suggest at least 64bits, but there is really no good reason not to go with 128/160, which would be more secure.

You will also have the problem of distributing the passwords, which will likely be insecure (probably email?).

Because of this, I would strongly suggest to make these one-time only passwords which the user must change after the next successful login (so basically it becomes a password reset token).

tim
  • 29,018
  • 7
  • 95
  • 119
  • There is a good reason not to go with 128- or 160-bit passwords, which is that they'd be hella long. – Luis Casillas May 22 '17 at 17:39
  • 1
    @LuisCasillas ~20-30 characters (example: `HCSmhvWyiRjfOtNLqut3`) may sound like much, but seems fine to me, especially if you consider that the user only uses it once. Of course, it depends a bit on the use-case. If it's eg send via snail mail and needs to be typed in via smartphone, it would indeed be a usability issue. If passwords should be generated that the user continues to use, that would be a different issue - one I would [recommend against](https://security.stackexchange.com/questions/85934/why-does-the-user-pick-the-password/85935#85935). – tim May 22 '17 at 17:54
  • Depending on the system and the attacker, for example if we're only looking at online brute-force, 8 characters randomly could easily provide appropriate security. when discussing brute-force it's important to differentiate between online brute-force (where realistically the appropriate control is anti-automation and account lockout) and offline brute-force where probably password storage algorithm is likely the most important control (along with password length). AFAIK with bcrypt used (and a decent work factor) 10 chars pure random would deter most attackers, even offline – Rory McCune May 22 '17 at 20:25
2

The way you do it is generally fine.

Make sure you use a secure random number generator. Some PRNGs create predictable output, making it possible to guess another user's password from my own.

The more possible outcomes your algorithm has, the more secure the password will be. This means that the longer the password, the more secure it is. However, a longer password will also be harder for the user to type. You use eight characters, which is a bit low. I recommend at least 10 characters.

In the same way, including punctuation characters increases the security a bit.

To make passwords easier for your users, you may want to remove characters that look alike, such as 0, o and O. There are also algorithms that create somewhat rememberable passwords, such as "NaughtyChopstick21@". However, it is often better if users use a password manager or create a memorable and secure password themselves.

Sjoerd
  • 28,707
  • 12
  • 74
  • 102
  • I am using Ruby's `rand`. Do you know if this is cryptopgraphically secure? – 123 May 22 '17 at 15:16
  • 3
    @123 No, it is "a modified Mersenne Twister" [(source)](https://ruby-doc.org/core-2.2.0/Random.html) –  May 22 '17 at 18:31
1

Your password requirements could be better but will probably work as a temporary password. I'd be more concerned about how you are going to distribute those passwords. Probably by email? If you are that is very insecure. If you do go this route you should allow the passwords to be used only one time.

rand is not cryptographically secure. I would look into using sysrandom instead.

Abe Miessler
  • 8,155
  • 10
  • 44
  • 72
0

For randomly generated passwords there are two important measures:

  • Make the entropy of the password high enough
  • Make it as user friendly as possible.

You need to decide how many bits of security is necessary. 8 alphanumeric characters does not provide enough entropy, there are two ways you can improve that:

  • Use a larger set of possible characters
  • Use a longer password

Making the password longer is the more efficient of the two at increasing the entropy of your passwords. It is also the most user friendly approach because the more different characters you use the harder they will be to type. And even if they are not going to be typed by the user, the more different characters will also make the password harder to copy-paste and more likely to trigger interoperability problems.

I would say you have already gone too far by using all the alphanumeric characters. To make it more user friendly I would recommend sticking with only lower case letters. And to make it secure I would recommend to make the password long enough.

Assume your security goal is 64 bits, you could either go with:

  • 14 random lower case characters
  • 10 random characters from all printable ASCII characters

The inconvenience of having to deal with all the special characters is much worse for the user than the inconvenience of having the generated password be 4 characters longer.

kasperd
  • 5,402
  • 1
  • 19
  • 38
0

With any password system and it's security you really have to consider more than just the length/randomness of the password, it's really more important to think about how they'll be attacked.

There's two ways passwords get attacked

  • Online brute-force. Here the attacker is attacking the user's password via your system. Unless your user has chosen a password that can be guessing before the account lockout kicks in, the attacker won't succeed in getting in. 8 generally random characters are very very unlikely to be guessed in this scenario. Important things for you to do here is ensure your system blocks attackers and try to ensure users don't choose very common passwords like 123456.

  • Offline brute-force Here the attacker has a copy of your password database (presumbably via a flaw such as SQL Injection, if it's a web based system) and is trying to crack the passwords. Likely the most important control here is what algorithm you're using to store the passwords. Here's I'll defer to Thomas Pornin to explain the options but it's worth noting that ruby has decent library support for bcrypt (Rails uses it for SecurePassword). Password length is also important here as is randomness, but cracking 8 char generally random passwords hashed with bcrypt and a decent work factor, is a non-trivial thing for most attackers. Without knowing your risk model I can't say it'll be fine, but I don't see it as dreadfully bad either.

On your point about cryptographically secure, as others have said ruby SecureRandom is better than Rand

Rory McCune
  • 60,923
  • 14
  • 136
  • 217
0

Use five-word, randomly generated passphrases instead. You could adapt the wordlist found here:

https://www.npmjs.com/package/niceware

Make them all lower case - easy to type, easy to memorize if needed.

Royce Williams
  • 9,128
  • 1
  • 31
  • 55