Content Security Policy (CSP)

LiteCart Fan
Van France
Lid sinds jan. 2021

Hi there

is it possible to get rid off all inline scripts to be able to set up an effective content security policy and get the best secure CMS ever made or what I am asking is an impossible mission ?
Or maybe could it be possible to automatically set up a random nonce for all of them included at the core of litecart and all plugins in the future ?
I meant to say this could be safer for commercial things, both customer and seller sides.
Regards

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

Sure, lib_document is already collecting all inline scripting. So instead of outputting it on the page you could store it in the session and fetch it with another php process. Or write it to some temporary storage.

https://github.com/litecart/litecart/blob/dev/public_html/includes/library/lib_document.inc.php#L239-L248

I was thinking of adding a nonce to version 3.0. I had a concept ready but wasn't sure if I was raising the bar too much for the users. I appreciate feedback on this conversation.

LiteCart Fan
Van France
Lid sinds jan. 2021

Throwing out some ideas because technically I'm just good for that.
Got an A+ on MDN but not deserving 5 stars for it because my main website is not having js at all, only html5,css, that said..
I'm interested on this part for my spouse's coming soon website as she's selling some stuff.

I understood it could be possible to link this lib_document to another included php function.
Maybe for user's simplicity one dedicated plugin (on, off) could fetch needed informations and with a starting point looks like default-src 'none' (hardenned for A+) or default-src 'self' (not A+, more likely A) and let them possibilities to write further directives on it to an htaccess file for example.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

This is the policy I had in mind, but nonce may prevent cache.

header('Content-Security-Policy: '. implode(';', [
  "frame-ancestors 'self'",
  "script-src 'nonce-". functions::escape_attr(self::$nonce) ."' 'strict-dynamic'",
  "style-src 'self'",
  "img-src 'self'",
  "base-uri 'self'",
  "form-action 'self'",
]));

To use nonce for all inline and external resources.

LiteCart Fan
Van France
Lid sinds jan. 2021

interesting, that's concrete.
exclude nonce from being in cache is possible ?

LiteCart Fan
Van France
Lid sinds jan. 2021

don't like much to share this kind of link , apologize my weakness but as an example it allows not to cache specific content and/or some dynamic content.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

No I don't think it's possible to serve cached content using nonce. We need cache to do it's part.

This leads me to believe SHA256 is better but will increase CPU usage. Which leads me back to square one wondering if there is a way that doesn't have disadvantages?

LiteCart Fan
Van France
Lid sinds jan. 2021

There is only one advantage, security.
another thought, if nonce lifespan is the same as cache lifespan or logged-in cache lifespan would it lead to some troubles ?

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

There is no lifespan for nonce, hence it's name "number used once". It's a one time used string. I'm gonna need to do some field testing with nonce vs sha256 to see how browsers react to caching the resources.

LiteCart Fan
Van France
Lid sinds jan. 2021

all right then, it looks simple on the paper ... wish you can do about it

Developer
Van United Kingdom
Lid sinds jan. 2025

I'm working on this at the moment for my own site. Is there a best way to implement it?

I'm currently writing a VMod and making changes to a clone of the template (that has other changes in). But I could fork the repo and make PRs if that helps.

I hit the nonce and caching problem, but have a really simple workaround. You just need to do a str_replace before and after caching.

I use mod_csp and Apache-level headers, so I've even been considering how it could work for people who don't have that installed.

LiteCart Fan
Van France
Lid sinds jan. 2021

Hello there, your reply rings like a good new.
I'm following this thread with interest.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

The easiest way to add some security to this thingy is adding hash checksums.

  echo '<script defer integrity="sha256-'. base64_encode(hash_file('sha256', $file, true)) .'" src="'. document::href_rlink($file) .'"></script>';
Developer
Van United Kingdom
Lid sinds jan. 2025

I've just been using nonces for now on the basis that the scripts may change and I don't want to keep track of the checksum or keep external copies of inline scripts and styles updated. A hash could be generated and cached on the fly, but I'm not sure it adds much over a nonce.

  • Nonce: File changes, nonce says "trust it", visitor runs whatever was served
  • Integrity checksum: File changes, checksum is recalculated, checksum says "trust it", visitor runs whatever was served

My current approach puts a nonce into all of the templates and then the "collect the scripts" and "collect the styles" steps look for the nonce as well (rather than just the plain tag). Unless I'm missing something, I think that's about as secure as we can get without hard-coding the checksums and keeping them up-to-date.

  • If someone finds a way to inject a script tag via a variable then it won't have a nonce, it won't get collected, so it'll get served up wherever it is in the code unchanged, and then it'll fail the CSP.
  • If someone finds a way to inject values into variables so that a nonced inline script now has bad code in it then that's bad and we'd be better off with external scripts. But the quick review that I did of inline scripts didn't find any that looked dangerous. It would have to be an admin compromise with a bad product name or something.
  • If someone finds a way to modify the template and get the nonce in there as well... well, it's game over at that point anyway. If they can edit a template file then they can basically put any code that they want in there!
LiteCart Fan
Van France
Lid sinds jan. 2021

What is the way for a person with bad intentions not to find this ways ... a strong and full CSP starting with default-src 'none'; ...
Most of the time on CMSs the only things I couldn't set up on CSP are inline scripts/styles.
Ended up to build manually one template without scripts at all, but then .. this is not friendly coding ..

If there is someone like you can build a kind of automatic set up for that with nonces, god will bless you and me too.

Saying that many broke their teeth trying to, me ve virst

Developer
Van United Kingdom
Lid sinds jan. 2025

It's not perfect, but this VMod is what I've got so far. My CSP is basically style-src: 'self' https://cdnjs.cloudflare.com/ajax/libs/tinymce/ 'nonce-%{CSP_NONCE}e (where %{CSP_NONCE}e is an Apache environment variable from mod_cspnonce) and script-src: 'self' https://cdnjs.cloudflare.com/ajax/libs/tinymce/ 'nonce-%{CSP_NONCE}e' 'strict-dynamic'. I've got some extra domains for Google fonts etc, which is why I think it might be better to do the policy at the server level if possible. Otherwise we need to start adding settings in the admin control panel.

As I said, I'm happy to do this in a fork and make a PR if that's the best option. The VMod lets me do it and distribute it without getting too closely coupled to the code, but I think there might be bits that won't work without changes to JavaScript files. If that's necessary then a PR would be best, if Tim will accept it, to avoid me distributing parallel copies of scripts and keeping them up-to-date.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

I want the best solution out of every aspect. Simple, minimum maintenance, dependency free. integrity="sha-256-{hash}" lets us sign the content with a checksum. Thoughts on using integrity hash checksum?

Developer
Van United Kingdom
Lid sinds jan. 2025

I don't see the benefits of a checksum over using a nonce except for external files.

If it's part of LiteCart then changes are under our control and either we trust the script or we shouldn't be serving it. Whether it has a nonce or a checksum, it has the same amount of trust. The only way the checksum stops being valid is if someone replaces the file on the server (or intercepts HTTPS and injects a replacement file), and the moment that happens then they can just replace other content including the checksum.

The place where the checksum helps is with CloudFlare and other third-parties to cover the "what if {third-party} ends up serving a different file under the same name?" situation.

I'll see what I can put together over the weekend in a branch rather than a VMod, and try to cover server-based CSP and additional third-party content (e.g. Google Fonts)

LiteCart Fan
Van France
Lid sinds jan. 2021

Many thanks idboard, you are very kind.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

If it's part of LiteCart then changes are under our control and either we trust the script or we shouldn't be serving it.

Even if we trust our own scripts, an integrity hash would guarantee no middle man attacks or file corruption.

Developer
Van United Kingdom
Lid sinds jan. 2025

Potentially. But HTTPS should prevent on-path attacks. And if they can intercept and replace the script, what's stopping them replacing the hash as well?

While it will prevent browsers executing scripts that corrupted between reading and receiving, I'd expect that a lot of scripts would fail to run anyway if they corrupted. It wouldn't catch on-disk corruption because we'd just hash the corrupt data. Any read corruption could hit both the hash and the main read (or the hash could be wrong and the read could be right - if it's happening then you need to fix the server issues rather than worrying about CSP!). And HTTPS HMAC should reject any packets that corrupt in transit.

There's probably a slim situation that it'll protect against, but I think we're getting to tiny probabilities for moderate overhead.

tim
Founder
Van Sweden
Lid sinds mei 2013
tim

Very good points, all of them.

LiteCart Fan
Van France
Lid sinds jan. 2021

Many litecart users may not have a full access to server side (eg:free hosting).
htaccess file suggested ?

Developer
Van United Kingdom
Lid sinds jan. 2025

Yeah, some users will be on shared hosting (I wouldn't want to run anything on free hosting these days, especially not professional/commerce stuff!) so they might not be able to add mod_cspnonce. But they can set almost all other config in htaccess files.

I'll look at what the options are to make sure people aren't prevented from using it. But I'd also rather have complete control at the server level instead of trusting the PHP script to inject the right headers. It's just another layer of security (like write-protecting files so that PHP can't rewrite them, rather than relying on "PHP shouldn't be rewriting them").

LiteCart Fan
Van France
Lid sinds jan. 2021

Agreeing to put conditions of use so there is no misunderstood about it.
Should I guess this will be an option to add or not to litecart ? For those who can and those who cannot ?
I'm just showing a picture to say litecart is free but not free in that case, not because of litecart but because this mod needs imperatively to have a non-free hosting provider with full server access and control to be effective and efficient.
In the meantime there are some for a few bucks per month ...

Developer
Van United Kingdom
Lid sinds jan. 2025

CSP is just a header, and PHP can add headers (as per Tim's earlier post). So it can definitely be made compatible with free and shared hosting. It's just that my personal security preference is that CSP is done at the server level to give the additional layer of separation.

LiteCart Fan
Van France
Lid sinds jan. 2021

I was confused and you made it clear.

Developer
Van United Kingdom
Lid sinds jan. 2025

Initial changes on a WIP. Not tested yet, but based on my VMod that I was testing.

https://github.com/litecart/litecart/compare/dev...IBBoard:litecart:IBBoard/content-security-policy

Still lots of style="..." attributes to sort out. And some settings to add (e.g. "let server set header" and "report only mode"), as well as adding the header for sites that don't have mod_cspnonce installed. I want to double-check the scripts as well because I just added nonces to all of them without checking what they do.

Developer
Van United Kingdom
Lid sinds jan. 2025

Hey did you know lib_document extracts style and js on pages, and group them in a new element?
https://github.com/litecart/litecart/blob/dev/public_html/includes/library/lib_document.inc.php#L173-L206

Yeah, I make use of that as part of the "make sure we're grabbing authorised tags". It's also a big part of working round style="…" attributes.

In 3.0 there will be a document::load_style($url) and document::load_script($url) to simplify implementation.

One of the things that made CSP annoying in Wordpress was the plugins that didn't use the functions for adding scripts/styles. If LiteCart is going to gain both the functions and CSP at the same time then that would make it a lot easier to enforce "use these functions or else things may break".

I'm happy to look at the 3.0 code. If it's in a reasonable state then there's not much point in me migrating a site to 2.x only to have to migrate to 3.x a little while later.

LiteCart Fan
Van France
Lid sinds jan. 2021

I think litecart v3.0 will have some major changements,
not guessing when it will be released but guessing we'll have to wait for ...

Developer
Van United Kingdom
Lid sinds jan. 2025

Tim declined a pull request to improve the Unicode handling in LiteCart (including most emoji) with a message saying "This is already implemented in 3.0. Otherwise I would happily like to accept this commit. I'm working hard to finalize many things in 3.0 so it can be released". So I'm assuming that it's not a long way off. At the very least, it sounds like 2.x won't get any more significant updates.

But yes, as it's v3 then presumably there will be incompatible API changes.

Developer
Van United Kingdom
Lid sinds jan. 2025

Given the uncertainty over when Litecart 3.0 is back and whether it's worth doing PRs on the 2.x branch, I'm going to go back to trying to implement this as a VMod. Starting by backporting some of my improved approaches from the branch to the VMod.

LiteCart Fan
Van France
Lid sinds jan. 2021

Oh well, I'm looking forward and I'll try to try to give it a try.

Developer
Van United Kingdom
Lid sinds jan. 2025

Here's a work-in-progress VMod. I think I've fixed everything that's user-side. Unlike the earlier version, this one is now very specifically altering each situation, as well as handling style="…" attributes. I'm now working on the admin control panel.

Note: There's a custom app.js but it looks like it's only needed because of two setTimeout() calls that pass the function name as a string. I'll put in a PR so that Tim can avoid that and I can drop the custom file.

Developer
Van United Kingdom
Lid sinds jan. 2025

I've got a lot of the admin control panel fixed now. I think the biggest problem is going to be the WYSIWYG editor. It uses inline styles for some things and the dev's response to a previous request was basically "nope, don't care about security - do it yourself" with a wave in the general direction of the documentation.

I think it should be possible to make it compatible if I sacrifice the full RGB colour options and just limit it to the built-in palette. If you want more colours and you're adding a CSP vmod then you probably know how to use "source code" mode and add a properly defined class 😁

LiteCart Fan
Van France
Lid sinds jan. 2021

I guess many started to create their things with inline styles/scripts everywhere without thinking at all about CSP, just have to test at MDN any website you would like to see the poor security results on the web.
Still looking forward, I'm already impressed by your work anyway !

U
Deze website maakt geen gebruik van cookies en geen trackingtechnologie van derden . Wij denken dat we het beter kunnen dan anderen en hechten veel waarde aan uw privacy.