InnovationM Secure Webservice Integration Mobile Apps

Secure Web Service integration in Mobile Apps

Web services have gained lot of importance lately. From mobile apps perspective, native apps (Andorid, iOS, Windows Phone, etc.) or HTML5/JS Frameworks like Sencha Touch need to talk to the web services to get the data and push the data. How do we ensure that request sent to web services is from authenticated client?

For our discussion, I will be talking about Mobile applications integrating with web services.

Concept of Signature and Signed Request

Let us first understand the basic concept of Signature and Signed Request. Application sending HTTP request to web services need to be secured in the sense that only requests from authenticated clients are allowed.

Mobile app sends HTTP request to web service (REST API). We need to piggy back on HTTP Request to make an authenticated request. To prepare an authenticated request, it requires three steps:

(i) Prepare a String
(ii) Encrypt the String (Called as Signature)
(iii) Place the Signature in the request sent to the server (Referred as Signed Request)

Authentication and User Authorization

There will be two level of Security while integrating with web services:

1. Authentication of request
2. Authentication of request along with user authorization

1. Authentication of a Request

When request is received by the web service then it should be generated from an authenticated client. Here the authenticated client is Mobile Application. Let us see how we can secure the request. Here are the steps:

1.1 Generation of Signature – Both  client (mobile application) and server will generate signature in similar way by using hashing algorithm (Hmac-sha1) and Base64 encoding. Follow the steps to generate signature:

(i) Prepare a string (Text). This string will be a combination of following elements in pre-determined order.

  1. Client Unique Id – Unique Id of application generated by app developer
  2. Http-Verb  – Every HTTP request carries this method. Ex – GET, POST, PUT, DELETE, etc.
  3. Content-Type – Type of content in the HTTP Request body.
  4. Date (Time Stamp)
  5. Canonical Resource (URL) – Part of URL without the server name and port.

Let us take some sample data:

  1. Client Unique Id – Generate a UUID
  2. Http-Verb – POST
  3. Content-type –  application/x-www-form-urlencoded
  4. Date (Time stamp) – 09/26/2013 15:55:40
  5. Canonical Resource (URL) – /SecurityTest/framework/login

Concatenated String – UUID + POST + application/x-www-form-urlencode + 09/26/2013 15:55:40 + /SecurityTest/framework/login

Concatenated String is ready  – UUIDPOSTapplication/x-www-form-urlencode09/26/2013 15:55:40/SecurityTest/framework/login

(ii) After preparing the string, you can then use your “SECRET  KEY” to convert the above string into encrypted string by doing a one way hash of the string.  This is also referred as keyed-HMAC (Hash Message Authentication Code) and the encrypted string is the output of the HMAC. Informally, we call this process “Signing The Request,” and we call the output of the HMAC algorithm the “Signature”. This Secret key is known to app developer and server.

HMAC (Encrypted String) –  Èlš#׬uÙ¸-Â?FUõÖ

(iii) When the data has to be sent on a network in HTTP Request then it has to be encoded using Base64 encoding. Convert it in Base64 encoded string and this is the signature.

Signature after Base64 Encoding – <BmOnrZIU7htDqIFHliXiNID75pE=>

Sample Code for generating signature in Java (Android):

/* Here we can choose the algorithm*/
SecretKeySpec signingKey = new SecretKeySpec(SEKRET_KEY.getBytes("UTF-8"), HMAC_SHA1_ALGORITHM);

Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);

byte[] rawHmac = mac.doFinal(stringToSign.getBytes("UTF-8"));

/* Here applying the Base64 encoding */
byte[] encoded = Base64.encodeBase64(rawHmac);

/* resultString is Base64 encoded HMAC */
resultString =new String(encoded,"UTF-8");

Sample Code for generating signature in Objective C using Category on  NSData for Base64 encoding:

/* Here we can choose the algorithm */
NSData *keyData = [@"SECRET_KEY" dataUsingEncoding:NSUTF8StringEncoding];

NSData *textData = [stringToSign dataUsingEncoding:NSUTF8StringEncoding];

uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};

CCHmacContext hmacContext;

CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length);

CCHmacUpdate(&hmacContext, textData.bytes, textData.length);

CCHmacFinal(&hmacContext, digest);

/* out is HMAC */
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];

/* resultString is Base64 encoded HMAC */
NSString *resultString = [out base64EncodedString];

1.2 Preparing request 

After preparing signature, you will have to prepare request at client (Mobile Application) end. HTTP Authorization header of HTTP Request is used to carry the signature. Authorization header looks like the following:

Authorization: IMWS CLIENT_UNIQUE_ID:Signature

IMWS - It is just a text that identifies that this is our signature
Signature - Base64 encoded string

1.3 Web services authenticating the request

At server side, web service receives  the request. It extracts the signature prepared by client (Mobile Application) that is part of Authorization header in request. Server prepares the same Signature as prepared by Mobile app by extracting information from HTTP Request headers. Server and client (Mobile Application) share the same Secret Key. After generating signature, server compares both signature from client (Mobile Application) and itself and authenticates successfully if they match.

Now request is validated as coming from authentic client.

Other Security considerations:

  • The client (Mobile Application) time stamp included with an authenticated request must be within 10-15 minutes of the Server time when the request is received.  If not, the request will fail. The intention of these restrictions is to limit the possibility that intercepted requests could be replayed by an adversary.
  • For stronger protection against eavesdropping, use the HTTPS transport for authenticated requests.

2. Authentication of request along with user authorization

Here user has logged into the app and we need to place a mechanism wherein all the subsequent requests from the app will be authorized by the server. We cannot pass login credentials in every subsequent requests.

There is a concept of Access Token. When user logs in then Access Token is generated by the server for authorized user. Let us see how Authenticated Requests and User Authorization works together:

2.1 Generation of Signature 

Signature generation is similar as described above for authenticated client.

2.2 Preparing request 

User logs in and server generates Access Token returning that to client. This access token will be sent for all subsequent requests in Authorization header.

Authorization header for Authenticated client and Authorized user looks like this:

Authorization:IMWS CLIENT_UNIQUE_ID:ACCESS_TOKEN:Signature
ACCESS_TOKEN - Sent by server

2.3 Authenticating the request and user 

So basically, two things will happen now:

(i) Check whether the request is coming from authenticated client and
(ii) Authorized user is sending the request.

At server side, when web service receives  the request, It will extract the signature and authenticates the client (Same way as described earlier). Also, it extracts the ACCESS_TOKEN that is part of Authorization header. It validates the ACCESS_TOKEN against expiration and modification of token.

Generation of Access Token for authorized user at the server 

Access Token is generated  using Hmac-sha1 algorithm and Base64  encoding and AES encryption. Here are the steps:

(i) You will have to prepare string. String will be combination of following elements in predetermined order with “+” as delimiter.

  1. User Id – id of user that identifies the user in the database.
  2. Current date and time in milliseconds
  3. Expiration time – Current date and time + Expiration period (60 days or whatever you want in milliseconds)
  4. Role of the user (if you want to set some permissions for server to use)

Output – Concatenated Sting (Let us call this as S1)

(ii) After preparing the string, calculate HMAC (One way hash) of string  by using SECRET KEY, then convert it in  string with UTF-8 format. Result String will be the signature for ACCESS_TOKEN.

Output – Signature / Encrypted String (Let us call this as S2)

(iii) We now need to concatenate the Signature (S2) and Concatenated String (S1). Then the concatenated string will be encrypted by AES encryption algorithm using your KEY, then convert it in Base64 encode string.

Output – Encrypted S1 + S2 (Let us call this as S3)

/* Encrypting the string */

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(KEY.getBytes("UTF-8"),"AES");
cipher.init(Cipher.ENCRYPT_MODE,key,new IvParameterSpec(IV.getBytes("UTF-8")));
byte[] rawEnc = cipher.doFinal(stringToEncrpt.getBytes("UTF-8"));
byte[] encoded = Base64.encodeBase64(rawEnc);

/* resultString is Encrypted string*/
resultString =new String(encoded,"UTF-8");

(iv) To add more security, S3 is now pre-fixed with 4 character variable string generated from a random number, then resulted string will be the ACCESS TOKEN.

token = UUID.randomUUID().toString().substring(0,4) + new String(encryptedString,"UTF-8");

We can validate the ACCESS TOKEN against the expiration and modification by Decrypting using AES algorithm using same key used for encryption. We can check expiration time for expiration validation and signature for ACCESS_TOKEN validation.

Have fun!!!!

Leave a Reply