NuxtJS Content Security Policy - http-headers

Unable to apply a content security policy without including unsafe-inline for scripts and styles.
NuxtJS generates both inline styles and scripts upon build.
As my application is static, NuxtJS default configuration for this does not work as it requires Server side rendering to achieve this. I haven't been able to find a way to inject a nonce into the build process to solve this issue.
My current setup is to apply Security HTTP Headers to the domain is using a cloudflare worker which does not touch the application. Therefore I am looking for options how to integrate this between the application and edge worker https://scotthelme.co.uk/csp-nonces-the-easy-way-with-cloudflare-workers/
Came across couple of injecting methods using middleware while browsing nuxtjs github issues which I can't get to work.
Has anyone found a solution for generating a policy which does not include unsafe-inline, either directly in the application or externally?

NuxtJS generates both inline styles and scripts upon build. ... I haven't been able to find a way to inject a nonce into the build process to solve this issue
From the point of view of the CSP
there are 3 types inline scripts and only 1 of them may be allowed using 'nonce-value'
there are 3 types on inline styles (including JS call of .setAttribute() function - yeah it's requires 'unsafe-inline' in style-src too), and only 1 of them may be allowed using 'nonce-value'.
Therefore, in an abstract form, your task is not solvable, you need specifics.
Assuming you are only using <script>...</script> and <style>...</style> constructs (these may be allowed using 'nonce-value') you have 3 options:
use 'nonce-value'
use 'hash-value'
place script/style into external file and use 'self'
In case of usage document.createElement('style'), opt 1 is preferable you just set style.nonce = 'generated_base64_value' attribute. Because to calculate 'hash-value' is not easy in this case.
In case of usage <script>...</script> and <style>...</style> much easier to calculate hashes or move all to external file (opts 2, 3). To use cloudflare workers is complicate the code unnecessarily in this case.
Some middleware generates a lot of separate <style>.red {color:red;}</style>, <style>.r_padd {padding-right:20px;}</style>, etc. It is a headache for opts 1, 2, but easy solvable via opt 3.
If you use third-party scripts, for example Google Tag Manager, there is no way to get rid of 'unsafe-inline' scripts, and from 'unsafe-eval' too in some cases.
PS: There is no universal way. And not knowing what is under the hood of your car, it is difficult to give advice on how to afterburner it.

Related

Multiple Vue apps, multiple entry files, same Vuex/Vue3CompostitionApi store [lost reactivity]

I am trying to iteratively replace .cshtml razor views with what I wanted to call Vue "mini-apps". Which should be somewhere in between a micro-frontend and a classic SPA. The aim is to share some of the code base, mainly dependencies. Compile a common chunk-vendors.js and have the "mini-apps" as separate javascript entry files to place on appropriate views. As performance demand would grow, I would progress into splitting chunk-vendors.js and optimize via lazy-loading.
The problem I am hitting here is trying to make two root Vue instances talk to each other through a shared state. Right now only the app that is imported/mounted first stays reactive. I thought that my problem was in the Vue 2 reactivity system/how Vuex binds itself to a concrete Vue instance here. When I implemented a primitive store, the situation ended up being exactly the same.
What confuses me about this is that if I were to instantiate two applications in a single main.js entry file, the store sharing would just work. Which suggest that Vue is either creating some kind of hidden root instance or that my Vuex code analysis deduction of it binding to a concrete instance was incorrect.
I would highly appreciate it if someone could tell me why this can't work, optionally suggest a workaround?
I have created a reproduction both in Vue 2 with Vuex and in Vue 3 with composition API/primitiveStoreImplementation here.
Vue-cli is building the app in an MPA mode with pages specified in vue.config.json, then imported in the root index.html file. The store is initialised once and saved for later check/loading on the window object. In the context of asp/razor I would have webpack set up to remove the redundant files, only leaving javascript bundles. Also, the dev proxy would proxy everything except the path to the script bundles. All of this is removed for the sake of the demonstration.
(once I find a solution I hope to replace the source link with specific code snippets)
Options considered:
I am trying to avoid it, but I might have to always run a "coordinator" root instance that will check the presence of certain elements on a page and load/unload the "mini-apps" as components using something like portal-vue when needed. That coordinator would also contain a state with modules, some of which would be marked as "shared" thus operations from multiple "mini-apps" would be allowed (ownership flag check).
I have considered sessionStorage/localStorage, the problem is that the 'storage' events are only triggered across tabs and not within one document first |Note. I would have to trigger a custom event or play around with iframes. Feels too hacky, but that might be an axiom here. It would also duplicate the same state across many store instances.
These are some relevant articles I have found on this topic:
Probably closest to what I am trying to achieve:
Using Vuex with multiple Vue instances
Same but different:
Build Vue microfrontend app (with routing and vuex store)
The use case for multiple entries are sub-apps that don't coexist on the same page, although they can. They could be web components or regular app bundles. They can even interact with each other but they need something else for this - global event bus or a mediator app that passes data between them.
The problem is that there are more than one Vue library copies and/or more than one Vuex store instance. In order to avoid this, they would need to be precisely loaded only once on the page and reused between apps, i.e. vue and vuex are loaded as CDN libs, possibly used as Webpack externals to use window.Vue and window.Vuex transparently for respective import. Not only Vuex but store needs to be a singleton on the page (basically a said mediator). This is acceptable solution but primarily suitable for existing applications that have design restrictions and need a workaround.
I am trying to avoid it, but I might have to always run a "coordinator" root instance that will check the presence of certain elements on a page and load/unload the "mini-apps" as components using something like portal-vue when needed.
This is the common way to do this. Vue 3 has teleports that has give less control than portal-vue. It has no downsides for application design if done properly. The same thing is achieved similarly in other frameworks (Angular, React) as well, where portals appeared earlier.
I have considered sessionStorage/localStorage, the problem is that the 'storage' events are only triggered across tabs and not within one document
This is solved by using window postMessage and message event in the same tab. In case this shouldn't be limited to a single window, there are third party libs that use both for cross-tab synchronzation, a native alternative is BroadcastChannel that has less browser support than LS but doesn't have its limitations regarding tabs.

Workbox/Vue: Create a custom variation on an existing caching strategy handler

Background:
I'm building an SPA (Single Page Application) PWA (Progressive Web App) using Vue.js. I've a remote PostgreSQL database, serving the tables over HTTP with PostgREST. I've a working Workbox Service Worker and IndexedDB, which hold a local copy of the database tables. I've also registered some routes in my service-worker.js; everything is fine this far....
I'm letting Workbox cache GET calls that return tables from the REST service. For example:
https://www.example.com/api/customers will return a json object of the customers.
workbox.routing.registerRoute('https://www.example.com/api/customers', workbox.strategies.staleWhileRevalidate())
At this point, I need Workbox to do the stale-while-revalidate pattern, but to:
Not use a cache, but instead return the local version of this table, which I have stored in IndexedDB. (the cache part)
Make the REST call, and update the local version, if it has changed. (the network part)
I'm almost certain that there is no configurable option for this in this workbox strategy. So I would write the code for this, which should be fairly simple. The retrieval of the cache is simply to return the contents of the requested table from IndexedDB. For the update part, I'm thinking to add a data revision number to compare against. And thus decide if I need to update the local database.
Anyway, we're now zooming in on the actual question:
Question:
Is this actually a good way to use Workbox Routes/Caching, or am I now misusing the technology because I use IndexedDB as the cache?
and
How can I make my own version of the StaleWhileRevalidate strategy? I would be happy to understand how to simply make a copy of the existing Workbox version and be able to import it and use it in my Vue.js Service Worker. From there I can make my own necessary code changes.
To make this question a bit easier to answer, these are the underlying subquestions:
First of all, the StaleWhileRevalidate.ts (see link below) is a .ts (TypeScript?) file. Can (should) I simply import this as a module? I propably can. but then I get errors:
When I to import my custom CustomStaleWhileRevalidate.ts in my main.js, I get errors on all of the current import statements because (of course) the workbox-core/_private/ directory doesn't exist.
How to approach this?
This is the current implementation on Github:
https://github.com/GoogleChrome/workbox/blob/master/packages/workbox-strategies/src/StaleWhileRevalidate.ts
I don't think using the built-in StaleWhileRevalidate strategy is the right approach here. It might be possible to do what you're describing using StaleWhileRevalidate along with a number of custom plugin callbacks to override the default behavior... but honestly, you'd end up changing so much via plugins that starting from scratch would make more sense.
What I'd recommend that you do instead is to write a custom handlerCallback function that implements exactly the logic you want, and returns a Response.
// Your full logic goes here.
async function myCustomHandler({event, request}) {
event.waitUntil((() => {
const idbStuff = ...;
const networkResponse = await fetch(...);
// Some IDB operation go here.
return finalResponse;
})());
}
workbox.routing.registerRoute(
'https://www.example.com/api/customers',
myCustomHandler
);
You could do this without Workbox as well, but if you're using Workbox to handle some of your unrelated caching needs, it's probably easiest to also register this logic via a Workbox route.

How to keep GraphQL API and frontend synchronized on a staging server?

We have a Rails application with GraphQL API in one GIT repository, and React frontend application in another. Both backend and frontend have CI and are deployed separately. But both backend and frontend are still under heavy development and often our staging server doesn't work, because deployment is not synchronized and we don't test the whole application - we test API and we test frontend without API.
What is the best way to deploy frontend and backend only when they are synchronized, I mean when new versions doesn't break functionalities? I thought about third repository with backend and frontend included as GIT modules, acceptance tests and deploying both sides at once. But maybe there is simpler solution? Maybe some versioning?
You certainly can do versioning with GraphQL, but ideally any changes to your schema shouldn't be breaking ones. This just takes discipline on the part of your backend devs, although there are also tools (like this) to help detect breaking changes. Some general guidelines:
Deprecate fields using the #deprecated directive instead of deleting them. Deprecated fields can be communicated to client teams and retired after some agreed-upon amount of time.
Avoid renaming types. Try to use more specific naming to avoid having to rename things in the future (i.e. use emailMessage instead of just message if you could foreseeably have a different kind of message in the future).
Use payload types for mutations. If you mutate a User, for example, instead of just returning the User, return a payload type that has a user field. If down the road, you realize the mutation should also return other information, you can easily add fields to the payload type without creating breaking changes.

vue-router route encryption (without webpack) for security

In vue or vue-router ;
Is it possible to minimize encrypt the route html/js and decrypt and use by vue-router at other end
export default{
template:'',
data:...
methods:..
}
just to make sure code is minimized and not exposing all the client code for attacks/security
Note: not using webpack.
Another Note: to clarify: export default{... } was clearly visible in the network panel. Causing the source of hacks and security breaches.
So here is what i am looking for :
Encryption will be done on server side in node.js
Decryption will be done on client side after the network panel loads the route.
So now instead of export default .. it will now be some encrypted text in network panel.
After decryption and decompression it gets loaded into vue-router.
First - there is no point to encrypt routes. Any kind of encryption you will make on backend - should be decrypted on the frontend. And you will make a method that would decrypt it. For anyone who can use chrome devtools it would be a matter of minutes to bypass your encryption.
Second - you may obfuscate your code. But again - it just a matter of minutes, literally, to deobfuscate it.
And any of the above methods would just increase bundle size and degrade performance.
At first, you must implement security on your backend.
If you are so worried that somebody will see your very private routes - build two or three bundles. With the same components/almost same look. But with limited routing. It's quite easy to implement due to Vue component nature.
And depending on user type inject the corresponding bundle into the page.
This will not increase security in any way whatsoever. You cannot prevent users from acquiring frontend code because they need it in order to use your product.
You can run your code through obfuscators such as this one but it's largely a waste of your time.
The best option in terms of both performance and obfuscation would be to run your code through a tool like UglifyJS. It can re-arrange your code paths, remove whitespace, and mangle variable names in order to make it more annoying for a would-be attacker to decipher your code.
Most importantly, you should never send valuable business logic over the wire. Keep your trade secrets on the server.

AngularJS dynamic application with or without routing

My application has 2 purposes:
It needs to run stand-alone, where it needs routing for choosing a
study etc.
Or, it runs integrated in an other project, and only needs
one controller and one view.
Currently i have a routeProvider configured for the stand-alone application, injecting the pages in the ng-view tag in the HTML.
Now is my question: How can i inject an controller and view in the ng-view (For the integration). I cannot manipulate the HTML since it is static. I cant use a single routeProvider rule, because this can interfeir the application that integrates mine (Other plugins can use the #/.. for info or other things).
In your situation you can't use routeProvider when other stuff interferes.
Of Course you could prevent routeProvider to act on outside changes of the hashbang with workarounds but thats not nice.
routeProvider will listen to all changes of the url after the hashbang.
So what you should do is to manually bootstrap() your angular app with the controllers you need. If your app is small enough you could even use directives to achieve lazy loading of templates with the attribute templateUrl : "/myurl"
Usually to create a dynamic App use Routing. Simnple point.
The best way to use Angular if you want to unleash all its might don't integrate it.
I explain why:
+ Your state never gets lost due to page reloads
+ You have full control of the environment and don't have to worry about interfering scripts etc.
+ If your user should manually reload, you can redirect to home/login or even better use requireJS or HTML5 local storage to recover your scopes after a reload
Cheers, Heinrich