Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nova requires CSP unsafe-eval permission #1933

Closed
Synchro opened this issue Sep 13, 2019 · 9 comments
Closed

Nova requires CSP unsafe-eval permission #1933

Synchro opened this issue Sep 13, 2019 · 9 comments
Labels
implemented Feature Request implemented
Milestone

Comments

@Synchro
Copy link

Synchro commented Sep 13, 2019

  • Laravel Version: 5.8.33
  • Nova Version: 2.3.0
  • PHP Version: 7.3.9

Description

This is a deployment issue caused by overall code structure, rather than any specific bit of code.

If you have a very strict CSP policy like this:

Content-Security-Policy: "default-src 'self' https: ; script-src 'self' ...

Nova will load its login page, but shows a blank grey page after login, and throws these two errors:

[Error] TypeError: undefined is not an object (evaluating 'h.app.$loading.start')
(anonymous function) — app.js:1:37137
(anonymous function) — vendor.js:1:1758947
Gt — vendor.js:1:1758388
promiseReactionJob

	It (vendor.js:1:1758278)
	jt (vendor.js:1:1758191)
	Yt (vendor.js:1:1757843)
	(anonymous function) (vendor.js:1:1758962)
	Gt (vendor.js:1:1758388)
	promiseReactionJob
[Error] Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'h.app.$loading.finish')
	dispatchException (app.js:1:637192)
	(anonymous function) (app.js:1:639360)
	o (app.js:1:795247)
	(anonymous function) (app.js:1:795344)
	promiseReactionJob

The error can be avoided by allowing unsafe-eval in script-src, however, allowing that along with unsafe-inline means you're losing all the XSS defences that CSP provides.

I know that this isn't a simple thing to work around because removing unsafe-inline requires moving all JS out to external files, and unsafe-eval can be tricky to avoid, but since Nova is an admin panel, I think it would be good if it avoided preventing the use of good security measures that would otherwise be usable - XSS in admin interfaces is a common attack vector.

Steps To Reproduce

  • Use any Nova installation (requires no alterations to the app).
  • Configure a strict CSP in nginx:
    add_header Content-Security-Policy "default-src 'self' https: ; script-src 'self' 'unsafe-inline' ; style-src 'self' 'unsafe-inline' fonts.googleapis.com ;
img-src * 'self' blob: data: ; font-src 'self' fonts.gstatic.com ; media-src * 'self' ; form-action 'self' ; frame-ancestors 'self' ; base-uri 'self' ;";
  • Reload nginx then try to log in to Nova; it should succeed, but redirect to a blank grey page.
  • Add unsafe-eval to the script-src section, so it becomes script-src 'self' 'unsafe-inline' 'unsafe-eval' ;.
  • Reload nginx, observe that login now works and the dashboard is displayed correctly.

It would be good to avoid using google fonts too - they are typically regarded as trackers, and it's fiddly to have to enable them only for Nova. I know they're pretty, but falling back to local static or standard web fonts would be preferable for an admin interface.

@Lednerb
Copy link

Lednerb commented Sep 21, 2019

#1933 (comment)
It would be good to avoid using google fonts too - they are typically regarded as trackers, and it's fiddly to have to enable them only for Nova. I know they're pretty, but falling back to local static or standard web fonts would be preferable for an admin interface.

It should not be a problem for nova to use this fonts but include them locally and shipping them directly with nova.

https://google-webfonts-helper.herokuapp.com/fonts/nunito?subsets=latin

@jbrooksuk
Copy link
Member

We will not be hosting the Nova JS externally. This is something that you could configure yourselves by overriding the Nova views to look for a different path, though.

@harlan-zw
Copy link

This one caught me out too, thanks for the fix @Synchro

@jbeales
Copy link

jbeales commented Mar 18, 2020

Does anyone have a way around adding unsafe-eval to the CSP. @Synchro what did you end up doing?

@Synchro
Copy link
Author

Synchro commented Mar 18, 2020

Unfortunately I've had to leave it with the worst-case unsafe-eval enabled. I don't know enough about Laravel, Vue, or Nova internals to fix it.

@jbeales
Copy link

jbeales commented Mar 18, 2020

That sucks. I just patched together a system where Nova gets unsafe-eval but everything else doesn't.

@sebastianmacarescu
Copy link

@jbeales how did you manage to do that?

@Synchro
Copy link
Author

Synchro commented Oct 2, 2020

Oh, I've done that too in other contexts, using nginx.

First create a map that has a default value, and a regex to match the pages you want to use a different CSP for, and the CSP contents you want for each (you can have as many of these entries as you like in the map):

map $request_uri $csp_header {
    default "default-src 'none' ; script-src 'self' ; style-src 'self' ; child-src 'self' ; img-src * 'self' data: ; font-src 'self' ; media-src * 'self' ; object-src 'self' ; form-action 'self' ; plugin-types application/pdf ; connect-src 'self' ; frame-ancestors 'self' ; base-uri 'self'";
    "~/(page1|page2|page3)" "default-src 'none' ; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' * ; child-src 'self' ; img-src * 'self' data: ; font-src 'self' ; media-src * 'self' ; object-src 'self' ; form-action 'self' ; plugin-types application/pdf ; connect-src 'self' ; frame-ancestors 'self' ; base-uri 'self'";
}

Then in any location that uses it:

add_header Content-Security-Policy $csp_header;

It will automatically pick the CSP policy that matches the request URL

@jbeales
Copy link

jbeales commented Oct 2, 2020

@sebastianmacarescu I'm using spatie/laravel-csp, and have 2 Policy classes, my Main policy, and my Nova policy which extends the Main policy class and adds unsafe-eval.

Then I have spatie/laravel-csp set to use the Main policy, but in config/nova.php I've added \Spatie\Csp\AddCspHeaders::class . ':' . \App\Services\Csp\Policies\Nova::class, to the middleware at the end. This replaces the Main policy with the Nova policy for Nova requests.

If you're not using spatie/laravel-csp you can use the same approach - set your main CSP in a middleware, then add an additional middleware that adds unsafe-eval to Nova using that middleware nova config option.

@crynobone crynobone added next-series implemented Feature Request implemented labels Apr 2, 2022
@laravel laravel locked as resolved and limited conversation to collaborators Apr 2, 2022
@crynobone crynobone added this to the 4.x milestone Apr 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
implemented Feature Request implemented
Projects
None yet
Development

No branches or pull requests

7 participants