Cache across domains with a file hash
alexchamberlain.co.uk
alexchamberlain.co.uk
Firstly you need a way to incrementally verify a file: you don't want to have to download and buffer the whole file before figuring out whether it's good. Thankfully you can do this with Merkle trees: just make them `degenerate' (every left child is a leaf node).
If you make the browser cache content addressable (as the post suggests) then you need to do more than look at the caching header. Consider a site with Content Security Policy enabled: If an attacker found an XSS, they could inject <script href="http://correct.origin.com/foo.js digest="degen-hash:sha256:123abc...">. That would match the CSP origin restrictions without the server ever having to serve foo.js. (Thanks to abarth for pointing that out.)
So I believe content addressable caches would need a separate hash:// URL scheme for this. But I didn't attempt to make the cache content addressable in my code.
I don't know what to do about img srcsets[1]. There's no obviously good place to put the hashes in the HTML.
And lastly, and possibly fatally for the "secure HTTP resources in HTTPS pages" use case, many networks will now transcode images on the fly (and possibly other files too). So matching a known hash will result in broken pages for users on those networks.
[1] http://www.whatwg.org/specs/web-apps/current-work/multipage/...
I believe that we collected some data in Chrome about the efficacy of a content addressable cache in improving density that was underwhelming, despite expectations. I don't have it to hand, but I suspect that it'll appear in a paper at some point.
I've not seen data about how well it reduces network loads yet, although I believe the same colleagues were intending to collect that too.
As it is, I think customers would already be angry if they knew that their network provider was rewriting code that will be executed on the customer's computer; anything which makes this more obvious can only be good.
I'm not claiming that this is good, but it is the reality of writing browsers.
Following the proposal of the article, you don't really need that. If you don't have the hash in your local cache, you should assume that the link provided by the site is correct and resume as you normally would without the hash present. When it's downloaded, you verify the downloaded contents with the hash, and add the file to the cache if the verification succeeds.
If you already had the hash in the local cache, then you already have the entire file and there's no need for incremental verification.
As I understand it, the point of the hash is purely for caching purposes, not strictly for validating that the downloaded file matches it.
That is a very useful consequence that prevents malicious content.
Or have we just given up trying to deal with all the privacy leaking side-channels in browsers these days?
Another way to do this would be to allow multiple alternative src urls for a resource. Then the browser could pick the best (for as yet undetermined values of best) source the resource.
This has the extra bonus of advantage of looking mostly like a normal <link> or <script> tag and doesn't introduce yet another way to probe across domains.
It would only apply to scripts you add the `sha256` attribute to and you would probably only do this for public libraries.
Unless the original content source has opted into this kind of behaviour this seems like a privacy leak to me.
This would effectively mean the person serving the files gets to determine if you are succeptible to this. If I serve you foo.js and don't want others to know you've seen it, I just make sure not to put a hash.
Although, overloading the hash this way sounds wrong. I'd rather see a "shared_cache='public|domain|none' property. I still like the consuming HTML being responsible for deciding that, though.
Of course, that means without duplicating it you would still need a request similar to If-Modified-Since - something like If-Hash-Differs: <sha256 hash>, but still better than downloading the whole file.
I've thought about this exact problem before and one nice way to solve it would be through some kind of signing process - so you instead tell the browser "I need com.jquery.1.7.2" and there would be some way of verifying that a given instance of that file was legitimate, and could thus be cached across multiple URIs.
On the web application side, by putting a "sha" tag in the script tag, the app is saying, "Fail if foo.js isn't the one I expect, regardless of where it comes from." By putting a "shared_cached" in the script tag, the app is telling the client where it is allowed to look for and to put foo.js.
Finally, a client should be able to ignore any shared cache requests and make everything private at the user's request.
An alternative use of this would be to validate the script that is being downloaded from the remote source. If you're delegating to Google or any other CDN for a javascript library you really expect it to be the one you requested. Assuming you're not pointing at the HEAD/latest version versus a specific (which would already be pretty amateur for a real site) then you expect it to always be exactly the same (ex: jquery-1.8.1.min.js should always be the same file ... if a bug is fixed it's a new version). It'd be a security improvement to have a way to have the browser verify that.
<script src="https://some-cdn.example.com/some-library-1.2.3.js hash="[secure hash of contents]">
If the downloaded file's hash does not match the expected one then the browser would flag a security warning or simply not load the file.
A malicious website could then include a request to download a bogus URL from their site with a hash which matched that of the bank statement AJAX response. The browser would then return the cached bank statement, without ever noticing the URLs were bogus or didn't even point to a file with the desired hash. The malicious website could then upload the bank statements back to itself.
This seems like technically an attack path, but it relies on being able to guess a 256-bit hash in a relatively small number of guesses; if you can do that, you might as well just start guessing password hashes and log in to a target website directly.
We're talking about a long-term standard.
A new chance for this to change soon may be come alongside the forthcoming browser-to-browser connectivity standards under the heading "WebRTC". Then you won't just have to hope a matching file might be in your local cache... you can cooperate with other nearby nodes to find reliable replicas (like the P2P networks do), triggered by a content-hash-specifying URI scheme.
http://lists.w3.org/Archives/Public/public-html/2012Jun/0094...