17.3. Host-Proof HostingASP, DataCloud, Key, Secure, Untrusted Figure 17-9. Host-Proof Hosting17.3.1. Goal StoryReta is dismayed to learn that a malicious hacker managed to download a chunk of the company's database containing personal details about all the customers in her store. Fortunately, she also learns that the pass-phrase she always entered was actually used to encrypt all that data, so the hacker won't be able to make sense of any of the contents. 17.3.2. ProblemHow can you mitigate the effects of unauthorized access to your application data? 17.3.3. Forces
17.3.4. SolutionHost sensitive data in encrypted form so that clients can only access and manipulate it by providing a pass-phrase that is never transmitted to the server. The server is limited to persisting and retrieving whatever encrypted data the browser sends it and never actually sees the sensitive data in its plain form. All encryption and decryption takes place inside the browser itself. Just what does secure hosting have do with Ajax? The Ajaxian twist comes in the maintenance of the pass-phrase. You could use the browser-side encryption with a conventional application, but the pass-phrase would have to be entered upon each page refresh, since no JavaScript state survives a reload. With page refreshes occurring every few seconds, the pass-phrase is completely unusable. However, using Ajax to avoid page refresh means you can retain all session state in the browser, so the pass-phrase only needs to be entered at the start. After being entered, it can be retained as a standard JavaScript string and will disappear from the browser when the user quits the browser or visits another site. Suddenly, Host-Proof Hosting becomes usable. Incidentally, don't take this pattern to be a new "Ajax-HTTPS" protocol. The issue here is how the data is actually stored, not how it's transmitted. In theory, the data itself need not travel over a secure connection because it's already encrypted. In practice, a secure connection might be worthwhile in order to reduce some of the vulnerabilities described later in this section. Before you rush off to upload all your trade secrets to Shonky Hosting Inc., you should be aware that this idea isn't foolproof. On the one hand, the host is assumed to be inherently untrustworthy. But on the other hand, the script for the browser application is held right there on the server, and the browser runs whatever scripts come down from that URL. This leaves open the possibility that the host will tamperto evil endswith either the code itself or the outgoing HTML and JavaScript. What if a rogue administrator from the hosting company decided to quietly add a small 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, serialize the entire DOM and upload a summary back to the server with Web Remoting (Chapter 6), where more malicious code would log it somewhere convenient. A third-party hacker sitting between the browser and the server could also inject a script and could upload data to a remote site with one of several established techniquesfor instance, by exporting browser data as CGI variables on the source URL of an external image under the hacker's control. In both scenarios, the application can continue as normal, and the poor user is none the wiser. The threat of script injection certainly weakens the claim for this pattern, but it doesn't invalidate it 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 that your application is uploading DOM details every sixty seconds (using a tool similar to those described in Traffic Sniffing [Chapter 18]), there's a good chance that something's blatantly wrong. For practical purposes, also consider what happens if a hacker gains unauthorized access for a short time. She might well grab as much data as possible, but the data will be safely encrypted. In the unlikely event such a hacker was sophisticated enough to use script injection, she would only be able to gain pass-phrases of users who happen to be logged in during the time the server is under her control. So pragmatic considerations suggest that the technique is safer than hosting the data in plain form, though it's by no means perfect. But is it so much safer as to warrant the extra performance overhead and coding effort and the constraint of zero page refreshes? That's a decision you'll need to make on a case-by-case basis, bearing in mind the critical nature of the datathe likelihood of the various types of attack. In theory, there's an even stronger claim in favor of this approach. It might be possible to develop a general-purpose plugin to detect 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 you 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. 17.3.5. Decisions17.3.5.1. What encryption algorithm and framework will be used?You'll need an algorithm that's available in JavaScript as well as in your server-side environment. If the data is accessed by other clients, they obviously must have access to the algorithm too. A search reveals that several algorithm implementations are available, each with its own strengths and weaknesses. All of the following are open source.
17.3.5.2. 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. 17.3.6. Real-World ExamplesThere are no public real-world examples to my knowledge. One precedent is Hushmail (http://hushmail.com), which uses a Java applet to allow access to email encrypted on the server. 17.3.7. Code Example: Host-Proof-Hosting Proof-Of-ConceptRichard Schwartz provides a proof-of-concept demo (http://smokey.rhs.com/web/test/AjaxCryptoConceptProof.nsf/blowfish?OpenPage)(Figure 17-10). For encryption, it delegates to a JavaScript Blowfish library. 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 to check that the user has the correct pass-phrase. The application then shows that 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. Figure 17-10. Host-Proof HostingThe application itself is quite simple: it manipulates the "display" style settings of a series of forms in order to show or 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 needs to be entered only once. When the application is ready to upload the encrypted data, it sets up the global variables required by the Blowfish library (ideally, the library 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 to the server:[*]
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 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); 17.3.8. Alternatives17.3.8.1. Richer PluginYou might consider exploiting the increased permissions of a Richer Plugin (Chapter 8) to access a local data store. However, with this there is still a risk of malicious script injection from the server. Furthermore, you'll lose several key benefits of holding the data server side:
Another application of Richer Plugin would be to hold the data server side but use the Richer Plugin in place of the JavaScript code to manage the local encryption and decryption. A plugin like this could also retain the pass-phrase. 17.3.9. Related Patterns17.3.9.1. Direct LoginDirect Login, like Host-Proof Hosting, also involves using JavaScript for encryption-related activity. 17.3.9.2. TimeoutApply a Timeout to clear the key from browser state after an idle period. This will help you prevent unauthorized users from accessing the encrypted data. 17.3.10. MetaphorCaesar wonders whether he can entrust his aide with the top-secret recipe for victory wine. Fortunately, he's a pioneer of cryptography, so he just hands over the recipe in encrypted form. 17.3.11. Want to Know More?Check out Richard Schwartz's blog entries:
17.3.12. AcknowledgmentsRichard Schwartz's blog entries provided the idea for this pattern, and its name is attributed to Richard Schwartz, Michael Griffes, and their colleagues at eVelocity. I am also grateful to others who have commented on the approach, notably Alex Russell, who has cautioned on the vulnerabilities of this approach, such as script injection. |