1

I want to use token-based authentication where the user would log in with a username/password combination. The server would make sure the username and password match and then return a token which would be used by the client to make subsequent API calls. These token would expire after a certain amount of time (4 hours is what I'm thinking), after which the user would have to login in again.

The way I want to generate tokens is this : SHA256 hashes of 3 randomly generated strings (characters - [0-9,a-z,A-Z]), concatenated. I would store this token in a database table along with the username and the login time.

When an API request is made with this token, I would be able to get the user from the token.

I want to protect against brute force attacks.

I want to implement all of this in PHP. Is this approach good enough? If not, why? And what would be a better way to do it? Should there be a way to get the user just from the token (without looking up from a database)? If so, why?

I'm a newbie as far as security is concerned, so detailed explanations would be greatly appreciated.

  • "good enough" for what? What do you want to secure against? – schroeder Sep 2 '16 at 15:55
  • @schroeder 1. Against someone being able to brute force a token? 2. Do I need to have a way to associate a token with a particular user to add an additional check on the token. If so, how can I do that? – Ayush Sep 2 '16 at 16:17
  • @Ayush I would suggest you edit your question with this comment so that it is easy for people to understand what you're securing against? – Limit Sep 2 '16 at 16:28
  • How long are your randomly generated strings, and what is the source of the randomness? – Justin LeMay Sep 2 '16 at 16:33
  • @JustinLeMay I was thinking some kind of built-in random string generator that php has. But others have already indicated that isn't good enough. – Ayush Sep 2 '16 at 17:35
2

The way I want to generate tokens is this : SHA256 hashes of 3 randomly generated strings (characters - [0-9,a-z,A-Z]), concatenated.

There is no point in hashing random data.

Avoid use of the default random functions as those are insecure. Use a Cryptographically Secure PSRNG to generate the random data. For example, on UNIX-like systems you can read the data out of /dev/urandom. I expect PHP has a platform-independent documented way to create Cryptographically Secure random data.

The token should have 72 bits of entropy or more.

I would store this token in a database table along with the username and the login time.

As you may know, you should never store user passwords, but use a Slow Hash such as bcrypt.

Similarly, for session tokens, you should not store those either, but use a Fast Hash for these. So your database should store an SHA-256 hash of the token. Avoiding storage of the original token is helpful for certain key management schemes or edge case attacks (i.e. limited SQLi) that you may have down the road.

When an API request is made with this token, I would be able to get the user from the token.

Sounds good.

I want to implement all of this in PHP.

These concepts are language agnostic. :-)


You should absolutely make sure you are using HTTPS/TLS to encrypt the connection and verify the server's identity before sending any sensitive authentication details such as passwords or session tokens.

I would recommend you also check that the IP address matches what it was when the user first signed in. If the IP address changes during the session, that may be a clue that the token was stolen.

Unfortunately mobile phone users, and users in certain foreign countries have frequently changing IP addresses, so such a restriction would not work for them.

  • How can I make sure that the token has at least 72 bits of entropy? Also, how many characters should the token have? – Ayush Sep 2 '16 at 17:33
  • 72 bits = 9 bytes of fully random values (0-255 each), or if you are restricted to alphanumeric, about 12-13 characters. – John Wu Sep 2 '16 at 19:09
  • I usually just grab 9 bytes (72 bits) from /dev/urandom, and then output it either as a Base64 (comes out to 12 characters) or Hex string. (comes out to 18 characters) – Bryan Field Sep 2 '16 at 21:10
0

The "standard" approach to this (in my opinion, having done this recently) is to use the OAuth Resource owner flow.

This means that you do exactly what you suggest, and create an "access_token" that is sort lived, then optionally, a "refresh_token" that is longer lived and grants you the ability to get a new access_token without re-inputting your credentials.

The access_token may, or may not, be stored in you application's datastore for revocation purposes, however, it's not a "pointer" to something in the database. It would contain all the information you need for the request. So that's the user identifiers, roles, origins, etc.

The access_token is generally then sent as an authorization header, that is parsed by some kind of middleware, and presented to your code as the raw data.

I'm not sure on technologies within PHP for that, but the terms you should be looking for are: OAuth 2.0 and bearer tokens.

My last piece of advice is, don't do it yourself, there are people who spend their life doing this. You are more likely to make yourself insecure by trying to do this on your own.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.