102

I have developed a backend REST API for a mobile app and I am now looking to implement token-based authentication for it to avoid having to prompt the user to login on every run of the app.

What I had in mind was on the initial request the user sends their credentials using Basic authentication over SSL. Once the server authenticates the credentials it creates a secure token and sends it back to the user so they can use it in subsequent requests until the token either expires or is revoked.

I am looking for some advice as to how I can generate a token which won't be susceptible to things like MoM/Replay attacks as well as ensuring the data stored within the token cannot be extracted out.

I am going to use the following approach to generate the token which I think would prevent any data from being extracted from it. However, I still need to make sure it's not vurnerable from other attacks.

The API will only be accessible over SSL but I am not sure if I can rely solely on this from a security perspective.

3
  • What about OAuth? Sep 3, 2012 at 15:21
  • 1
    @MikeWeller OAuth is probably the universal solution to this problem, however, time constraints & complexity of development is where it falls down. Also, OAuth is probably a little bit overkill as there are no plans to open the API up to 3rd parties at the moment. The sort of token-based system I want to implement isn't far off what OAuth does, it's more like Twitters version of XAuth whereby you skip the whole login request part.
    – James
    Sep 3, 2012 at 15:33
  • 2
    Be very careful with writing your own session management mechanism (which is essentially what you are proposing). There are dozens of common errors that inevitably occur in every new session management mechanism, which will affect yours, too. You should seriously consider how you can use an existing mechanism instead of rolling your own
    – atk
    Sep 8, 2014 at 4:39

3 Answers 3

83

The "authentication token" works by how the server remembers it.

A generic token is a random string; the server keeps in its database a mapping from emitted tokens to authenticated user names. Old tokens can be removed automatically in order to prevent the server's database from growing indefinitely. Such a token is good enough for security as long as an attacker cannot create a valid token with non-negligible probability, a "valid token" being "a token which is in the database of emitted tokens". It is sufficient that token values have length at least 16 bytes and are produced with a cryptographically strong PRNG (e.g. /dev/urandom, CryptGenRandom(), java.security.SecureRandom... depending on your platform).

It is possible to offload the storage requirement on the clients themselves. In the paragraph above, what "memory" should the server have of a token ? Namely the user name, and the date of production of the token. So, create your tokens like this:

  • Server has a secret key K (a sequence of, say, 128 bits, produced by a cryptographically secure PRNG).
  • A token contains the user name (U), the time of issuance (T), and a keyed integrity check computed over U and T (together), keyed with K (by default, use HMAC with SHA-256 or SHA-1).

Thanks to his knowledge of K, the server can verify that a given token, sent back by the user, is one of its owns or not; but the attacker cannot forge such tokens.

The answer you link to looks somewhat like that, except that it talks about encryption instead of MAC, and that's:

  1. confused;
  2. confusing;
  3. potentially insecure;

because encryption is not MAC.

14
  • 2
    +1 This is more along the lines of the type of answer I am looking for, thanks. You mention that the proposed solution for generating tokens is potentially insecure and I understand why (if it's encrypted there is the possibility for it to be decrypted). However, it's encrypted using the machine key of the server (see here) so am I right in saying it's secure as long as my server is physically secure and no-one get's a hold of the decryption key?
    – James
    Sep 3, 2012 at 14:59
  • 1
    @James: what I mean is that the authentication token is secure as long as the attacker cannot build a fake one. Encryption does not protect against that. For instance, if using a stream cipher like RC4 (data is encryted by XORing with a key-generated pseudorandom stream), it would be trivial for a user to authenticate under his name, then fiddle with the bits to make a new valid token with another name of his choosing (as long as it has the same size as his name) (and I have seen that in a deployed banking system !). Really, if you need integrity, use a MAC. Sep 3, 2012 at 15:06
  • 1
    Based on your comments here is what I am doing (server-side). Generating a secret key of 256 bits using a .NET RNG. Then generating a HMAC using SHA12 of the username + creation date of token (using the secret key). Then finally, generating a final HMAC of username + creation date + HMAC(username + creation date) again using secret key. Does that sound about right? I can post code if need be.
    – James
    Sep 3, 2012 at 20:41
  • 2
    For the record, the standard ASP.NET functionality linked in the original question does involve a MAC. The method name, Encrypt(), is misleading. What it actually does includes both an an HMAC (with SHA256) and encryption (with AES).
    – Erv Walter
    Sep 16, 2012 at 22:18
  • 1
    @ThomasPornin Thank you for a very good answer. When you say that "It is possible to offload the storage requirement on the clients themselves", does it mean that the server does not need to store any information whatsoever of issued tokens? As a token is signed by the server itself and carries all relevant information (username and expiration), the server does not need to query its database to tie the token to a user and check for expiration - all data is available in the token and cannot have been altered if its signature is checked. Correct? Jul 14, 2016 at 13:43
38

In short, you should use a cryptographic strength one-time random token, and hash it in the database.

The token

  • must be allowed to be used only once,
  • must only be usable for the user it was created for,
  • must only be sent via HTTPS,
  • should have an expiry date (e.g. 7 days).

Once the user logs in with the token, it is invalid and a new token should be created and given to the user. In the case of an expired token, the user must be made to log in again, using their real credentials.

A more definitive and lengthy description of these rules can be found in part 2 of The Definitive Guide To Forms based Website Authentication:

Persistent Login Cookies ("remember me" functionality) are a danger zone; on the one hand, they are entirely as safe as conventional logins when users understand how to handle them; and on the other hand, they are an enormous security risk in the hands of most users, who use them on public computers, forget to log out, don't know what cookies are or how to delete them, etc.

[...]

Follow Charles Miller's 'Best Practices' article. Do not get tempted to follow the 'Improved' Best Practices linked at the end of his article. Sadly, the 'improvements' to the scheme are easily thwarted (all an attacker has to do when stealing the 'improved' cookie is remember to delete the old one. This will require the legitimate user to re-login, creating a new series identifier and leaving the stolen one valid).

And DO NOT STORE THE PERSISTENT LOGIN COOKIE (TOKEN) IN YOUR DATABASE, ONLY A HASH OF IT! The login token is Password Equivalent, so if an attacker got his hands on your database, he could use the tokens to log in to any account, just as if they were cleartext login-password combinations. Therefore, use strong salted hashing (bcrypt / phpass) when storing persistent login tokens.


Update: Sorry, I misunderstood the question. The method you linked looks reasonable, but it won't protect you from replay attacks or man-in-the-middle. You should use SSL alongside it.

8
  • 1
    "cryptographic strength one-time random token" would you say the approach I linked to is secure enough for this? "Once the user logs in with the token, it is invalid and a new token should be created" Not quite sure if I understand how that would work. Are you saying tokens should be invalidated/re-issued on a per request basis?
    – James
    Sep 3, 2012 at 12:17
  • 1
    @James When the user comes to the site and does not have a session, the cookie token is sent to the server. The server validates it, creates a new session as the logged in user, and invalidates the token. It then gives the user a new token. The session identifies them whilst they're using the site, but when they close their browser (or the session expires) the user is no longer logged in. When they come back, they have no session, and the new token you gave them allows you to create a new session (go back to step 1)
    – Polynomial
    Sep 3, 2012 at 12:21
  • @Polynomail There is no notion of a cookie, session or browser in my case. This is a REST API which is accessed via a mobile app.
    – James
    Sep 3, 2012 at 12:23
  • @James Sorry, misunderstood the question. The mechanism you linked is fine for this kind of situation, but it will not protect you against replay attacks. You need to use something like SSL to prevent MitM / replay.
    – Polynomial
    Sep 3, 2012 at 12:29
  • The API is running over HTTPS so is it safe to assume I wouldn't be vurnerable to those sort of attacks? I guess I am probably being overly paranoid, however, when it comes to security on the web I think it's a good thing to be like that!
    – James
    Sep 3, 2012 at 12:31
4

A pure RESTful API web service should use the underlying protocol standard features:

  1. For HTTP, the RESTful API should embrace and comply with existing HTTP standard headers, status codes and methods. Adding a new HTTP header violates the REST principles.

  2. RESTful services MUST be STATELESS. Any tricks, such as token based authentication that attempts to remember the state of previous REST requests on the server violates the REST principles.

Bottom-line: For authentication / authorization purposes, you should use HTTP authorization header. And you should add the specific HTTP authorization scheme header in each subsequent request that needs to be authenticated.

I have developed a RESTful web service for the Cisco Prime Performance Manager application. Search Google for the Cisco Prime Performance Manager REST API document that I wrote for that application for more details about RESTFul API compliance - see below. For this application, we have chosen to use the HTTP "Basic" Authorization scheme to authenticate and authorize requests. And obviously, we are using HTTPs to encrypt all the data in transit from the client to the server when using HTTP Authorization.

http://www.cisco.com/c/en/us/support/cloud-systems-management/prime-performance-manager/products-programming-reference-guides-list.html

2
  • 2
    If token based approaches are not allowed, doesn't that mean the client must store and resend the user's name and password on every request and determine when to invalidate them?
    – Michael
    Nov 8, 2014 at 4:49
  • 1
    Couple of things - who said I wasn't utilising the authorization header? Token authentication is still stateless, the server remembers nothing beyond the current request - the token is simply used as a ticket to say "hey, I've been before, he's the proof, so you can skip the authentication step".
    – James
    Dec 16, 2014 at 15:35

You must log in to answer this question.

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