The Goal

We want more offline web applications. A ToDo app, a Bitcoin wallet, a password manager - Javascript can easily handle these tasks. For starters, this is why I hate desktop applications:

  1. I have no idea what those shady binaries are going to do with my computer. In other words I don’t want to install anything on my computer.

  2. Those apps are large (e.g. Multibit wallet is 34 MB), require manual download, manual installation, manual removal of app.exe/app.dmg file and manual uninstallation.

Speaking of usability, it’s obvious web apps are superior to desktop apps : you type wallet.com and it just works.

Speaking of security, web apps are way more superior: it runs in a sandbox, explicitly asks for access to your web cam/location/local files, and uses a scripting language that almost any programmer can read and audit.

Speaking of performance and heavy video games, yes, WebAssembly isn’t there yet. But let’s focus on simple apps like bitcoin wallet.

Appcache is an HTML5 technique to make applications work offline, without any requests to the server.

Here is Proof of concept - after first encounter with the app it sits in your browser, permanently cached. You can embed public keys of the developers to allow manual updates and require signatures for every update (code sign) like @substack’s Hyperboot offers.

But there’s one thing why I will never use existing web apps for critical tasks. Because web apps are “backdoored” out-of-box by the maintainer.

The Problem

If the app is hacked/the maintainer is forced by government to steal your secrets (namely content of localStorage) they can trivially make victim’s user-agent visit uncached and therefore loaded from the server https://wallet.com/hacked_page with JS code stealing sensitive localStorage.

By the way all existing “we keep private key in your browser blah-blah” Bitcoin wallets are vulnerable to this. As long as you don’t download the wallet and run it under file:/// protocol (not a “web” wallet anymore, huh?), they can easily steal your Bitcoins with simple Javascript code served from same origin.

Here is the result of my brainstorm trying to solve this.

1) Always require passphrase to decrypt localStorage?

This will require malicious page to create a link with the app via x=window.open('/');waitForPassphrase();alert(x.passphrase); (which can be detected) or via more sophisticated link x=window.open('/hacked_page_spying_on_opener');location='/' which cannot be detected (a window doesn’t know if it opened other windows and therefore can be accessed from them).

Same origin policy is our ubiquitous enemy. On top of that typing complex passphrase every time is inconvenient.

2) Content-Security-Policy: sandbox to prevent cross-page access?

Would be cool, it’s the feature I used in Pagebox. Unfortunatelly localStorage isn’t going to work: Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag.

3) Ask users to add 127.0.0.1 wallet.com to /etc/hosts after first load

Don’t be so sceptical, it’s not that hard.

4) Use path-specific cookie for storing passphrase

Take a deep breath: ugly design of cookies is finally useful! We can ask the user to use wallet.com/s3cr3tpage which stores encryption_key for localStorage in a path specific cookie: document.cookie='key=secret;path=/s3cr3tpage;'; The only way to access decrypted content of localStorage is to know the /s3cr3tpage part storing the encryption key.

Weird trick, but seems to be working.

5) Like previous one but more reliable

Wildcard subdomains. Secrets of an app served from s3cr3tsub.wallet.com can never be hijacked with same origin attacks as long as the attackers don’t know what s3cr3tsub you’re using. Demo coming soon.

The Solution

As far as I know there’s no way to develop a Secure Offline Web Application without path-based cookies (4) or random subdomains (5) which are super ugly.

Therefore we need Appcache to have one simple option: “never load any URL from the server like we’re forever offline”. This will cut off all possible vectors and malicious maintainer will not be able to abuse same origin policy to access our secrets. I believe this feature can revolutionize the world of web applications.

Jul 28, 2015 • Egor Homakov (@homakov)