Open ghost opened 5 years ago
I should add that I was able to resolve some of the non-eval issues by using sha256 hashes in script-src (not the ones generated here, but only the ones Google Chrome shows when an element is blocked). The eval issue remains, however, and further inline-styles are required once you get past the initially blocked evals / inlines. It would appear that some of the initial issues were caused by the Netlify Identity widget, but once those are out of the way, further issues crop up when trying to load /admin/
edit:
Because I can't get very clear error messages from Firefox or Chrome, this issue is very hard to diagnose. It seems as though the issues start with the Netlify identity widget and then continue when trying to load the CMS. The identity widget throws an script-src eval-violation in Firefox, but not in Chrome. In Chrome, the identity widget throws a style-src unsafe-inline violation, which does not show in Firefox.
In Firefox, this is where the buck stops.
In Chrome, I can advance to the /admin/ URL, where the CMS itself will provide the following error EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'sha256-Y1ZIa2N59dlCRGtBP67/dCOpq2eDNPEO+vGJU0pjvEw=' 'sha256-jILZY2UBo/ux6K6qGHntQonoJYNQZfxdLrszRmDpc/o=' 'sha256-v40OvYf1mF3VQM75141gVEb6xZk97Wd9tDERTFg3N38=' 'sha256-tphCtOfPA2HxpbQIjyGzEOxfajrm+crnavJGIhdlT7k=' https://www.google.com https://www.googletagmanager.com https://www.gstatic.com https://identity.netlify.com https://cdn.jsdelivr.net https://www.google-analytics.com".
Chrome also throws multiple inline-style errors and the eval error mentioned before. I believe that without unsafe-inline and unsafe-eval it won't be possible to run either the identity widget or the CMS.
For the style-src issues I think it's down to react components' usage of inline-styles. For eval, you have to look further as it's not just eval itself, but it's also related functions.
I found a discussion regarding react from 2016 and one from 2018 regarding this.
In a recent e-mail conversation, Netlify have confirmed that they have a feature request to fix this, but are not actively looking into it, so for now I shall give up. I'll leave this information here for someone to revisit one day.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I tried to create my own local version of the script. It worked until I wanted to add cloudinary with triggers the same issues.
Is there a way around this ?
I second the question, is there any way around having to add unsafe-*
stuff in the CSP?
Hi guys... any chance to ADMIN works without unsafe?
I think this might be related to one of the dependencies we're using https://github.com/netlify/netlify-cms/issues/4367#issuecomment-699884163
Thanks for answer! Do you think we can use CMS without that dependency?
No sure actually, it requires some research. We'll be happy to get a contribution for it if someone does the research on it.
It looks like the issue might be caused by AJV creating a function at runtime to compile JSON schema into executable code. It's described here https://github.com/ajv-validator/ajv/issues/406
One possible solution is to use standalone mode to compile schemas to code at build time.
After a bit more digging, we might have a way to eliminate this problem by compiling schemas during build time.
On https://github.com/netlify/netlify-cms/blob/dbf2920254fb3682e12463a6df8ded4b94b55be0/packages/netlify-cms-core/src/constants/configSchema.js#L364, we'd need to use compiled schema.
To compile schema, we can use AJV Standalone to create executable code that we store as a JavaScript module. There is a Webpack loader that can be used to take care of some of this, but this loader is using ajv-pack
which is deprecated.
It looks like the game plan here would be,
getConfigSchema
to read value from a module import@erezrokah After doing some more digging, coding, and research, we're really close on this, but there is one final stumble that we're hitting.
We were able to completely extract the schema, and build the validateConfig
function at build time. This works for our site, but there are cases where it will not work for everyone. Specifically, the schema itself can change dynamically based on widget schemas that are added via registerWidget()
https://github.com/netlify/netlify-cms/blob/2877f7983e9b5f4ff0cb2cdaaf6549675af68913/packages/netlify-cms-core/src/constants/configSchema.js#L75
Unfortunately, registering widgets happens in the browser, and so it cannot be known at build-time what the complete schema will be including widget extensions.
It seems to me that the only way this can work correctly is to deprecate registration of pieces of schema along with widgets and instead make the schema for user-supplied widgets sufficiently broad to type-check against any widget config. That's a breaking change and would mean slightly less type-safety for config.yaml, but it also means that it can be deployed with a secure content policy because the entire schema would be known at build time.
We're investing so much effort in this because we really like Netlify CMS, but unsafe-eval
is unfortunately a deal breaker for our security team. We'd love to find a way forward here, but not really sure what to do at this point.
Thanks for the additional information @cowboyd and effort you're putting into this. Is there a way to put this change behind an option? Then users should be able to opt-in to the breaking change.
We could always generate the static schema during build, the generate the dynamic schema by default, or let users opt out of the last part if they'd like.
I also added this to https://github.com/netlify/netlify-cms/issues/5652
A compromise option that might be viable is to only do dynamic validation if we detect that we need to because there are widgets registered with custom schemas. Widgets registered that do not have any additional schema would not require any dynamic validation.
// defined at build time
import { staticValidateConfig } from './config.schema.json';
export function validateConfig(config) {
if (Object.values(getWidgetSchemas().find(schema => !!Object.keys(schema)))) {
// there are custom widget schemas, we can't use the static validation
// this is the current `validateConfig` function.
// this will trigger a CSP error unless `unsafe-eval` is set.
return dynamicValidateConfig(config)
} else {
return staticValidateConfig(config);
}
}
It's a bit of a strange implicit opt-out, but it does have the advantage of being backwards compatible.
I like that idea @cowboyd 💡 !
@erezrokah I'm having a look at implementing @cowboyd 's suggestion.
There are a couple of places in the codebase where registerWidget
is called.
One is in netlify-cms-app
where a number of widgets are registered, and in netlify-cms-core
where an UnknownControl is registered.
I wonder if you could help me understand if:
UnknownControl
is always registered as a default editor control.netlify-cms-app
to determine if the schema is a dynamic schema or not?Thanks for your input
Hi 👋
The UnknownControl is always registered as a default editor control.
UnknownControl
is always registered, and it's in the "core" since it renders as a fallback when the CMS doesn't find a widget (e.g. someone made a typo in the configuration).
See https://github.com/netlify/netlify-cms/blob/dd8f0050c4e2d646e851da28056456c4b76a5738/packages/netlify-cms-core/src/lib/registry.js#L143
We can assume it will never have a schema.
Do we need to account for the widgets in netlify-cms-app to determine if the schema is a dynamic schema or not?
I think the schemas for those could be evaluated at build time, as netlify-cms-app
should not reference widgets outside this monorepo.
@erezrokah I created a PR that includes changes implemented by @dagda1 and has all of the tests passing. There is a blocking the PR that I'll describe in a comment.
With help from @dagda1, I created an example repo that has CSP with Netlify. I created a version of Netlify build that works with CSP. You can find it here https://github.com/taras/create-react-app-csp-strict-example
We still need https://github.com/iarna/iarna-toml/issues/45 to fully eliminate eval.
Any updates here?
I have managed to solve above issue using exclude option and allowed Unsafe Eval.
Describe the bug I have been using Netlify CMS for sites without a content security policy. I am now trying to increase the security of my sites by adding this. The CSP requires defining what sources are allowed for scripts, styles, frames, objects, etc. The CSP also blocks things like eval in any JS execution and also generally inline-scripts or styles. While it is possible to globally allow these things by setting unsafe-inline or unsafe-eval as permitted, this is not recommended, as it defeats the purpose of the CSP.
Here is the CSP I am applying to one of my sites via special file that Netlify recognises on deploy:
As you can see, I have already attempted to somehow make anything coming from Netlify permissible, but Firefox states (among other things):
Content Security Policy: The page’s settings blocked the loading of a resource at eval (“script-src”) Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”)
To Reproduce Deploy any site to Netlify with a Content Security Policy which does not permit unsafe-eval or unsafe-inline
Expected behavior Once Netlify has been added as permitted source for scripts, styles, etc. for this to allow loading the CMS. This may require a way to load the Netlify CMS without an inline-script tag, but I am not seeing this issue with other scripts, like google tag manager. Eval may be a bigger issue, as that would require a change to the CMS' code and eval maybe unavoidable.
Applicable Versions: Tested on:
CMS configuration not relevant for this, presumably