Airborn Blog

Transparent Web Apps using Service Workers

TLDR: As has been written before, writing web applications that don't trust the server (e.g. by adding client-side encryption, or storing all data in local storage and never sending it to the server) wasn't possible before, because the browser requests the code of the web application from the server every time you open it and executes it trustingly. We propose a solution, analogous to Binary Transparency on the desktop, using Service Workers, and have implemented it for Airborn OS.

Introduction

Web applications, unlike desktop and mobile applications, aren't normally installed: the browser downloads the application from the server every time you open it. As well as advantages, this has some disadvantages: for example, they don't normally work offline. I say "normally" because in modern browsers, web applications can partially "install" themselves with Service Workers. Service Workers sit between the web application and the server and cache responses so that the app keeps working offline, among other things.

There's also a security disadvantage to downloading the web app every time, if you want to verify whether you trust its source code: even if you read all the source code on GitHub, the server could send you a new version tomorrow with no easy way to notice.

Furthermore, the server could send just you a different version of the web application tomorrow. There's no way to check that you're getting the same version as everyone else. This also applies to desktop applications, and the solution is Binary Transparency, such as Firefox is planning to implement. Basically, every release will be put in a public log, and the Firefox Updater will check that the new version matches the version in the log.

Now that we know all the pieces of the puzzle, the question arises: can we use Service Workers to achieve Binary Transparency? It turns out we can, with some limitations.

Implementation

When the browser requests a file (/ or /main.js, say) the request goes to the Service Worker. If the SW has a response in cache, it responds with that immediately. It also requests an up-to-date version from the server. If it differs from the version in cache (i.e. the web app has been updated), it sends a request to the GitHub API for a list of files with sizes and hashes on GitHub. If the response matches, the cached version is updated and the user is shown this message:

response_matches.png

That link to GitHub is not just a generic link to the repository: it's a link to the specific commit with the same code that we received from the server (the Service Worker verified that). This makes it easy to check whether you trust the code of the web application.

If the response doesn't match, the user is shown this message:

response_does_not_match.png

Note that it's not a warning because the user isn't really at risk, because we still have the old version in cache. If that's not the case (this is the first time the user opens the web app) this error is shown instead:

new_response_does_not_match.png

Note that while we chose GitHub as a public log, this is not a requirement. You could check the files against another (possibly cryptographic) log, or check that they are signed with a given public key, etc.

What does this guarantee?

If you trust or verify the Service Worker the first time you get it from the server, this guarantees that:

  • Unless you've gotten a message saying Airborn OS has been updated*, you're still running the same code as when you first opened Airborn OS
  • Unless you've gotten a message saying you should check your trust in Airborn OS*, you're running the code on GitHub, and therefore the same code everyone else is running

This makes it possible for a security researcher to read the code on GitHub, publish their results (with inspected GitHub commit) and for everyone to verify that they're running that same code.

(*) Or a warning, error, or your computer has been hacked, or (for the second guarantee) if both the server and GitHub have been hacked. However, notably, the guarantees hold true if the server has been hacked or gone rogue. If the server has been hacked, the hacker also needs access to GitHub to update the code for existing users. And if the developer has gone rogue and pushes malicious code to the server, he also has to push that same code to GitHub, which makes it possible for observers to detect his rogueness.

Furthermore, we would like to guarantee that a security researcher can independently verify that all users are running the same code, as long as the server was not malicious when the users first opened the web app.

However, currently, the server tells the Service Worker which commit on GitHub each file is coming from. This is necessary, because it's hard to guarantee that the browser always gets the latest version on GitHub, due to caches and using a CDN. However, an attacker could hide a commit on GitHub, for example in an old branch. To solve this, the Service Worker could check that the commit is in a specific 'release' branch, and either the latest commit or no more than 24 hours old. We plan to implement this but haven't done so yet.

Service Worker lifecycle

The designers of the Service Worker specification have taken great care to make sure that a web application cannot permanently break itself using Service Workers: the browser checks for an update to the SW on every page load, and we can't prevent the SW from being updated if it has been changed on the server. Fortunately, both the old Service Worker and the web app get notified when that happens, so we can notify the user of the update.

However, we can't actually check that the new Service Worker matches the version on GitHub. We can request the new Service Worker file, of course, but (at least in Chrome) that issues a separate network request from the request that Chrome itself used to get the Service Worker, so we can't be sure that the server replied with the same file.

response_matches_sw.png

It would be nice if Chrome could put the Service Worker file it got in network cache, so that the old Service Worker can request it from there. Then, we can stop showing the relatively unhelpful warning above.

Service Workers also update on Push Notification and Background Sync events. We currently use neither, but it's worth verifying that browsers starts the old Service Worker for the event (while updating asynchronously) and sends it an update event, which is what we want. It's also worth verifying that there's no other way to trigger an update, especially without starting and notifying the old Service Worker, since that would be a vulnerability for our use case.

Previous approaches to Transparent Web Apps

Previously, some (including Airborn OS) have been using browser addons to increase the security of their web apps. The obvious disadvantage of this is that users have to install an addon. Also, you can't install addons on mobile Chrome and Safari.

I've previously written about another approach using Certificate Transparency. Basically, the idea is to put checksums of the files of the web app in the website's certificate. Thanks to Certificate Transparency, we can check that there's only one certificate for the website (and by extension, only one version of the code).

The advantage of that approach is that it's less trust-on-first-use: it can protect you even the first time you open the web app on a computer. The disadvantages are that it's less flexible (because it's implemented in the browser or an addon instead of in the web app), requires more work or tooling to update the web app, and requires work on the part of browser makers to implement. The solution using Service Worker, in contrast, can be deployed today.

Next steps

There are many web apps that would benefit from being made transparent: encrypted chat apps, BitCoin wallets, but also client-side tools such as word counters and photo editors. Let us know if you're a web app developer and need help implementing something like this. We would also like to create a library (maybe with the help from other web app developers) to make that easy. Let us know if you want to help or have any feedback!

The first web application that doesn't trust the server

Airborn OS is an in-browser OS and Google Docs alternative that encrypts your files in the browser.

TLDR: The latest version of our Firefox extension has been approved. It checks the content at https://www.airbornos.com against a known good version. This way, you see a warning if anyone in the chain from us to you wants to, say, steal your password. That could be us, our hosting provider, our Content Delivery Network (CDN), someone who hacks any of the above, or someone further down the chain who can get their hands on a certificate for airbornos.com.

Every so often, someone comes along who wants to make a web application that can't read the notes you store in it, or view the pictures you store in it, or something like that. "I'll use a symmetric encryption library! Then user's notes are secure." Most of them are promptly redirected to this Matasano article or some other explanation of the fact that if your users are entering their password and notes on your website, they have to trust you every time they do that. So why use encryption at all?

We, too, read the articles. Couldn't we cheat? Maybe we could build a browser extension? In fact we did, for Firefox. It contains checksums of the first few files you get from airbornos.com. If any of them don't match, you get a big error page. Or if the checksums are considered out of date, you get a smaller warning.

The checksums are considered out of date when a new certificate for airbornos.com has been generated and is in use. Today, that can be done quite easily and unnoticed, so the warning shouldn't be taken lightly. However, in the future, Certificate Transparency will notify people when that happens, so that they can check if a corresponding extension update has been issued.

These first files, checked by the extension, then continue to fetch and execute further scripts, which are authenticated with the user's password. If the user wishes, they are asked before updating those further scripts. The result is that none of the scripts that the server delivers are trusted at face value.

But Firefox extensions take weeks to update, right? You can't put a website's checksum in there!
Our experience so far, with three versions of our extension, has been pretty good. Still, this is a valid concern. The first few files on airbornos.com have been purposely designed to remain constant. For example, most of the content on the homepage is loaded in a sandboxed iframe. This has some downsides, but for us it's worth it.

Nobody wants to install an extension before using a web app!
We hope that those who care about their security will. However, not everybody has to install the extension for everybody to benefit: an attacker doesn't know in advance whether or not you have the extension installed, after all.[1] That means they don't know if their attempt will go unnoticed.

Does this mean Airborn OS is secure?
Maybe. We would like to have a full audit done of Airborn OS and the Firefox extension in the future. However, if you install the extension, and disable automatic updates for Airborn OS, you're probably running the code that's on GitHub.

Can my web app do this too?
Yes. Send a pull request with your web app's checksums. However, make no mistake: the files for which you include checksums can't change often.[2] So your web app either needs to be very simple, or you need to build upon this to verify the rest of the web application in some other way. A simple example would be to check the rest of the source with the version on GitHub.

Notes

[1] Unless you don't use Firefox. However, in the future we could solve that by 1) releasing an extension for other browsers or 2) impersonating other browsers in our Firefox extension for some users.

[2] If you want to help decide on branding for the addon, or want help with making the first few files of your web app static, shoot me an email (see GitHub).

A Better Taskbar

Airborn OS is an in-browser OS and Google Docs alternative that encrypts your files in the browser.

Normally when I talk to people about certain things in Airborn OS, such as its security, they at least think it's somewhat complicated, sometimes even overcomplicated. However, there's one thing I show people that I'm proud of, but they seem to think is completely obvious and even uninteresting:

When you minimize a window, it's placed on the taskbar in the location closest to where it was, not next to the previous window.

Please try out the Airborn OS Demo if it's not clear what this means.

Indeed, it didn't take a long time to come up with this. Nevertheless, I've never seen it anywhere else.

The main advantage to this is that it makes it easier to find windows you were previously looking at, which is the purpose of the taskbar.

The main disadvantage is that if all your windows are maximized and you only have one screen, it doesn't help you. Currently, Airborn OS partially layers those windows on top of each other so that only the icon is visible. However, many modern taskbars already only show the icon, so it might actually work well in that case.


Thinking further

How do we make it easy to find windows you were previously looking at?

One counter-question is, "What do we know about the window we are trying to find?" Every answer to that question points to a window switching mechanism:

  • Its title
    • Show every window's title on the taskbar
    • Make a "window search box" in which you can type part of a window's title
  • Its icon
    • Show every window's icon on the taskbar
  • Its location
    • Make windows' position on the taskbar close to their location
    • Add a mechanism to view and switch to covered windows (e.g., a 3D view which looks at the desktop at an angle from above)
  • What it looks like
    • Add a mechanism to view all open windows
  • That we we were looking at it recently
    • Show a list of windows in order of last focused
  • Where it always is
    • Allow users to order their window list

Obviously, some mechanisms show multiple properties of the window, such as its icon and title, or its location and what it looks like.


Invitation to experiment

Switching windows on many operating systems can still feel a bit behind, say, switching files in Sublime Text. In any case, there's probably always room for improvement on every OS.

If you know HTML, CSS and JavaScript, not just Airborn OS's taskbar is written in it — Cinnamon's (the desktop environment by Linux Mint's developers) is as well, and GNOME 3 allows you to write extensions (including a taskbar) in JavaScript, too.

Small UX Tip: Show Password Requirements at Login, not just when Registering

Airborn OS is a secure alternative to Google Docs.

In an ideal world, everyone would use a password manager and unique passwords on every website. But in reality, many people use the same password on many websites. Let's take one user as an example. His name is Marc. Marc uses the same password of 10 characters on every website. However, when registering for your website, he gets an error: "Password has to be at least 12 characters long." (This is a good idea, in my opinion.) Marc is annoyed, but he spends half a minute to think of something to add to his password.

Now he is successfully registered. However, next time he wants to login, he'll probably try his normal password of 10 characters. "Password incorrect", he gets. He doesn't remember why or what his different password is, so he clicks "Forgot password." This gives him a link that asks him to fill out a new password. He enters his normal password. "Password has to be at least 12 characters long." Oh, right, he thinks, I probably added something to my password. Maybe it was … . He fills out his password on your website. Now, to add insult to injury, your website might say "Can't use the same password."

Seeing the "Password has to be at least 12 characters long" message put him in the thought process he was in when he created the password. That's a good way to remember it. If he'd gotten that message earlier, at login, it might've saved him some of the steps above.

Of course, this gets tricky to implement if your password requirements have ever changed or if you want to change them later. You would either have to remember their password requirements in a database in some way, or you'd have to require that everyone whose password does not fulfill the new requirements change it. The former gets especially tricky when you use a library that calculates the strength of a password. The latter is also tricky, because you only know they didn't meet the requirements after they've logged in, which is what you're trying to help them do.

Two mobile applications I know of that get this right: my HTC tells me, when I accidentally try to unlock with a three number passcode, that four numbers are required (admittedly a bit silly because I already know that, but some people might not) and the ING Bank app has 5 squares in which the numbers of my passcode go.

If you want to help implement this and other improvements in Airborn OS, take a look at the registration code on GitHub.

Dividing Content into Visual Pages in CSS

Airborn OS is a secure alternative to Google Docs.

Pages Demo Screenshot

Unlike Google Docs, Airborn OS (or rather Firetext, the text processing app) doesn't include a custom renderer for text documents. Instead, it uses the browser's built-in html viewing and editing capabilities. This means that if we want to divide content into visual "pages" that correspond to the pages that would come out of a printer, we'd have to do it in CSS (or a combination of CSS and JavaScript). Can it be done?

It sure can, with some trickery. The trickery consists of two steps:

  1. Divide the content into CSS3 Columns. Thanks to the foresight of the creators of the Columns spec, column-count: 1 happens to do exactly what we want: divide into columns with a specific width and height.
  2. Rotate the columns so they are under each other instead of next to each other, and rotate the content so it's the right way up: writing-mode: vertical-lr and writing-mode: initial. This tells the browser it should order text (and columns) from top to bottom.

    Unfortunately, this trickery only works in Firefox and then only if you set layout.css.vertical-text.enabled to true. If you do that, you can see a working demo here.


    This trick no longer works since Firefox 40. Instead, you can use transforms to rotate the columns.

Even when support is enabled by default in Firefox, there are still unsolved problems: it's hard to style individual "pages" much further than in the demo (padding, box-shadow and border don't work on individual pages; outline does but is buggy). (Edit: the new box-decoration-break CSS property should solve this, but it's only supported in Firefox and even there it's slightly buggy.) When you enable editing text more problems arise, for example this bug.

Also, before you use this on your own website, there's a debate to be had if pages improve readability. Still, it's a cool trick and it's amazing that it works at all.

For a related technique to show only one page at a time, see this article.

Airborn OS as a Secure Alternative to Google Docs

Maybe you want something more secure than Google Docs/Drive.
If so, Airborn OS might be a good alternative for you.

What is Airborn OS?

  • It's an operating system in the cloud.
    It comes with the app "Firetext" to edit text documents.
  • It's accessible from any platform.
    Like Google Docs, you only need access to a browser to edit your documents. Unlike Dropbox, you don't need to download and upload your documents to edit them.
  • Your files and apps are all encrypted in the browser.
    This makes Airborn OS much more secure than Google Docs.

How does Airborn OS realize more security?

The encryption of Airborn OS uses a private key. Every user has their own private encryption. The encryption is used both for the documents and the code of Airborn OS to open and edit your documents. So nobody can read your documents, or change the code to open and edit your documents.[1]

What can't you do with Airborn OS yet?

Google Docs is a complex product with many features. Airborn OS and Firetext are still in development and don't have all of them. Here are some things you can't do with them yet:

  • Work together on documents.
    Firetext, for now, is an individual app. You can't edit one document with two people at the same time unless you're sitting next to each other.

    Airborn OS has collaboration now.
  • Spreadsheets and presentations.
    With Firetext, for now, you can only upload, create and edit text documents.
    Airborn OS has a presentation editor now. Spreadsheets are on the roadmap.

In short, Airborn OS with Firetext might be a good alternative to Google Docs if you want more security and don't need all the functionality of Google Docs.

Notes

[1] For more information on how this is made secure see http://blog.airbornos.com/post/2015....

Secure Delivery of JavaScript

Airborn OS is an in-browser OS that encrypts your files in the browser.

Let's say you wanted, like us, to create a web application that encrypts your user's data with their password before it stores it on your servers. You value your user's privacy, after all. Does this buy you anything, though? Not really. Tomorrow you could change your code to send you your user's password. Even worse, you could do so for a particular user you're interested in. In other words, there's no way to securely deliver a web app without trusting the server.

Yet. What we need, in essence, is an external source that tells us what the HTML, CSS and JavaScript of the web app should be. People should be able to be notified when the source changes, in case you changed it to send you their password, and it should be the same for everybody, so that when one person checks the source, everybody can be more confident in it. A browser addon, or eventually the browser itself, could then check the server's responses with that external source.

One possibility for the external source is the browser addon itself. However, updates to Firefox addons can take a few weeks to be approved, which is simply too long when you need to change your JavaScript (more about that later). Browser updates also take six weeks, if we ever wanted to build this functionality into the browser.

A more promising possibility is the website's certificate. With the upcoming Certificate Transparency (CT), people will be able to keep track of certificates and be confident that everyone gets the same certificate. We could use a certificate extension to store the information we need. Currently, though, no Certificate Authority (CA) that I'm aware of actually allows you to put arbitrary information in certificates. One CA we asked worried about CA/Browser Forum requirements. One CA was willing to do it, but at a large sum per generated certificate, which is a disincentive you shouldn't want.

Finally, we could do something in between those two possibilities: store the information in the addon, but allow updating the web app by regenerating a certificate (which is faster). In other words, pin the information to the certificate. This is what we currently do for airbornos.com. We call it "HTTPS Content Signatures" (HCS) and the addon is here (code).

Once Certificate Transparency becomes a requirement in browsers[1], this means it's no longer possible to serve unknown certificates with a website (that's what CT is). That means it's no longer possible to serve unknown HTML or JavaScript to the browser as long as every known certificate is listed in the addon (that's what the addon does). Secure delivery of JavaScript, coming soon!


As promised above, one more note about updating the web app. Having to regenerate your certificate every time you update your web app is still quite unfortunate, especially if it means users of the addon are no longer protected. It might be necessary to reduce the amount of code that is protected this way. I'll offer two possibilities.

For the homepage and login page, you could separate form from function with a sandboxed iframe. However, there are many small problems with this to which I have no solution yet: it complicates scrolling, if you allow navigating the top frame (for links) that could be abused, and some things can't be moved to an iframe (e.g. <meta> tags).

For the web app itself, you could protect only a small "loader" and do in it whatever you want. What we do is decrypt the rest of the code with the user's password.

This is all by no means an easy or ready-made solution, but for web apps that are very serious about security, it could be an important building block.

Notes

[1] Since we have an addon anyway, we could build this requirement into the addon. We haven't done so yet, though.