[HN Gopher] Improving the Trustworthiness of JavaScript on the Web
___________________________________________________________________
Improving the Trustworthiness of JavaScript on the Web
Author : doomrobo
Score : 49 points
Date : 2025-10-16 14:50 UTC (8 hours ago)
(HTM) web link (blog.cloudflare.com)
(TXT) w3m dump (blog.cloudflare.com)
| some_furry wrote:
| This is really cool, and I'm excited to hear that it's making
| progress.
|
| Binary transparency allows you to reason about the auditability
| of the JavaScript being delivered to your web browser. This is
| the first significant step towards a solution to the "JavaScript
| Cryptography Considered Harmful" blog post.
|
| The remaining missing pieces here are, in my view, code signing
| and the corresponding notion of public key transparency.
| zb3 wrote:
| Ok (let's pretend I didn't see the word "blockchain" there), but
| none of this should interfere with browser extensions that need
| to modify the application code.
| some_furry wrote:
| EDIT: Disregard this comment. I think there was a technical
| issue on my computer. Keeping the original comment below.
|
| -----
|
| > let's pretend I didn't see the word "blockchain" there
|
| There's nothing blockchain about this blog post.
|
| I think this might be a rectangles vs squares thing. While it's
| true that all blockchains use chains of hashes (e.g., via
| Merkle trees), it's not true that all uses of append-only data
| structures are cryptocurrency.
|
| See also: Certificate transparency.
| JimDabell wrote:
| They specifically suggest using a blockchain for Tor:
|
| > A paranoid Tor user may not trust existing transparency
| services or witnesses, and there might not be any other
| trusted party with the resources to self-host these
| functionalities. For this use case, it may be reasonable to
| put the prefix tree on a blockchain somewhere. This makes the
| usual domain validation impossible (there's no validator
| server to speak of), but this is fine for onion services.
| Since an onion address is just a public key, a signature is
| sufficient to prove ownership of the domain.
| some_furry wrote:
| Oh, weird. I didn't see that (and a subsequent Ctrl+F
| showed 0 results) but now it's showing up for me?
| AndrewStephens wrote:
| As a site owner, the best thing you can do for your users is to
| serve all your resources from a server you control. Serving
| javascript (or any resource) from a CDN was never a great idea
| and is pointless these days with browser domain isolation, you
| might as well just copy any third party .js in your build
| process.
|
| I wrote a coincidently related rant post last week that didn't
| set the front page of HN on fire so I won't bother linking to it
| but the TL/DR is that a whole range of supply chain attacks just
| go away if you host the files yourself. Each third party you
| force your users to request from is an attack vector you don't
| control.
|
| I get what this proposal is trying to achieve but it seems over
| complex. I would hate to have to integrate this into my build
| process.
| doomrobo wrote:
| You're right that, when your own server is trustworthy, fully
| self-hosting removes the need for SRI and integrity manifests.
| But in the case that your server is compromised, you lose all
| guarantees.
|
| Transparency adds a mechanism to detect when your server has
| been compromised. Basically you just run a monitor on your own
| device occasionally (or use a third party service if you like),
| and you get an email notif whenever the site's manifest
| changes.
|
| I agree it's far more work than just not doing transparency.
| But the guarantees are real and not something you get from any
| existing technology afaict.
| EGreg wrote:
| If they want to make a proposal, they should have
| httpc://sha-256;... URLS which are essentially constant ones,
| same as SRI but for top-level domains.
|
| Then we can really have security on the Web! Audit companies
| (even anonymous ones but with a good reputation) could vet
| certain hashes as being secure, and people and organizations
| could see a little padlock when M of N approved a new
| version.
|
| As it is, we need an extension for that. Because SRI is only
| for subresource integrity. And it doesn't even work on HTML
| in iframes, which is a shame!
| ameliaquining wrote:
| The linked proposal is basically a user-friendlier version
| of that, unless you have some other security property in
| mind that I've failed to properly understand.
| jmull wrote:
| It would be helpful if they included a problem statement of some
| sort.
|
| I don't know what problem this solves.
|
| While I could possibly read all this and deduce what it's for, I
| probably won't... (the stated premise of this, "It is as true
| today as it was in 2011 that Javascript cryptography is
| Considered Harmful." is not true.)
| miloignis wrote:
| For me, the key problem being solved here is to have reasonably
| trustworthy web implementations of end-to-end-encrypted (E2EE)
| messaging.
|
| The classic problem with E2EE messaging on the web is that the
| point of E2EE is that you don't have to trust the server not to
| read your messages, but if you're using a web client you have
| to trust the server to serve you JS that won't just send the
| plain text of your messages to the admin.
|
| The properties of the web really exacerbate this problem, as
| you can serve every visitor to your site a different version of
| the app based on their IP, geolocation, tracking cookies,
| whatever. (Whereas with a mobile app everyone gets the same
| version you submitted to the app store).
|
| With this proposed system, we could actually have really
| trustworthy E2EE messaging apps on the web, which would be
| huge.
|
| (BTW, I do think E2EE web apps still have their place
| currently, if you trust the server to not be malicious (say,
| you or a trusted friend runs it), and you're protecting from
| accidental disclosure)
| jmull wrote:
| It doesn't seem like there's much difference in the trust
| model between E2EE web apps and App Store apps. Either way
| the publisher controls the code and you essentially decide
| whether to trust the publisher or not.
|
| Perhaps there's something here that affects that dynamic, but
| I don't know what it is. It would help this effort to point
| out what that is.
| fabrice_d wrote:
| On the web, if your server is compromised it's game over,
| even if the publisher is not malicious. In app stores, you
| have some guarantee that the code that ends up on your
| device is what the publisher intended to ship (basically
| signed packages). On the web it's currently impossible to
| bootstrap the integrity verification with just SRI.
|
| This proposal aims at providing the same guarantees for web
| apps, without resorting to signed packages on the web (ie.
| not the same mechanism that FirefoxOS or ChromeOS apps
| used). It's competing with the IWA proposal from Google,
| which is a good thing.
| knowitnone3 wrote:
| everyone gets the same version that sends your secure
| messages to another server? I'm impressed.
| CharlesW wrote:
| > _I don 't know what problem this solves._
|
| This allows you to validate that "what you sent is what they
| got", meaning that the code and assets the user's browser
| executes are _exactly_ what you intended to publish.
|
| So, this gives web apps and PWAs some of the same guarantees of
| native app stores, making them more trustworthy for security-
| sensitive use cases.
| everdrive wrote:
| I improve the trustworthiness of js by blocking it by default.
| thadt wrote:
| Starts reading: "fantastic, this is what we've been needing!
| But... where is code signing?"
|
| > One problem that WAICT doesn't solve is that of provenance:
| where did the code the user is running come from, precisely?
|
| > ...
|
| > The folks at the Freedom of Press Foundation (FPF) have built a
| solution to this, called WEBCAT. ... Users with the WEBCAT plugin
| can...
|
| A plugin. Sigh.
|
| Fancy, deep transparency logs that track every asset bundle
| deployed are good. I like logging - this is very cool. But this
| is not the first thing we need.
|
| The first thing we need, is to be able to host a public signing
| key _somewhere_ that browsers can get and automatically signature
| verify the root hash served up in that integrity manifest. Then
| point a tiny boring transparency log at _that_. That 's the thing
| I really, really care about for non-equivocation. That's the
| piece that lets me host my site on Cloudflare pages (or Vercel,
| or Fly.io, or Joe's Quick and Dirty Hosting) that ensures the
| software being run in my client's browser is the software I
| signed.
|
| This is _the_ pivotal thing. It _needs_ to live in the browser.
| We can 't leave this to a plugin.
| doomrobo wrote:
| I'll actually argue the opposite. Transparency is _the_ pivotal
| thing, and code signing needs to be built on top of it (it
| definitely should be built into the browser, but I'm just
| arguing the order of operations rn).
|
| TL;DR you'll either re-invent transparency or end up with huge
| security holes.
|
| Suppose you have code signing and no transparency. Your site
| has some way of signaling to the browser to check code
| signatures under a certain pubkey (or OIDC identity if you're
| using Sigstore). Suppose now that your site is compromised.
| What is to prevent an attacker from changing the pubkey and re-
| signing under the new pubkey. Or just removing the pubkey
| entirely and signaling no code signing at all?
|
| There are a three answers off the top of my head. Lmk if
| there's one I missed:
|
| 1. Websites enroll into a code signing preload list that the
| browser periodically pulls. Sites in the list are expected to
| serve valid signatures with respect to the pubkeys in the
| preload list.
|
| Problem: how do sites unenroll? They can ask to be removed from
| the preload list. But in the meantime, their site is unusable.
| So there needs to be a tombstone value recorded somewhere to
| show that it's been unenrolled. That place it's recorded needs
| to be publicly auditable, otherwise an attacker will just make
| a tombstone value and then remove it.
|
| So we've reinvented transparency.
|
| 2. User browsers remember which sites have code signing after
| first access.
|
| Problem: This TOFU method offers no guarantees to first-time
| users. Also, it has the same unenrollment problem as above, so
| you'd still have to reinvent transparency.
|
| 3. Users visually inspect the public key every time they visit
| the site to make sure it is the one they expect.
|
| Problem: This is famously a usability issue in e2ee apps like
| Signal and WhatsApp. Users have a noticeable error rate when
| comparing just one line of a safety number [1; Table 5]. To
| make any security claim, you'd have to argue that users would
| be motivated to do this check and get it right for the safety
| numbers for every security-sensitive site they access, over a
| long period of time. This just doesn't seem plausible
|
| [1] https://arxiv.org/abs/2306.04574
| thadt wrote:
| I'll actually argue that you're arguing exactly what I'm
| arguing :)
|
| My comment near the end is that we _absolutely_ need
| transparency - just that what we need tracked _more_ than all
| the code ever run under a URL is that one signing key. All
| your points are right: users aren 't going to check it. It
| needs to be automatic and it needs to be distributed in a way
| that browsers and site owners can be confident that the code
| being run is the code the site owner intended to be run.
| doomrobo wrote:
| Gotcha, yeah I agree. Fwiw, with the imagined code signing
| setup, the pubkey _will_ be committed to in the
| transparency log, without any extra work. The purpose of
| the plugin is to give the browser the ability to parse
| (really fetch, then parse) those extension values into a
| meaningful policy. Anyways I agree, it 'd be best if this
| part were built into the browser too.
| saurik wrote:
| 1) It seems strange that this spec isn't an extension of the
| previous cache manifest mechanism, which was very similar and
| served a very similar purpose: it listed all of the URLs of your
| web app, so they could all be pre-downloaded... it just didn't
| include the hashes, and that could easily have been added.
|
| 2) That the hashes are the primary key and the path is the value
| makes no sense, as it means that files can only have exactly one
| path. I have often ended up with the same file mapped to two
| places in my website for various reasons, such as collisions in
| purpose over time (but the URL is a primary key) or degenerate
| objects. Now, yes: I can navigate avoiding that, but why do I
| have to? The only thing this seems to be buying is the idea that
| the same path can have more than one hash, and even if we really
| want that, it seems like it would make a million times more sense
| to just make the value be an array of hashes, as that will make
| this file a billion times more auditable: "what hashes can this
| path have?" should be more clear than "I did a search of the file
| to check and I realized we had a typo with the same path in two
| places". No one -- including the browser implementing this -- is
| trying to do the inverse operation (map a hash to a path).
|
| 3) That this signs only the content of the file and not the HTTP
| status or any of the headers seems like an inexcusable omission
| and is going to end up resulting in some kind of security flaw
| some day (which isn't an issue for subresource integrity, as
| those cases don't have headers the app might want and only comes
| into play for successful status). We even have another
| specification in play for how and what to sign (which includes
| the ability to lock in only a subset of the headers): Signed HTTP
| Messages. That should be consulted and re-used somehow.
|
| 4) Since they want to be able to allow the site to be hosted in
| more than one place anyway, they really should bite the bullet
| and make the identity of the site be a key, not a hostname, and
| the origin of a site should then become the public key. This
| would let the same site hosted by multiple places share the same
| local browser storage and just act like the exact same site, and
| it would also immediately fix all of the problems with "what if
| someone hacks into my server and just unenrolls me from the
| thing", as if they do that they wouldn't have the signing key
| (which you can keep very very offline) and, when a user hits
| reload, the new site they see would be considered unrelated to
| the one they were previously on. You also get provenance for
| free, and no longer have to worry about how to deal with
| unenrollment: the site just stops serving a manifest and it is
| immediately back to being the normal boring website, and can't
| access any of the content the user gave to the trusted key
| origin.
| doomrobo wrote:
| 1. I didn't know about this [1] actually! It looks like it's
| been unsupported for a few years now. The format looks pretty
| barebones, and we'd still need hashes like you said, as well as
| "wildcard" entries. I reckon the JSON solution might still be
| the better choice, but this is good to have as a reference.
|
| 2. I agree, and this is something we have gone back and forth
| on. The nice thing about hashes as primary keys is you can
| easily represent a single path having many possible values, and
| you can represent "occurs anywhere" hashes by giving them the
| empty string. But the downside like you mention is that a hash
| cannot occur at multiple paths, which is far from ideal. I'll
| make an issue in the Github about this, because I don't think
| it's near settled.
|
| 3. I had read the spec [2] but never made this connection!
| You're right that it's not hard to imagine malleability
| sneaking in via headers and status codes. I'll make an issue
| for this.
|
| 4. I wanted to veer a bit from requiring sites to hold yet more
| cryptographic material than they already do. Yes you can keep
| signing keys "very very offline", but this requires a level of
| practice that I'm not sure most people would achieve. Also you
| run into key rotation annoyances as well. The current route to
| something like you describe is have every site have their own
| transparency log entry (though they can share manifests and
| even asset hosts), and use code signing to link their instance
| to the source of truth.
|
| [1] https://en.wikipedia.org/wiki/Cache_manifest_in_HTML5
|
| [2] https://www.rfc-editor.org/rfc/rfc9421.html
| saurik wrote:
| <3 FWIW, I know Hacker News discussions often go stale after
| a bit and later responses might never be seen, and I don't
| really have time until later tonight to work on this (I used
| up my minutes earlier frantically reading this article to
| leave that other comment), so I thought I'd leave a quick
| comment here saying that I will be doing some further
| explanation in a comment here later tonight into what I
| thought is so interesting with cache manifests and some
| further thoughts viz-a-viz shared origins. (And, if you also
| happen to think any of my commentary is somewhat useful, I'd
| love to have a call or something with you at some point to
| talk about some of your vision for this work: I have a number
| of use cases for this kind of verification, and I think I was
| one of the more serious users of cache manifests back a
| decade ago.)
| vader1 wrote:
| > This is because app stores do a lot of heavy lifting to provide
| security for the app ecosystem. Specifically, they provide
| integrity, ensuring that apps being delivered are not tampered
| with, consistency, ensuring all users get the same app, and
| transparency, ensuring that the record of versions of an app is
| truthful and publicly visible.
|
| The Google Play Store does none of this, lol. All apps created
| since 2021 have to make use of Google Play App Signing, which
| means Google holds the keys used to sign the app. They leverage
| this to include stuff like their Play Integrity in the builds
| that are served. The Android App Bundle format means that
| completely different versions of the app are delivered depending
| on the type of device, locale, etc. There is 0 transparency about
| this for the end-user.
___________________________________________________________________
(page generated 2025-10-16 23:01 UTC)