[HN Gopher] Hardening the Firefox Front End with Content Securit...
___________________________________________________________________
Hardening the Firefox Front End with Content Security Policies
Author : evilpie
Score : 165 points
Date : 2025-04-09 09:34 UTC (13 hours ago)
(HTM) web link (attackanddefense.dev)
(TXT) w3m dump (attackanddefense.dev)
| davidmurdoch wrote:
| Firefox really needs to fix their CSP for extensions before this
| kind of thing.
|
| Here is the 9 year old bug:
| https://bugzilla.mozilla.org/show_bug.cgi?id=1267027
|
| And their extension store does not permit workarounds, even
| though they themselves have confirmed it's a bug.
| Semaphor wrote:
| Having fewer permissions for extensions than one might want
| seems fairly less important to making the browser more
| secure...
| joshuaissac wrote:
| Arguably, it can make it less secure by reducing the user's
| control over what content the browser loads or what scripts
| it executes. For example, users may be using extensions to
| selectively replace harmful content (like intrusive
| JavaScript, tracking) with benign content. It is a balance
| between security for the user and security for the website
| owner.
| gear54rus wrote:
| Exactly. It's been clearly established that web extensions'
| code is more priveleged than a page code, as it should be.
| The amount of people going 'muh sesoority' in this thread
| is baffling.
| pessimizer wrote:
| > It is a balance between security for the user and
| security for the website owner.
|
| Which in the case of browsers should always be decided for
| the user, rather than balanced. The browser is a user
| agent. It is running on the user's hardware.
| pama wrote:
| Wouldn't fixing this bug reduce security?
| shakna wrote:
| If you are using filter scripts, to block specific domains or
| script payloads, that extension can't load on a properly
| secured CSP page. And that page may be using CSP to protect
| throwing up ads... Or malware.
| pama wrote:
| Thanks.
| davidmurdoch wrote:
| No, it's explained more in the issue. An extension is a part
| of the "User Agent". The CSP header in FF is almost seemingly
| arbitrarily applied to extensions.
| pama wrote:
| Thanks!
| gear54rus wrote:
| One of the possible workarounds would be to just remove the
| damn header before it causes any further inconvenience. I think
| they do allow `webRequest` API usage in the store, don't they?
| evilpie wrote:
| Removing security headers like Content-Security-Policy is
| forbidden by the addons.mozilla.org policy.
|
| https://extensionworkshop.com/documentation/publish/add-
| on-p...
| gear54rus wrote:
| I don't think this is being enforced in practice,
| thankfully.
| davidmurdoch wrote:
| It is. It happened to us a few weeks ago.
| gear54rus wrote:
| That's crazy. Did it happen to a public extension or an
| unlisted one?
| davidmurdoch wrote:
| Public, with about half a million installations.
|
| I think it was noticed only because this version had a
| major bug that broke a bunch of websites.
| davidmurdoch wrote:
| We modified the CSP to inject a per user generated nonce that
| exempts it script from the policy.
|
| They said this was not allowed and removed it from the
| extension store.
| evilpie wrote:
| While this is definitely annoying, most of the time this can be
| worked around by the extension without workarounds that
| themself weaken security.
|
| For example I helped uBlock Origin out in 2022 when they ran
| into this: https://github.com/uBlockOrigin/uBlock-
| issues/issues/235#iss...
| KwanEsq wrote:
| And it's worth noting that since your comment later in that
| thread about sandbox being an issue, that's been fixed too as
| of Firefox 128:
| https://bugzilla.mozilla.org/show_bug.cgi?id=1411641
| davidmurdoch wrote:
| Thanks for this! I'll look into implementing it soon.
| theandrewbailey wrote:
| CSP is really great at plugging these kinds of security holes,
| but it flummoxes me that most developers and designers don't take
| them seriously enough to implement properly (styles must only be
| set though <link>, and JS likewise exists only in external
| files). Doing any styling or scripting inline should be frowned
| upon as hard as table-based layouts.
| pocketarc wrote:
| > should be frowned upon as hard as table-based layouts
|
| I absolutely agree with you. I've been very very keen on CSP
| for a long time, it feels SO good to know that that vector for
| exploiting vulnerabilities is plugged.
|
| One thing that's very noticeable: It seems to block/break -a
| lot- of web extensions. Basically every error I see in Sentry
| is of the form of "X.js blocked" or "random script eval
| blocked", stuff that's all extension-related.
| chrismorgan wrote:
| > _Doing any styling or scripting inline should be frowned upon
| as hard as table-based layouts._
|
| I strongly disagree: inlining your entire CSS and JS is
| _absurdly_ good for performance, up to a surprisingly large
| size. If you have less than 100KB of JS and CSS (which almost
| every content site should be able to, most trivially, and
| almost all should aim to), there's simply no question about it,
| I would recommend deploying with _only_ inline styles and
| scripts. The threshold where it becomes more subjective is, for
| most target audiences, possibly over half a megabyte by now.
|
| Seriously, it's _ridiculous_ just how good inlining everything
| is for performance, whether for first or subsequent page load;
| especially when you have hundreds of milliseconds of latency to
| the server, but even when you're nearby. Local caches can be
| bafflingly slow, and letting the browser just execute it all in
| one go without even needing to look for a file has huge
| benefits.
|
| It's also a _lot_ more robust. Fetching external resources is
| much more fragile than people tend to imagine.
| allan_s wrote:
| note that for inline style/script, as long as you're not
| using `style=''` or `onclick=''` , you can use `nonce=` to
| have a hash and to my understanding, newly added inline
| script will not be tolerated, allowing to have the best of
| both world
| LegionMammal978 wrote:
| It does seem like CSP nonces do not play well with caching
| (since they must have a different value on each page load),
| which would make them a detriment to performance.
| SahAssar wrote:
| You can also include a hash of the contents in the CSP,
| which plays well with caching.
| LegionMammal978 wrote:
| True, a hash works as a good alternative. (Unless you're
| doing super weird stuff like generating inline scripts at
| runtime.)
| eru wrote:
| I think that's a limitation of our implementations. In
| principle, it's just bytes that we shoving down the pipe to
| the browser, so it shouldn't matter for performance whether
| those bytes are 'inline' or in 'external resources'.
|
| In principle, you could imagine the server packing all the
| external resources that the browser will definitely ask for
| together, and just sending them together with the original
| website. But I'm not sure how much re-engineering that would
| be.
| erikerikson wrote:
| In principle there's no difference between principle and
| practice.
| eru wrote:
| Simple models are still useful: understanding exactly how
| and why they fail is instructive. There's a reason
| spherical cows in a vacuum come up again and again.
| Perseids wrote:
| This feature actually existed (see
| https://en.wikipedia.org/wiki/HTTP/2_Server_Push ) but was
| deemed a failure unfortunately (see
| https://developer.chrome.com/blog/removing-push )
| eru wrote:
| Thanks for the links! Yes, my comment was based of a
| vague recollection of this kind of thing.
|
| I'll read up on the '103 early hints' and 'preload' and
| 'preconnect' which might be close in enough practice.
| theandrewbailey wrote:
| It's called Content _Security_ Policy, not Content
| _Performance_ Policy. My thoughts:
|
| 1. Inlining everything burns bandwidth, even if it's 100KB
| each. (I hope your cloud hosting bills are small.) External
| resources can be cached across multiple pageloads.
|
| 2. Best practice is to load CSS files as early as possible in
| the header, and load (and defer) all scripts at the end of
| the page. The browser can request the CSS before it finishes
| loading the page. If you're inlining scripts, you can't defer
| them.
|
| 3. If you're using HTTP/2+ (it's 2025, why aren't you?[0]),
| the connection stays open long enough for the browser to
| parse the DOM to request external resources, cutting down on
| RTT. If you have only one script and CSS, and they're both
| loaded from the same server as the HTML, the hit is small.
|
| 4. As allan_s mentioned, you can use nonce values, but those
| feel like a workaround to me, and the values should change on
| each page load.
|
| > Local caches can be bafflingly slow, and letting the
| browser just execute it all in one go without even needing to
| look for a file has huge benefits.
|
| Source? I'd really like to know how and when slow caches can
| happen, and possibly how to prevent them.
|
| [0] Use something like nginx, HAProxy, or Cloudflare in front
| of your server if needed.
| bgirard wrote:
| > Source? I'd really like to know how and when slow caches
| can happen.
|
| I don't have a source I can link to or share. But cache
| outliers are a real thing. If you aggregate Resource Timing
| results, you'll find some surprising outliers in that
| dataset where transferSize=0 (aka cached load on Chrome).
| You'll have users with a slow/contended disk where as they
| might have a fast link, but you'll also have the reverse
| where you'll have users with a fast cache and a slow
| network link (high latency, low bandwidth or both).
|
| There's no universal answer here and I feel like the above
| poster tries to oversimplify a complex problem into one-
| size-fits-all answers. You'll have different users making
| up your distribution and you'll have to decide how you
| weight optimizations. This could very much depend on your
| product, the expectations and if your user are power users
| running a complex SaaS frontend, or a news site supporting
| a range of mobile devices.
|
| A few years ago I traced and notice that Chrome has a
| pseudo O(n^2) behavior when pulling a bunch of sequential
| resources from its cache. I reported it but I'm not sure if
| it got fixed.
| theandrewbailey wrote:
| > If you aggregate Resource Timing results, you'll find
| some surprising outliers in that dataset where
| transferSize=0 (aka cached load on Chrome).
|
| I've been digging into the JS resource timing API. You've
| suggested a fascinating avenue for me to explore!
| bgirard wrote:
| > If you have less than 100KB of JS and CSS (which almost
| every content site should be able to, most trivially, and
| almost all should aim to), there's simply no question about
| it
|
| Do you have data to back this up? What are you basing this
| statement on?
|
| My intuition agrees with you for the reasons you state but
| when I tested this in production, my workplace found the
| breakeven point to be at around 1KB surprisingly.
| Unfortunately we never shared the experiment and data
| publicly.
| athanagor2 wrote:
| Honest question: I don't understand how forbidding inline
| scripts and style improves security. Also it would be a serious
| inconvenience to the way we distribute some of our software
| right now lol
| theandrewbailey wrote:
| CSP tells the browser where scripts and styles can come from
| (not just inline, but origins/domains, too). Let's pretend
| that an attacker can inject something into a page directly
| (like a SQL injection, but HTML). That script can do just
| about anything, like steal data from any form on the page,
| like login, address, or payments, or substitute your elements
| for theirs. If inline resources are forbidden, the damage can
| be limited or stopped.
|
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP
| magicalhippo wrote:
| Still recall the classic forum exploits of including
| Javascript in your signature or similar, before such
| software started escaping input.
| bryanrasmussen wrote:
| sounds weird to me too, although I guess there could be a
| script that was not allowed to do CORS that then instead
| created an inline script and did its CORS stuff in that
| script - about the only way I can think of it being bad.
| diggan wrote:
| > although I guess there could be a script that was not
| allowed to do CORS that then instead created an inline
| script and did its CORS stuff in that script
|
| Wouldn't even matter, as it's the origin of wherever it
| ends up being executed that matters, not where the code was
| loaded from. So JS code loaded from cdn.jquery.com on
| mywebsite.com would have the origin mywebsite.com, even if
| loaded with a typical <script> tag.
|
| In short, CORS applies to network requests made by scripts,
| not to the scripts themselves
| bryanrasmussen wrote:
| ah yeah, sorry wasn't thinking clearly.
| flir wrote:
| Cross-Site Scripting. If a user injects a malicious script
| into the page, it doesn't get run.
| allan_s wrote:
| forbidding inline script protect you from
|
| ``` <h3> hello $user </h3> ```
|
| with $user being equal to `<script>/* sending your session
| cookie out, or the value of the tag #credit-card etc.
| */</script>`
|
| you will be surprised how many template library that
| supposedly escape things for you are actually vulnerable to
| this , so the "React escape for me" is not something you
| should 100% rely on. In a company I was working for the
| common vulnerably found was
|
| `<h3> {{ 'hello dear <strong>$user</strong>' | translate |
| unsafe }}` with unsafe deactivating the auto-escape because
| people wanted the feature to be released, and thinking of a
| way to translate the string intermixed with html was too
| time-consuming
|
| for inline style, it may hide elements that may let you input
| sensitive value in the wrong field , load background image
| (that will 'ping' a recipient host)
|
| with CSP activated, the vulnerability may exists, but the
| javascript/style will not be executed/applied so it's a
| safety net to cover the 0.01 case of "somebody has found an
| exploit in
| diggan wrote:
| > forbidding inline script protect you from
|
| What you use as an example has nothing to do with
| inline/"external" scripts at all, but everything to do with
| setting DOM contents vs text content. Most popular
| frameworks/libraries handle that as securely by default as
| one could (including React) and only when you use specific
| ways (like React's dangerouslySetInnerHTML or whatever it
| is called today) are you actually opening yourself up to a
| hole like that.
|
| If you cannot rely on the escaping of whatever templating
| engine/library you're using, you're using someone's toy
| templating library and probably should switch to a proper
| one that you can trust, ideally after actually reviewing it
| lives up to whatever expectation you have.
|
| > `<h3> {{ 'hello dear <strong>$user</strong>' | translate
| | unsafe }}`
|
| This would have been the exact same hole regardless if it
| was put there/read by external/inline JavaScript.
|
| I do agree with your last part that CSP does help slightly
| with "defense in depth", for when you do end up with
| vulnerabilities.
| myko wrote:
| I find not being able to use inline styles extremely
| frustrating
| sebazzz wrote:
| > it flummoxes me that most developers and designers don't take
| them seriously enough to implement properly (styles must only
| be set though <link>, and JS likewise exists only in external
| files). Doing any styling or scripting inline should be frowned
| upon as hard as table-based layouts.
|
| At our place we do abide by those rules, but we also use 3rd
| party components like Telerik/Kendo which require both unsafe-
| inline for scripting and styling. Sometimes you have no choice
| laxing your security policy.
| midtake wrote:
| Why? If you're the content owner, you should be able to. If you
| factor out inline code, you will likely just trust your own
| other domain. When everything is a cdn this can lead to less
| security not more.
|
| Do you mean people should be banned from inlining Google
| Analytics or Meta Pixel or Index Now or whatever, which makes a
| bunch of XHRs to who knows where? Absolutely!
|
| But nerfing your own page performance just to make everything
| CSP-compliant is a fool's errand.
| myfonj wrote:
| I am surprised there is no policy that would allow inline event
| handlers set in the initial payload (or stuff emitted by
| document.write), but neuter any done after initial render by
| `....setAttribute('on...', ...)`.
|
| That would keep "static form" helpers still functional, but
| disable (malicious) runtime templating.
| SebFender wrote:
| CSP is a soothing cream but is most usually easily bypassed by
| other simple attacks relying on poor DOM management and security
| - to this day my team has never found so many web vulnerabilities
| just going into the DOM...
| sixaddyffe2481 wrote:
| Their blog has a lot of posts on trying to attack Firefox. If
| it's so simple, why are you not in the bug bounty hall of fame?
| :)
| foobar9898989 wrote:
| Mozilla's finally realizing what my paranoid uncle has been
| shouting for years: "They're coming for your browser UI!"Jokes
| aside, it's pretty cool seeing them implement CSP in the front-
| end. Kind of like putting a security guard at the entrance of a
| bank that already has 50 guards inside. But hey, that 51st guard
| might be the one who catches the bad guy!The separation between
| privileged and unprivileged processes reminds me of my
| relationship with coffee - I know I shouldn't let it access my
| system too often, but somehow it always finds a way in.What's
| actually impressive is how Firefox keeps evolving despite being
| around forever (in internet years). Most of us would have given
| up and said "eh, good enough" years ago. Next thing you know
| they'll be securing the about:config page with a pop quiz on
| quantum physics.
| yanis_t wrote:
| CSP is great in mitigating a whole bunch of security concerns,
| and it also forces some good practices (e.g. not using inline
| scripts).
|
| I recently implemented a couple of tools to generate[1] and
| validate[2] a CSP. Would be glad if anybody tries it.
|
| [1] https://www.csphero.com/csp-builder [2]
| https://www.csphero.com/csp-validator
| bbarnett wrote:
| Do this, and then use Firefox's profiles to have weaker instances
| without these configs.
|
| Why? Some sites implement then break this, sadly.
|
| I have extremely locked down instances for banks and so on. On
| Linux I have an icon which lets me easily launch those extra
| profiles.
|
| I also use user.js, which means I can just drop in changes, and
| write comments for each config line, and keep it version
| controlled too. Great for cloning to other devices too.
| lol768 wrote:
| This is an entire class of vulnerabilities that would've never
| been possible with XUL, is that correct?
|
| I appreciate they had to move for other reasons but I also really
| don't like the idea that the DevTools and browser chrome itself
| now has all of the same security issues/considerations as
| anything else "web" does. It was bad with Electron (XSS suddenly
| becoming an RCE) and makes me pretty nervous here too :(
| emiliocobos wrote:
| Xul would've had the same issues.
| WorldMaker wrote:
| XUL would have had worse issues because it could make
| arbitrary XPCOM calls to all sorts of native components and
| nearly the full gamut of native component issues written
| mostly in C/C++.
|
| XUL was in many ways always a ticking time bomb.
| sebazzz wrote:
| It still surprises me parts of Firefox still use XUL.
| CamouflagedKiwi wrote:
| I can't help but wonder if this HTML-based setup is actually more
| trouble than it's worth. It seems there's a very complex
| ecosystem in there that is hard to reason about in this way, and
| it's a top-level requirement for a browser to sandbox the various
| bits of code being executed from a web page.
|
| Obviously hard to say what those tradeoffs are worth, but I'd be
| a bit nervous about it. The work covered by this post is a good
| thing, of course!
___________________________________________________________________
(page generated 2025-04-09 23:01 UTC)