Enabling Content-Security-Policy on a minimal web app - http-headers

I'm new to CSP and my goal is to enable the simplest possible CSP header.
Based on reading the spec and MDN docs I thought my app should work but unfortunately no luck on Chrome Canary v70.
I setup a minimal repo to reproduce. Can you see where I've gone wrong?

Turns out I was misunderstanding the details a bit. I'll post my solution here in case it helps someone else in the same boat.
My goal is to serve a React SPA with CSP enabled. The app happens to use Material-UI, which uses JSS, which injects inline styles - which of course are blocked by default with CSP.
Because it's a static SPA for the frontend and modifying HTTP headers is out of scope of the SPA, I instead generate a nonce on the web server. The nonce gets injected into the CSP HTTP Header and also in the index.html tag consistent with what JSS expects.
The upside is CSP is protecting the SPA, and we don't have to use unsafe-inline escape hatch. The downside, but a small one, is that index.html is dynamic now and can't be cached. But seeing as the file is already tiny (<1kb) the benefits of CSP seem worth that tradeoff.

Related

Implement CSP for indiviual pages in NUXT JS

I had a requirement in a project of mine using NUXT JS to add CSP for a particular page only. The CSP headers that we provide should also be dyanamic. I looked through various articles which mentioned implementing CSP using the nuxt.config.js file for the entire NUXT application. Also if I change the values in the CSP property I need to restart the server each time (Also not sure about how to implement that). Is the above requirement possible to implement in NUXT..?

Set Permission-Policy for Vue and NodeJS app

I have an application that has a VueJs based front end and NodeJs based backend API. The client-side is a SPA and it communicates with API for getting data. Now in a security scan, it is mentioned that the app doesn't have a Permission-Policy HTTP header and I would like to add it. I but not sure is there any option I can add in the VueJS and I am confused whether this is something that needs to be added from the front end. From the Node app, it is possible to set the header, but here the pages are not generated from the server-side. It will be helpful if someone can let me know how can I add these headers to the app.
Technically you can publish Permissions-Policy header when you sent an initial SPA's HTML code (you have to use some packages or Node.js server facility to publish response header). Even more so scanners do not execute ajax and will not see the pages of your SPA.
But there are some doubts whether it is worth doing it at all.
Permissions Policy is a new name of Feature Policy, below I will use Feature Policy term, but all of the below also applies to Permissions Policy.
Browsers poorly support Feature Policy and do not support Permissions Policy. Only Chrome supports the interest-cohort directive, but you have to set specific flags to enable Permissions Policy support. Feature Policy / Permissions Policy spec still is under development.
Feature Policy is rarely published via HTTP header, because it is intended to restrict the capabilities of nested browsing contexts (iframes), and not the main page itself. Therefore it's mostly published via <iframe allow="..." attribute for each third-party iframe embedded.
But the scanners are not aware of this and do not check the allow= attribute.
Scanners don't know much about real security, they are more focused on visualization baubles like Grade A+ and labels with green/red color. Therefore scanners:
are not recognize Content Security Policy in meta tag, just in the HTTP header.
require X-Frame-Options header for any web page despite presence of CSP's frame-ancestors derictive and ignore fact that some sites are inbtended to be embedded (widgets, youtube/vimeo video etc.).
require Feature Policy / Permissions Policy header despite these are not supported or are published by another way.
Mostly scanners results have nothing with real security, all is how to get A+ grade, nothing else (see a relevant thread "headers manipulatin to get Grade A+").
Of course, scanners can draw your attention to some overlooked headlines, but final decision which headers do web-app need to publish is up to you.

JS storefront URL is picked up for OCC_BACKEND_BASE_URL_VALUE"

Running into very strange situation with the Spartacus setup on CCV2. After setting up the meta placeholder in the index.html file:
I setup the baseURL as null in environment.ts and environment.prod.ts, just to be double sure.
baseUrl: null,
It seems to work, but the problem is when storefront is deployed, JS store is picking up the JS storefront URL for content load
https://JS Storefront URL/XXXwebservices/v2/SITE/cms/pages
My understanding is that it should be ACC Storefront URL:
https://ACC Storefront URL/XXXwebservices/v2/SITE/cms/pages
Is there any other setting that needs to be made? Other than the ones identified above? do we need any other configuration on the CCV2 side of things?
The initial answer below didn't make too much sense, let me retry:
I recommend to leave out the baseUrl in the configuration completely, as the current behaviour prioritises the configuration over the meta-tag. See https://github.com/SAP/spartacus/issues/5886 for more info.
While the MEDIA_BACKEND_BASE_URL_VALUE has been added in Spartacus to distinguish the api and media, CCv2 has not yet implemented this feature. See also https://github.com/SAP/spartacus/issues/2212#issuecomment-490089609.
This is why the Spartacus side of it works, but the media base Url doesn't get injected on ccv2.

Are we forced to use 'unsafe-inline' in our CSP when using Vue.JS?

Is there a way to make Vue.js to work with CSP properly?
When I run my spa application (resulting from npm run generate with Nuxt.js), I will get several warnings such as these:
Refused to apply inline style because it violates the following
Content Security Policy directive: "style-src 'self' 'strict-dynamic'
'nonce-124lk5fjOc4jn7qqLYEsG2jEvxYuqu8J' 'unsafe-inline' https:". Note
that 'unsafe-inline' is ignored if either a hash or nonce value is
present in the source list.
Knowing CSP, there are two correct ways of fixing this:
Using nonces, where Vue.js would have to sign all the generated scripts and styles with a nonce attribute. But I don't think this would solve anything, since it appears some CSS is added inline.
Using hashes, which is actually the preferred way of doing it, since the hash secures exactly what we want the client to execute on the browser.
However, in order to use hashes, Vue.js/Webpack must be able to calculate the hash for all its scripts and styles, and:
for each compilation, tell them to the developer that will then add these hashes to a NGINX configuration file,
or,
be able to generate meta tags containing the hashes, making this process 100% transparent to the developer, who doesn't need to configure anything else to guarantee a good CSP protection.
Does Vue.js support this in any way? Is there anyone in the world who was able to make CSP working with Vue.js without any 'unsafe-inline'?
According to the Vue.js docs, the runtime build is fully CSP-compliant.
Nuxt is supporting a csp config to create hashes via webpack sent as header on dynamic SSR mode and meta elements otherwise (see https://github.com/nuxt/nuxt.js/pull/5354)
you could use the --no-unsafe-inline option in your npm run build script
https://cli.vuejs.org/guide/cli-service.html#vue-cli-service-build
Not sure if this is better as a comment or not but it kinda works so putting it here for now.
Our deployment strategy might be a bit different, but essentially we trigger a lambda to update the cloudfront csp with our CI/CD.
We noted that the inline scripting was static despite different app versions/bumps. Our current workaround is:
Deploy on a dev server - get the sha256 hash from the chrome dev tools (you could probably calculate it yourself to avoid deploying)
Updated our terraform cloudfront lambda CSP with the hash
On the new deploy the hash matches and we don't need unsafe-inline
Some big limitations re: if nuxt changes the inline script on new versions we'll have to manually update our hash in the CSP. Also, depending on your styling framework there may be a number of inline-styles which aren't captured here.

CSRF tokens - Do we need to use them in most cases?

So I essentially went on an epic voyage to figure out how to implement CSRF tokens. 20 years later - and now I feel like I just wasted my life. haha
So basically after making malicious test-clients and doing some re-reading it looks like it's virtually not a problem if:
1) You don't allow outdated browsers(they don't enforce CORS)
2) You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
3) You use a JSON API(all requests-responses is sending JSON).
4) You take care of XSS(they can inject code that will run from same origin ).
So as long as you take care of XSS(Reactjs! Holla) - all of the above(minus the old browser part I guess) is basically common practice and an out-of-the-box setup - so it seems like a waste of time to worry about csrf tokens.
Question:
So in order to avoid throwing my laptop under a moving car - is there any reason that I did all that work adding CSRF tokens if I am already adhering to the 4 prevention strategies mentioned above?
Just Fun Info - wanted to share one juicy find my tests came across:
The only ify thing I found with my tests is "GET" requests and an image tag
e.g.
<img src="http://localhost:8080/posts" onload={this.doTheHackerDance} />
The above will pass your cookie, and therefore access the endpoint successfully, but apparently since it is expecting an image - it returns nothing - so you don't get to do the hacker dance. :)
BUUUUT if that endpoint does other things besides return data like a good little "GET" request(like update data) - a hacker can still hit a "dab!" on ya (sorry for viral dance move reference).
tl;dr - Requiring JSON requests mitigates CSRF, as long as this is checked server-side using the content-type header.
Do we need to use them in most cases?
In most other cases, yes, although there are workarounds for AJAX requests.
You don't allow outdated browsers(they don't enforce CORS)
You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
CORS is not required to exploit a CSRF vulnerability.
If Bob has cookies stored for your site, CORS allows your site to allow other sites to read from it, using Bob's browser and cookies.
CORS weakens the Same Origin Policy - it does not add additional security.
The Same Origin Policy (generally - see below for caveat) does not prevent the request from being made to the server, it just stops the response being read.
The Same Origin Policy does not restrict non-Javascript requests in any way (e.g. POSTs made by <form> or <img> HTML directives).
Browsers that do not support CORS, also do not support AJAX cross-origin requests at all.
Therefore while not outputting CORS headers from your site is good for other reasons (other sites cannot access Bob's session), it is not enough to prevent CSRF.
You use a JSON API(all requests-responses is sending JSON).
Actually, if you are setting the content-type to application/json and verifying this server-side, you are mitigating CSRF (this is the caveat mentioned above).
Cross-origin AJAX requests can only use the following content-types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
and these requests are the only ones that can be made using HTML (form tags or otherwise).
You take care of XSS(they can inject code that will run from same
origin ).
Definitely. XSS is almost always a worse vulnerability than CSRF. So if you're vulnerable to XSS you have other problems.
BUUUUT if that endpoint does other things besides return data like a
good little "GET" request(like update data) - a hacker can still hit a
"dab!" on ya (sorry for viral dance move reference).
This is why GET is designated as a safe method. It should not make changes to your application state. Either use POST as per the standard (recommended), or protect these GETs with CSRF tokens.
Please just follow OWASP's guidelines: "General Recommendation: Synchronizer Token Pattern". They know what they're doing.
CSRF counter-measures are not hard if you're using a framework. It's dead simple with Spring Security for example. If you're not using a security framework, you're screwing up big time. Keep it simple. Use one general method to protect against CSRF which you can use on many types of projects
CSRF is orthogonal to CORS . You are vulnerable even if you disallow CORS on your server and your users use the latest Chrome. You can CSRF with HTML forms and some JavaScript.
CSRF is orthogonal to XSS . You are vulnerable even if you have no XSS holes on your server and your users use the latest Chrome
CSRF can happen against JSON APIs. Rely on Adobe keeping Flash secure at your own peril
The new SAMESITE cookie attribute will help, but you need anti-CSRF tokens until then.
Keep reading