Signed Web Pages

Signing and Verifying Web Pages and Web Apps Using PGP and a Browser Extension

 ·  3 minutes read

As some of you already know, I've recently released the EteSync Web App. It's a fully blown EteSync client that lets you access all of your data while maintaining the End-to-End encryption assurances you've come to expect from EteSync.

There is one caveat though. The above describes the code in the EteSync repos, not necessarily the code on the server or the code being served by the server.

One way to solve it, is to clone the EteSync Web App's repo, verify it locally using the signed tags, and then run a local version. This will give you the same assurances as a native app. The other, more convenient solution, is using the new web extension I just released: Signed Pages.

The Problem

Unlike with native applications, where you can install a version you can verify (or even build yourself), with web apps, you are served the app every time you enter the website. This means, that the server could all of a sudden serve malicious code to everyone, a small group of users or a specific targeted user. Even worse, a state-sponsored attacker could issue a certificate for a certain domain, man-in-the-middle the connection to the server and serve malicious code to the user. This is slightly mitigated by certificate transparency, but the issue still remains.

The Solution

One solution to this problem is signing web pages using PGP and using trusted code (a browser extension) to verify it.

As a user, all you need to do is install Signed Pages and add the websites you want. At the moment, you need to manually add the pattern and the expected public key of the signer as provided by the developer, though I plan on making it more user friendly in the future.

How it Works

Developers sign their pages using a detached PGP signature, and put the signature as the first comment in the page after the doctype. That's it. There's even a script that does that for you, which you can get from here.

Users with the browser extension configured will then see a shield in their address bar (or tool bar, based on browser) based on the validity of the signature. If a signature is valid, a green shield with a black tick will be shown, and if it's invalid or missing (but expected for a page) a red shield with a big black X will be shown.

Valid Signature

We however only solved part of the problem. We now verify that the page we are accessing is indeed what we expect, but what about its external scripts and CSS? Luckily, this is already a solved problem. All you need to do is enable subresource integrity for all of external resources in the page (event if served from the same server!), and the browser will verify them automatically.

For example, to include jquery:

<script src="/assets/jquery-2.1.4.min.js"
    integrity="sha384-R4/ztc4ZlRqWjqIuvf6RX5yb/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC"
    crossorigin="anonymous">
</script>

You can also include jquery from a CDN and you'll have the same integrity assurances.

More Information

For more information please refer to the README and the source code, or let me know if you have any questions.

Please let me know if you spotted any mistakes or have any suggestions, and follow me on Twitter or RSS for updates.

pgp encryption web security