After long frustrating hours of research I finally found the cause for my Laravel7 VueJS (within blade templates) application running on nginx throwing a blank screen. Yet I lack the explanation or correct config.
When I accessed any route it would be seen for around 200ms and then switch to a white screen without any errors in npm run prod config.
Body tag would be completely empty (it looked uncommented in the inspector)
[...]
<body>
<!-- -->
</body>
[...]
Funny enough (sarcastically speaking) on page reload the login page would work normally but after accessing any other route it would revert to the behaviour described above.
After switching to npm run dev the console threw the following error:
[Vue warn]: It seems you are using the standalone build of Vue.js in an environment with Content Security Policy that prohibits unsafe-eval. The template compiler cannot work in this environment. Consider relaxing the policy to allow unsafe-eval or pre-compiling your templates into render functions.
and
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: "default-src 'self' http: https: data: blob: 'unsafe-inline'".
Which made me realize my nginx security config which I generated using the fabulous Tool provided by DigitalOcean included the following line:
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
After removing and restarting nginx everything works and looks as it does on my dev environment.
From what I get I now theoretically make my site vulnerable to XSS attacks but I do not fully understand what the option does or if it is safe to run without it with these circumstance.
The CSP header just lets your browser know what sources of JS are allowed. However, it is really a backup plan - what causes XSS is some code on your system that would render unauthorised JavaScript.
For example, the comment boxes on Stack Overflow allow me to enter the following text: <script src="http://evilserver.com/malicious.js"></script>. Stack Overflow know what they are doing, so they make sure that what is rendered is HTML, and not a literal <script> tag. Thus, you need to make sure you take the necessary care when rendering user supplied content and you will be OK (in general you do this in your output layer, not when accepting/storing input).
If you accept HTML input from users (as Stack Overflow does) then you have to be especially careful to allow only certain tags, and to ensure that any JS vectors are blocked up. So, the following text:
is actually in an <i> tag, which is rendered literally in the web app
That one is OK, since it is safe. You do need to make sure that any attributes are carefully checked, and any invalid markup is rejected. These can also be the source of security problems. This is a complex enough problem that, if you need users to be able to input HTML, you should not attempt to filter it yourself. Use a well-tested and well-regarded library instead.
Related
I have a strict CSP (Content-Security-Policy) in place, allowing the Fathom Analytics script.js to be loaded from a custom domain.
In the .htaccess on Apache:
script-src 'self' 'nonce-%{UNIQUE_ID}e' my-custom-domain.example.com;
Application layer:
<script src="https://my-custom-domain.example.com/script.js" data-site="ABCDEFGH" defer nonce="<?php echo $_SERVER['UNIQUE_ID']; ?>"></script>
It always returns “loading failed” with an error 403 in the console.
The nonce was introduced for testing, as I thought, that might solve the problem. It doesn’t. (I know, I know, this is not the most secure method to use a nonce.)
I have tried variants of the custom domain, too (with protocol, without protocol, wildcard subdomain, …).
Turning off the CSP “fixes” the issue. Meaning, the 403 only kicks in, when the CSP is active.
I am relatively new to CSPs and don’t know, how to proceed.
Any suggestions are appreciated.
Right after reaching out publicly I found the solution:
I had to get rid of the “Referrer-Policy” directive—or rather provide an empty one like so: Header always set Referrer-Policy "".
After doing that, make sure to employing rel="no-referrer" on all external links instead.
Also I had to add the custom domain to the img-src directive (on top of the script-src one).
The nonce is not necessary to make this work.
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.
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.
We ran Burp Suite on our product and found some security vulnerabilities. The tool detected some of the CGI files which are vulnerable to Cross-Site Request Forgery attacks (CSRF).
As usual I did search for CSRF protection module on CPAN and found CGI::Application::Plugin::ProtectCSRF.
I'm wondering how can I integrate this module into our application in a generalized way? The documentation is not clear to me. How do I configure this module and make minimal changes to make sure whole application is secured from CSRF.
I also came across mod_csrf (an Apache module to prevent CSRF). Is installing this module and setting below in apache configuration file enough to prevent CSRF?
<VirtualHost>
CSRF_Enable on
CSRF_Action deny
CSRF_EnableReferer off
</VirtualHost>
I can understand that you found the documentation for CGI::Application::Plugin::ProtectCSRF unclear: it is a little impregnable
All that the Perl module appears to do is to add a hidden field to each HTML form with the name _csrf_id and a random value derived from various sources and encoded through SHA1. The protection comes when the response from the client requires that the same value must be returned to the server
It is quite nicely coded, but it uses custom subroutine attributes, and the documentation for the attributes pragma says this
WARNING: the mechanisms described here are still experimental. Do not rely on the current implementation
I cannot tell from my quick review whether the subroutine prototypes are essential to the module, but I recommend that you use the Apache mod_csrf module instead, which is likely to be more thoroughly tested than the Perl module, and has proper documentation
Since we were using in house server, not apache, therefore, mod_csrf was not possible to implement.
I ditched ProtectCSRF module as the documentation was unclear.
I solved it by doing below:
Add an element in header template which is common to all pages, this element contains CSRF token which is being passed from server
Create a JavaScript function and bind it to onload event. This JS function does below tasks:
a) Find forms in current page
b) If forms are found then create a hidden "input" element and append it to each form
c) Take the value which was put in header and assign it to above created elements
d) Now all forms have a hidden input element which contains CSRF token from point 1
Now whenever a form gets submitted this hidden element will also be submitted, whose value we are verifying at server end. If tokens do not match then there is CSRF, for which we throw the error and block request
According to this documentation I should be able to include <script src="https://sandbox.google.com/checkout/inapp/lib/buy.js"></script> in html of my packaged app, but I received an error:
Refused to load the script
'https://sandbox.google.com/checkout/inapp/lib/buy.js' because it
violates the following Content Security Policy directive: "default-src
'self' chrome-extension-resource:". Note that 'script-src' was not
explicitly set, so 'default-src' is used as a fallback.
Also I've tried to attach buy.js (which I just copied from mentioned url) but it also produces an error in buy.js:
Refused to frame
'https://checkout.google.com/inapp/frontend/app/payments.html?formFactor=DES…extension://ihligbifffjddjffdiapccakkdglodcj&rti=i:48847aba&rt=o:-519cd794'
because it violates the following Content Security Policy directive:
"frame-src 'self' data: chrome-extension-resource:".
What is the problem here?
You're doing it wrong. This buy.js is a simple cross-app messaging script which talks to internal Google In-App Application inside Chrome.
You must package the buy.js library with your app, and load the library from its location in your package.
Check this for more info