Wednesday, June 30, 2010

Restful Link Integrity

lockHow do you secure sensitive information within your URIs? Many of the RESTful examples I have seen expose sensitive information within their links. Often this sensitive data is the identifying key of the entity that is being managed. RESTful Web Services Cookbook briefly discussed two solutions for securing sensitive information within URI's (refer to chapter 12 for details). I will expand upon these two solutions by demonstrating how we can leverage the Jasypt encryption framework to preserve sensitive information.

Initially, we must validate our URI templates do not expose sensitive data. If they do not, there are no concerns. However, if your URI templates expose sensitive data we must preserve their integrity and confidentiality. An example of an insecure URI template may look like:

http://rest.com/account/{account_id}.

If this URI template exposes a clear text account ID we have a security gap. If a security gap exists, we must implement a solution to preserve the integrity and confidentiality of the insecure URIs. Three solutions exist to secure RESTful links:

Hashing

Hashing is an ideal solution if you need to expose data parameters in clear text and want to preserve data integrity. Integrity is the assertion that the data was not altered by the consumer or a man-in-the-middle. With a hash-based solution the RESTful link may look like:

http://rest.com/account?account_id=123456&digest=83r/grjAxjcqe5FE42xRgD6YF00q4DmsJALlfA==

This solution will preserve integrity but it does not provide confidentiality. If the consumer or malicious user alters the account ID a server-side integrity check against the hash algorithm will fail. The JUnit below demonstrates the creation of the digest (hash) and the assertion to validate the integrity of the clear text and digest have been preserved:

@Test
public void testJasyptsHashAlgorithm() {
/*
* By default the standard digester uses the RandomSaltGenerator and runs the hash
* algorithm 1000 times. These are configurable for greater security.
*/

StandardStringDigester digester = new StandardStringDigester();
digester.setAlgorithm("SHA-1");

final String clearText = "123456";
final String digest = digester.digest(clearText);
Assert.assertTrue("Integrity has been violated!", digester.matches(clearText, digest));
}

Encryption

Encryption is an ideal solution if you want to preserve integrity and confidentiality. For example, an encryption-based RESTful link may look like:

http://rest.com/account/kNddGYRn3KAWK5nYJ/5jrA==

The JUnit below demonstrates the creation of the encrypted text and the assertion to validate the integrity of the encrypted text has been preserved:

@Test
public void testJasyptsEncryptionAlgorithm() {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("password");
encryptor.setAlgorithm("PBEWithMD5AndTripleDES");

final String clearText = "123456";
String encryptedText = encryptor.encrypt(clearText);

String decryptedText = null;
try {
decryptedText = encryptor.decrypt(encryptedText);
} catch (EncryptionOperationNotPossibleException e) {
Assert.fail("Integrity has been violated!");
}
Assert.assertEquals(clearText, decryptedText);
}

Do not expose sensitive data

The ideal solution is to not expose any sensitive information. Alternatively, instead of exposing a sensitive primary key expose an associative key or index that has no identifying relationship to the entity. A common scenario occurs when consumers need to search and maintain records. Consider the following use case:
  1. User performs a search
  2. The server-side executes the search and stores the list of authorized search results within session
  3. The server only exposes the indexes of the entities the consumer is allowed to maintain: http://rest.com/account/{index_id}
This solution preserves integrity by restricting the user to only maintain the records they are authorized to manage and we do not expose a confidential primary key.

No comments :

Post a Comment