4

I am creating a website whereby users are given an account by invitation only, and are sent a unique code by post. Users can then log in (at least the first time) by entering the code only.

The goal of this is for it to be extremely easy to understand and use by non tech-savvy people.

  • User accounts will contain name, email, maybe address if the user wants to add it. No other sensitive information.

  • The site itself would not be of interest to anyone other than those invited, and will not be indexed by search engines.

If you imagine the users are receiving a piece of mail in the post which says something along the lines of:

 Please visit www.example.com
 Log in with your unique code:

            A6XH3

As for the code, it must be extremely easy to remember and enter.

  • I was planning four or five upper case alphanumeric characters - e.g. A6XH3 - because I don't want anyone to have to enter a long hash or complicated string. I think 6 characters is the limit that I would deem acceptable for people to enter in this format.

  • An alternative idea I had was to use two/three easy to spell words, such as [adjective] [noun] which would be more fun and seem less "techy" to the users - e.g. pretty blue flower - which would be more in keeping with the spirit of the site.

Caveat

Website administrators must be able to see all the users' codes in plain text, so they can mail them out in the first place and/or offer support to anyone unable to log in. They may also need to generate a new code for some reason, and tell the person directly.

Questions

  1. Is this secure enough for the context? i.e. The only people who know about the site are those invited, and there is no real motive for anyone else to try to force their way in.

  2. Would you use either of my methods of unique code generation, and if not what would you suggest as a better solution?

  3. Is there another way I could allow a simple login without compromising security or simplicity of use without a username?

Note: I am using PHP/MySQL if it is relevant.

4
  • 1
    The codes wouldn't necessarily have to be kept in plaintext. You could have a script that generates the codes, sends the email out, hashes the codes, stores them in the database, and throws out the plaintext. If a user has a problem, then just run the script again generating new codes and sending a new email. Feb 26, 2015 at 17:19
  • @EarlCrapstone Doesn't solve the problem of sending out the codes in printed media via postal service.
    – BadHorsie
    Feb 26, 2015 at 17:26
  • Ahh sorry I missed the wording about using the postal service. Feb 26, 2015 at 17:30
  • If the users have to register with name and email they must be at least familiar with how a password works... Can you give some degree of background on the requirement of keeping the password so simple? The fact that you believe the site wouldn't interest anyone else doesn't mean no one will try to mess with it. How much damage could an unauthorized access cause you?
    – JPCosta
    Feb 27, 2015 at 11:22

4 Answers 4

2

Ultimately, you are the one who will have to make the decision as to what system is secure enough for the context, because that will be based on your threat model, but we can certainly provide some information to help you make that decision.

So, a few points:

  1. The generation method should be a given. From the set of inputs at your disposal, (be they alpha-numeric characters, a list of words, or any other set of components a random subset of which will ultimately be the code) each element should be selected using a cryptographically secure psuedo-random number generator. So, that solves the problem of how to generate the codes, and leaves only the problem of what should the codes consist of.

  2. For randomly selected elements, the entropy, which determines the relative level of security is based on how many potential elements you're choosing from, and how many of these outputs you string together. So, for a 6 character code, using all 26 uppercase letters and 10 digits will give you just over 2 billion possible codes, (36^6, or 36*36*36*36*36*36) for ~31 bits of entropy. (36^6 is roughly equal to 2^31) Now, if we were taking about protecting password hashes against offline brute force attacks, this would not be nearly enough to be secure. In your case however, if it is as it sounds, and they're not really protecting anything but serving more to identify users on first access, then coupled with reasonable additional security measures such as rate limiting access attempts and securing the database and database access properly, it may be perfectly adequate.

  3. If you were, however, to use the Diceware list of 7,776 words, and choose three random words from the list, the number of potential codes would skyrocket to over 480 billion, (7776^3 or 7776*7776*7776) giving you over 38 bits of entropy. (7776^3 is between 2^38 and 2^39) Still not great for a user's password, but quite probably good enough for a default code. Besides, AOL used to use this system for default passwords for years, and it seemed to work well enough for them. (And they only used two words!)

  4. If you want to use your [adjective] [noun] construction, then you'll have to figure out how secure it will be based on the word list you use. For two words, you would multiply the number of words in the list of adjectives by the number of words in the list of nouns to come up with the number of potential random codes. A bigger number means more security. So, if you have 2000 adjectives, and 4000 nouns, your security level would be 2000*4000. If you added a second adjective, 2000*2000*4000.

So, now that you know how to gauge the relative strength of codes generated using different types of input components, you can make a more informed decision as to which will give you the margin of safety you need, and then there are a few other things to think about for the system as a whole.

  1. As mentioned earlier, rate limit code use attempts. For a niche system with a small userbase, there's no reason you should need to allow the system to process hundreds or thousands of code access attempts per second. The only thing that would cause those volumes of traffic would be an online brute force attack.

  2. Protect your database. If you have SQL injection vulnerabilities in your website, it doesn't matter how good your codes are...The attacker will just dump them from the database and use them at his leisure.

  3. Discard used codes. Since they're only used for initial access to the system, presumably the users can chose a password of their own at that point, and the code becomes redundant. They should not be left in the system in a state where they can be reused after that point to access the user's account.

From what you've said, it sounds like the level of risk here is relatively low, so I don't know that I would be too concerned, whatever you choose. Hopefully the guidance above will help you to be more comfortable with your decision, and better able to justify that the decision you end up making is indeed adequately secure for the system in question.

1

I have a similar approach for a few web services that I have worked on , this is effectively token based authorisation ..

To keep this more secure I would still handle all of the auth tokens in the same manner as passwords .

Also you might have to remember that if a user can change their token then it may be possible for them to create a collision with another users token.

6
  • Would you mind expanding on the details of what you're suggesting I do? Users won't be able to change their own token.
    – BadHorsie
    Feb 26, 2015 at 17:08
  • 1
    handling them as a password means a minimum level of entropy, which would mean a longer code Feb 26, 2015 at 20:47
  • @RichieFrame not exactly sure why you say this, but umm... Ok... Feb 26, 2015 at 22:53
  • 1
    @BadHorsie simply maintain a hashed and salted version in the database, replace the token with another token which can expire ( usually a session cookie ) , avoid transmission as plaintext or over HTTP get , instruct users to keep it secret, you know the usual things really. Feb 26, 2015 at 22:57
  • @DamianNikodem a 5 char alphanumeric code like that has around 25-bits of entropy, which is like a regular 4 letter, and it is essentially being used as a username, not as a password Feb 27, 2015 at 1:02
0

You have several options for codes like this. I assume your idea is to use the code as the primary user login, and there would be no separate password. You have several parts to the question, I will start with "is it secure?"

Short answer, probably not enough. And it is not just because of the context of invite only and no motive. There is always a motive, even if it is just "for the lulz". Just because the site is not indexed and is invite only, does not mean that some blackhat wont find it and want to play. They may not know that you have no potentially valuable information beyond the login. How much of a problem will it be if someone gets a copy of your database? How much of a problem if someones code gets stolen?

5 characters may be enough for an invite code, but as a login it is unreasonably short, even if there are a very low number of users. With the size of your code, you have between 30 and 60 million combinations depending on the generation algorithm and if you are limiting characters to avoid confusion "O vs 0". The code can always be broken into sections to make it easier to type, say A1C-B2X-YP3. 9 characters will be at least a trillion combinations.

In terms of generating the codes, one is shorter but random looking, the other is longer and natural looking. Choosing a natural language code means the user has to type more information, and also may limit the amount of combinations if they are ordered to appear natural like a sentence. How do you deal with a typos? What if a typo generates a valid login? Calling the natural language option a "passphrase" may improve things for the user, as the perception of what it is may influence the ability to recall it, and to not be intimidated by it. The other problem with a natural language code is that a user may not like some of the words, or their combination, they may find it offensive, distasteful, or have some bad memory. Some people really don't like the word "moist" for example.

As a user I would prefer a more "codey" looking code. There could be a client side check digit verification prior to the code being used to login. Limiting the amount of login attempts works a lot better if someone cannot enter an obviously invalid code. I use an algorithm to generate codes just like that using a pseudorandom permutation called Molybdenum, basically a custom block cipher resembling HIGHT. Internally it is 5 8-bit values, externally it is 8 5-bit values, encoded in 32 character alphanumeric, with "OIZS" omitted as to not confuse with "0125". Add a single check digit at the end, and it is 9 digits, which looks nice broken into 3 groups of 3. I routinely see much longer codes in mailings. New codes are generated by encrypting an incrementing counter, so they are guaranteed not to repeat. Generating codes randomly requires a check against all in-use codes to make sure there is not a collision. Using a permutation to generate codes means access to it must be limited.

You could also force a specific type of sequence like a Canadian postal code, which is alternating letters and numbers. NLN-LNL-NL(N) such as 5A9-F4E-0L0 would limit you to 4.6 billion codes, but may be easier to remember, and easier to tell when someone is having a problem. I would assume the users would not try to remember, but rather keep it written down somewhere.

If a code is used as an invite, short codes are ok, as long as they are time limited and one time use. I am assuming users will not have passwords, and only their user ID. In that case you could consider an invite code as an addition to the user ID, only used when someone has to call in for support as an additional authenticator. In this way they would use the invite code to get their user code when they sign up, then the invite code is deactivated, but stored with the account. Only the invite code would ever be mailed.

If you are not the victim of a targeted attack against your system, and you follow best practices for securing the site and database, you will probably be ok. There are many ways to store and process the login data, which is probably outside the scope of your question, that can effect the security of the system. Auditing the generation and lookup of codes by support personnel is a good idea. I have made quite a few assumptions here because of the limited information regarding the user base and site, hopefully this response is still relevant.

0

Yes, your method is acceptable, provided that:

  • your codes are generated randomly so they aren't easily guessed
  • each codes can be used only once, for a limited time
  • you limit brute-force attacks

If invitations time out and the code is discarded once used, and an attacker cannot rapidly try possible codes (e.g. you only allow 1 attempt per second) then you have sufficient security for the use case you describe. Obviously, you wouldn't want to do this for the invitation for the super-secret super-villian club.

There is a better way

Unless "by post" you mean actual physical mail, the better and very common way is to use a long random string and include that in the link directly. That way the user doesn't have to type anything and the random string can be long enough to make brute-forcing entirely impractical.

You must log in to answer this question.

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