Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating cryptographically secure authentication tokens

Background:

This is really a general best-practices question, but some background about the specific situation might be helpful:

We are developing a "connected" application for the iPhone. It will communicate with the backend application via REST services. In order to not have to prompt the user for a username and password every time they launch the application, we will expose a "Login" service that validates their username and password on initial launch and returns an authentication token that can be used for future web service requests for real data. The token may have an expiration time after which we'll ask them to re-authenticate with their username/password.

The Question:

What are the best practices for generating this sort of token to be used for authentication?

For example, we could...

  • Hash (SHA-256, etc) a random string and store it in the database for the given user along with an expiration date. Do a simple lookup of the token on subsequent requests to make sure it matches.
  • Encrypte the user id and some additional information (timestamp, etc) with a secret key. Decrypt the token on subsequent requests to make sure it was issued by us.

This feels like it must be a solved problem.

like image 599
Erv Walter Avatar asked May 08 '09 15:05

Erv Walter


People also ask

What is a cryptographically secure token?

A token where the secret is a cryptographic key. Source(s): 1. A portable, user-controlled, physical device (e.g., smart card or PC card) used to store cryptographic information and possibly also perform cryptographic functions.

How the tokens are generated?

In many cases, tokens are created via dongles or key fobs that generate a new authentication token every 60 seconds in accordance with a known algorithm. Due to the power these hardware devices hold, users are required to keep them safe at all times to ensure they don't fall into the wrong hands.

How do you generate a token in Python?

In order to authenticate a user connecting to an OpenTok session, a client must connect using a token (see this overview). Calling the generate_token() method returns a string. This string is the token.


2 Answers

Based on the feedback from the other answers to this question, additional research, and offline discussions, here is what we ended up doing...

It was pointed out pretty quickly that the interaction model here is essentially exactly the same as the model used by Forms Authentication in ASP.NET when a "remember me" checkbox is checked. It's just not a web browser making the HTTP requests. Our "ticket" is equivilant to the cookie that Forms Authentication sets. Forms Authentication uses essentially an "encrypt some data with a secret key" approach by default.

In our login web service, we use this code to create a ticket:

string[] userData = new string[4];  // fill the userData array with the information we need for subsequent requests userData[0] = ...; // data we need userData[1] = ...; // other data, etc  // create a Forms Auth ticket with the username and the user data.  FormsAuthenticationTicket formsTicket = new FormsAuthenticationTicket(     1,     username,     DateTime.Now,     DateTime.Now.AddMinutes(DefaultTimeout),     true,     string.Join(UserDataDelimiter, userData)     );  // encrypt the ticket string encryptedTicket = FormsAuthentication.Encrypt(formsTicket); 

Then we have an operation behavior attribute for the WCF services that adds an IParameterInspector that checks for a valid ticket in the HTTP headers for the request. Developers put this operation behavior attribute on operations that require authentication. Here is how that code parses the ticket:

// get the Forms Auth ticket object back from the encrypted Ticket FormsAuthenticationTicket formsTicket = FormsAuthentication.Decrypt(encryptedTicket);  // split the user data back apart string[] userData = formsTicket.UserData.Split(new string[] { UserDataDelimiter }, StringSplitOptions.None);  // verify that the username in the ticket matches the username that was sent with the request if (formsTicket.Name == expectedUsername) {     // ticket is valid     ... } 
like image 110
Erv Walter Avatar answered Oct 30 '22 02:10

Erv Walter


Building your own authentication system is always a "worst practice". That's the kind of thing best left to professionals who specialize in authentication systems.

If you're bent on building your own "expiring ticket from a login service" architecture rather than re-using an existing one, it's probably a good idea to at least familiarize yourself with the issues that drove the design of similar systems, like Kerberos. A gentle introduction is here:

http://web.mit.edu/kerberos/dialogue.html

It would also be a good idea to take a look at what security holes have been found in Kerberos (and similar systems) over the last 20 years and make sure you don't replicate them. Kerberos was built by security experts and carefully reviewed for decades, and still serious algorithmic flaws are being found in it, like this one:

http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt

It's a lot better to learn from their mistakes than your own.

like image 42
Eric Lippert Avatar answered Oct 30 '22 02:10

Eric Lippert