Host-Proof Hosting - Ajax Patterns

Host-Proof Hosting

From Ajax Patterns

Revision as of 14:11, 2 January 2007; view current revision
←Older revision | Newer revision→

Evidence: 0/3

Tags: ASP DataCloud Key Secure Untrusted


Contents

In A Blink

Sketch: Locked inside data cloud, key at browser.


Goal Story

Reta is dismayed to learn the head office's a malicious hacker managed to download a chunk of the company's database, containing personal details of all the customers in her store. Fortunately, she also learns that the pass-phrase she always entered was actually used to encrypt the all that data, so the hacker won't be able to make sense of any of the contents.


Problem

How can you mitigate the effects of unauthorised access to your application data?


Forces

  • Web applications require some form of persistent data, to hold information about users, business state, past events, and so on.
  • Security restrictions prohibit storage on user's own hard drives. Even if that was possible, it would largely defeat the purpose of using a web application in the first place.
  • Server-side storage suffers is open to abuse: the administrators, along with anyone who is able to gain access to it, are able to extract sensitive information by reading the data, as well as effect malicious changes by tampering with it. The abuse can occur within an organisation's own IT department or a third-party hosting company entrusted with the data.
  • Cookies can support data storage within the browser, but cookie data is also transmitted to the server, where it may be vulnerable.


Solution

Host sensitive data in encrypted form, so that clients can only access and manipulate it by providing a pass-phrase which is never transmitted to the server. The server is limited to persisting and retrieving whatever encrypted data the browser sends it, and never actually accesses the sensitive data in its plain form. It. All encryption and decryption takes place inside the browser itself.

To clarify all this, here's a likely flow of events:

  • User enters pass-phrase to begin using the system. Browser retains the pass-phrase as a global variable.
  • User requests a list of all data belonging to him.
  • For each record, the system stores the associated user ID in plain-text, the record ID in plain form, and the record content only in encrypted form. (The message content is one or more database columns, each encrypted.) Thus, system is able to return a list of record IDs for this user.
  • User selects one of the record IDs.
  • System checks that this user ID is associated with the record ID, and returns the corresponding message content.
  • Browser uses stored pass-phrase to decrypt the contents.

One thing to note here is that we haven't discussed transport. Needless to say, transport must be secure, as there is no point being worried about your chosen data host, but then leaving data on the public internet, where it's easy for someone to access all of it. Incidentally, don't take this pattern to be a new "AJAX-HTTPS" protocol - the idea here is about how the data's actually stored. Clearly, the transport mechanism must be secure, so standard HTTPS should fit the bil for most Host-Proof Hosting implementations.

What's a pattern about secruity of hosting doing in a collection of patterns about Ajax web design? The Ajaxian twist here comes in the maintenance of the pass-phrase. You could use the encryption-decryption approach with a conventional application, but the pass-phrase would have to be entered upon each page reload, since no Javascript state survives a reload. With all server interaction handled by Web Remoting, the pass-phrase need only be entered once per session.

Before you rush off to upload all your trade secrets to Shonky Hosting Partners, you should be aware that this solution is by no means fool-proof. On the one hand, the host is assumed to be inherently untrustworthy. But on the other hand, the scripting for the browser application is held right there on the server, and the browser is told to run whatever scripts come down from that URL. This leaves open the possibility of the host tampering with either the code itself, or the outgoing HTML and Javascript, to evil ends.

What if the host decided to quietly add a little monitoring function to a Javascript file, and append its execution to a window.onload function. Then, the evil monitoring function could be made to run once a minute within the browser. It might for instance, traverse the entire DOM, and upload a summary back to the server with Web Remoting, where more malicious code will capture the DOM data and log it somewhere convenient. The poor user would be none the wiser.

The threat of script injection certainly weakens the claim for this pattern, but doesn't invalidate the pattern altogether. While script injection is theoretically possible, it does require some skill on the host's part and is also detectable if you know what the code should and should not be doing. If you happened to discover your application uploading its DOM model every sixty seconds, there's a good chance that something's gone blatantly wrong. Injection is a form of abuse

As another practical consideration, consider what happens if a hacker gains unauthorised access for a short time. They might well grab as much data as possible, but script injection, though possible, is a much less likely event. Even if it occurs, the hacker will only be able to gain as much information as can be extracted from the users who run the application in the time before the violation is detected. Downloading the entire data store would, in contrast, provide unbridled access to all the data.

So, pragmatic considerations suggest that the technique is safer than hosting the data in plain form, while by no means perfect. Is it so much safer to warrant the extra performance overhead and coding effort? That's a decision you'll need to make on a case-by-case basis, bearing in mind the criticality of the data and the likelihood of the various types of attack.

In theory, there is an even stronger claim in favour of this approach. It might be possible to develop a general-purpose plugin precisely for detection of script injection. For a given application, such a plugin would have access to a certified copy of the source code. Then, it could monitor traffic and caution about any unexpected activity. If such a plugin could be developed, the only way for script injection to succeed would be a conspiracy between the host, the code certifier, and the plugin manufacturer.


Decisions

What encryption algorithm and framework will be used?

You'll need an algorithm that's available in Javascript as well as your server-side environment. If the data is accessed by other clients, they obviously must have access to the algorithm too. A search reveals several algorithm implementations are available, all of the following being open-source:

Comparing encryption algorithms is well beyond the scope of this pattern, but it's worth noting here that they each algorithm has its own benefits and weaknesses, so the algorithm shouldn't be chosen arbitrarily.

Also important is the particular implementation, as you need to be confident its a faithful implementation of the algorithm you're after. In addition, there are standard considerations such as performance and licensing issues. In practice, the algorithm you ultimately choose will often be influenced by the quality of available implementations.


When will the pass-phrase be requested?

The browser will need to query for the pass-phrase as soon as encrypted data must be rendered. However, that might not be immediately. To make the encryption less intrusive, you might consider using something like the Lazy Registration pattern, where regular data is shown as soon as the user accesses the application, with encrypted data only accessible after the pass-phrase has been entered.


Real-World Examples

Online Password Managers

In 2006 a number of online password managers based on this pattern have emerged. Those currently in at least Beta Release are:

- Parvez Anandam's [1] Passlet was one of the first implementations of Host-Proof Hosting. The service is free and in Beta release.

- PassPack, written by Francesco Sullo [2], was released contemporarily. The service is free and in Beta release.

Many other applications are in development or 'demo' version.

Other types of applications

There are no known other applications at this time.



Code Examples

Ajax Crypto Proof-Of-Concept

Richard Schwartz provides a proof-of-concept application. For encryption, it delegates to a blowfish Javascript implementation by Andre Mueller and Rainer Wollmann. The application accepts a pass-phrase, a message key, and some message content. It then encrypts the message and uploads it. It also uploads the key along with an encrypted version of the key, which can be used later on to check that the user has the correct pass-phrase. The application then shows how the server is holding only the encrypted content and the key. You can then pull the encrypted content back down and decrypt it with the original pass-phrase.

The application itself is quite simple: it presents a series of forms by manipulating their "display" style settings, to show and hide them. Thus, the user's pass-phrase remains in the pass-phrase input field at all times. This is the important thing about the demo: there's no form submission, so the pass-phrase only needs to be entered once.

When the application's ready to upload the encrypted data, it sets up the global variables required by the blowfish implementation (ideally, the implementation would accept these as parameters). encodetext is called (with "2" to specify the blowfish algorithm) and it outputs the encrypted version in the form of a global variable:

 saveCryptoText() {
   ...
   inpdata=window.document.inputForm.plaintextInput.value;
   passwd=window.document.inputForm.password.value;
   // invoke blowfish
   encodetext(2);
   data = data + "&check=" + outdata ;
   ...
 }

The encrypted key is also attached:

 inpdata=window.document.inputForm.check.value;
 encodetext(2);
 data = data + "&check=" + outdata ;

The data can now be sent over to the server. RESTful principles suggest the data would be uploaded with a POST in practice, because it will affect the server state. Another reason to use POST is that it's not practical to encode an entire message in the URL. However, this application is a proof-of-concept, and GET is sufficient for that purpose, so a GET query is used here.

 url = "http://smokey.rhs.com/web/test/AjaxCryptoConceptProof.nsf/SaveBlowfishDoc?OpenAgent" + data
 httpPost(url)	

Later on, the application provides a list of message keys that have been sent to the server. When the user chooses one, the application requests an XML document from the server, containing the message and key details (in practice, the message key could be verified first, before the body is downloaded). It first performs a check that the key is valid for this pass-phrase, then decrypts the message itself. Finally, a DOM object is morphed to display the decrypted text:

 inpdata = "";
 inpdata = getElementText(valuenode);
 outdata = ""
 decodetext(2);
 ...
 window.document.all.decryptedText.innerHTML = stripNulls(outdata);	


Alternatives

Richer Plugin

You might consider exploiting the increased permissions of a Richer Plugin to access a local data store. However, there is still a risk of malicious script injection from the server. Furthermore, you lose several key benefits of holding the data server-side:

  • Users will not be able to access the data from remote locations.
  • Each local data store will need its own backup process. Uploading to a backup server will defeat the purpose of the local store.
  • Each local data store must be protected against unauthorised access.
  • The data stores will sometimes need to be migrated as the system changes.

Another application of Richer Plugin would be to hold the data server-side, but use the Richer Plugin to manage the local encryption and decryption, in place of the Javascript code.


Related Patterns

Direct Login

Direct Login also involves using Javascript for encryption-related activity.

Timeout

Apply a Timeout to clear the key from browser state after an idle period. This will help prevent unauthorised users from accessing the encrypted data.

Visual Metaphor

This pattern is about viewing the keeper of information with suspicion. Ceasar wonders whether he can entrust his aide to retain the top-secret recipe for victory wine. Fortunately, Caesar's a pioneer of cryptography, so he has a safer option: hand over the recipe in encrypted form.

Want to Know More?

Acknowledgements

Richard Schwartz's blog entries provided the idea for this pattern and the name is attributed to Richard, Michael Griffes, and their colleagues at eVelocity. I am also grateful to others who have commented on the approach, notably Alex Russell who pointed out some of the vulnerabilities of this approach, such as script injection.