"True" end-to-end security with Javascript

End-to-end is hard, especially on the web. For me there's a difference between true and non-true end-to-end.

When we talk about end-to-end security we probably think it's when everything is handled locally and only cipher text is sent between client and server. This is partly true, but what happens if the server is compromised? Then a hacker can serve scripts that backdoors the encryption and in worst cases make the client send plaintext instead of ciphertext, I mean how can the client verify that the files he/she got are legit?

But what about extensions?

Extension will work just great! But do they work everywhere? Hopefully soon we will see more browsers with built-in Javascript libraries which servers can enforce the user to use.


With CSP-and SRI-hashes the client can automatically verify the integrity of resources


SRI

SubResource Integrity(SRI) is a method to verify the contents of a third-party resource with a hash, in the <script> and/or <link> element, like so: integrity="<hash>". If the hash does not match the content, it will not be loaded. You can read more here.

This is great because let's say the server that hosts the content gets hacked the hacker could serve bad code instead of the requested resource. Also, this only works with webservers that supports CORS so it will not work all the time. If you want it to work you have to host it yourself.

The hash is called a "SRI"-hash and can be calculated in openssl like this cat file.js | openssl dgst -sha256 -binary | openssl base64 -A.

CSP

Content Security Policy(CSP) is awesome in many way and is extended with new features from time to time. In one of the latest versions(1.1) you can verify the contents of inline-javascript but you can of course do so much more with CSP.

With CSP you can tell the client that only resources from a specific domain is allowed and over which protocols(http, https or wildcard). CSP is extremely powerful in many ways and I'll show en example how you can serve resources in a more secure way.


An example with CSP and SRI



So let's say that you have built a web based email service where users login via a website. Your domain is www.mysecure.email

At the login page there's resources such as CSS, images and Javascript. The CSS and Javascript-files are served from your static webserver that is hosted at another provider. The servers only purpose is to serve static files.

Both the CSS and Javascript is loaded from https://static.mysecure.email and is using SRI-hashes so the client can verify the integrity and if the hashes does not match the contents of the files the user will not be able to login.

There's also a CSP-policy that tells the user that only content from https://static.mysecure.email is allowed to be loaded. Also, inline Javascript is disallowed(script inside <script>-tags). The only actual content that is allowed is raw HTML.

-

So how secure is this? What is the static server is hacked? Or the webserver?

If the server that serves the Javascript and CSS gets hacked the hacker will not be able to do any harm because even a slight change in the content will stop the clients browser to load any resources.

But if the main server gets hacked the hacker will be able to do some harm depending on what access level he/she got. The hacker will not be able to change the CSP-policy without root-access but he/she can still do some harm. The hacker could insert HTML-form that tricks the user to enter it's credentials that later sends it to another domain. But the hacker will not be able to insert own CSS and/or Javascript without changing the CSP-policy(it's located in the webserver configuration).


It's good, but not perfect


CSP and SRI is indeed awesome and adds some layer of security on the web, but it's not perfect. I would like to see something like HSTS and HPKP but for resources.

The server should offer the client an hash of the served content(this is possible using CSP) and tell how long this hash should be valid. But this would also be dangerous if the content is vulnerable because then the client would be forced to use vulnerable code and that's not good...

Also, dynamically offered hashes is a bad idea because what if the server offers hacked Javascript and a new client visit the server, then he/she would not be able to visit the server when the bad code is cleared from the server. So only static hashes would work. Well, only if the script is secure.

So maybe it is perfect after all...