Update 8/5: Mario Heiderich and koto on GitHub point out that this method is completely unworkable on Firefox due to this Firefox bug which means that the same-origin context for data: URIs is inherited from the parent or opener.

Demo of protecting crypto keys from XSS attacks by storing them in an iframe. Keys are stored inside an iframe with a data: URI, along with the crypto methods that use them. The parent document cannot access the keys due to the same-origin policy. In this demo, keys are generated inside the crypto frame, but in deployment the keys would be injected into the crypto frame from some long term storage, since it's not worthwhile trying to protect keys that are generated on the fly.

This technique is useful because an XSS in your main application doesn't leak your private keys. It's important to note that an XSS will still ruin the *current* session, making it possible to generate messages signed as you and decrypt messages intended for you. It's also worth noting that there's still potential for an XSS inside the crypto frame to leak your keys. This is especially dangerous because it's impossible to apply a Content-Security-Policy to a data: URI in order to obstruct exfiltration. However, since the crypto frame is invisible (no mouseover or click events) and its code has no need to modify document state, the surface of attack is much smaller than the rest of your application.

This demo is in response to this Cryptocat issue. Feedback welcome: @j4cob on Twitter.

Public key is: (..generating..)
Text to sign (with private key):
JS to eval: