2

I am interested if it could be possible to validate source code integrity for web apps somehow.

For example:

  1. Developer builds app and sign source code with his private key. Both signature and public key is included in web app.

  2. User fetches web page.

  3. Browser plugin stores public key for web page.

  4. Developer builds new version as step 1.

  5. User has already public key from previous update in plugin. Plugin checks integrity of source code. If there is problem, it blocks all requests.

Is something like this technically possible?

Thank you

0

1 Answer 1

1

Yes, you could implement this for pages consisting solely of client-side resources, with some caveats.

Subresource Integrity (SRI) allows you to provide a cryptographic hash of a resource, such as a script or CSS file, being included in a page. The hash is included in the HTML of the web page, for example:

<script src="https://cdn.example/jquery.js" integrity="sha256-abcd1234..." crossorigin="anonymous"></script>

The browser downloads the remote resource, computes its SHA256 hash, and refuses to process it further if the hash does not match.

This doesn't guarantee authenticity on its own, but it guarantees that the content was not modified since being hashed, so it provides transitive trust. If you trust the page that contains the hash, then you can trust that the loaded content was not modified. The typical use-case for SRI is for hosting content on third party CDNs.

In most scenarios, the trust you have in the page comes from the fact that you trust the operator of the server, and your trust in the server's identity comes from the fact that HTTPS was used and the server certificate was signed by a trusted CA. This builds a chain of trust from the CA to the server to the served webpage to the third party content covered by SRI.

However, if you don't inherently trust the server not to modify the content (e.g. if your threat model needs to consider the server being compromised) then the chain of trust is broken. HTTPS with a valid certificate only guarantees that you're talking to the real server as identified by the DNS name matching the certificate's common name, but it doesn't guarantee that the server itself isn't doing something malicious. In addition, you can't use SRI to hash the page itself - SRI is specifically for subresources.

This break in the chain could be solved by digitally signing the HTML and verifying it in the browser, either using a standardised browser feature or with a plugin like you suggested. Since the page is signed, SRI then handles all the additional content loaded from script or link tags. Images and media unfortunately cannot be restricted by SRI.

Back in 2007, W3 worked on a standard called HTML Signing Profile which was intended to solve essentially this exact problem. It did not become a standard, though, so you're out of luck there.

One approach you might consider is to exploit the XML Signature standard: wrap a HTML page in an XML wrapper, then have your plugin use the existing standard to validate that signature and unwrap the document. That is workable, but it is also problematic. You can't really put a HTML5 document into an XML document as if it were XML, because even though they look similar they are in fact different standards. You could instead have the HTML5 be loaded as a CDATA string, but that's a bit of a hack.

Another way to go would be to have the digital signature placed into the opening HTML tag at the top of the page. The signature would be created on the page with this tag empty (e.g. pagesign="") and the validation process would involve emptying out this tag and then computing the signature on the served document. I would recommend against this, though. It requires parsing the DOM or doing string search and substring extraction on the HTML before the document's authenticity can be proven, which is fraught. These schemes often result in critical vulnerabilities by abusing the parsing logic.

One of the better approaches is to load the signature into a HTTP response header, and have the plugin perform the verification. This is cleaner, because it doesn't affect the content, but it does require some work on the server side to ensure that the header is sent.

Whichever way you go with there is an additional problem: how do you know when you're supposed to be seeing a signature? If the server doesn't send a signature, your browser plugin doesn't check the validity. Exactly how you resolve this depends on your requirements. If you know the domain names that are hosting the content ahead of time, you can have your plugin automatically check for the signature and its validity when you try to go to a URL on that domain, and refuse to load the page if the signature is not present or is invalid. If you don't know the domain names ahead of time, the best you can really do is have the user reactively add a rule when they come across a page they know should be signed.

The final trust problem is the plugin and the signatures themselves. If you can't trust the plugin or the signatures, you can't trust the signature validation, which means you can't trust the page or any of its subresources. This is generally tractable if your browser plugins support digital signing, though.

A major caveat to this design is that dynamic content, i.e. any data that is introduced into the system after publication by the developer, cannot be protected by this kind of authenticity check. In addition, any code that needs to run on the server-side (e.g. for providing REST APIs) is inherently opaque to the client and also cannot be checked for authenticity (unless you want to get into hardware enforced remote attestation). The developer can sign static resource files (e.g. JSON) but anything that changes dynamically cannot feasibly be authenticity checked beyond what is already offered by HTTPS.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .