Implement CSP for indiviual pages in NUXT JS - vue.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..?

Related

Is It Possible to Have a Meaningful/Secure Content Security Policy With Next.js + Styled-Components and a Static Host (eg. S3)

Recently Google's Lighthouse tool alerted me to the fact that I wasn't providing a Content Security Policy. However, when I try to add one (or at least one without the word "unsafe" in it), I wind up with a bunch of violations, seemingly coming from Next.js and Styled-Components.
Both libraries seem to use dynamic script/style tags which violate any sane CSP. But the only way I've found to work around them is to use a "nonce". However, that seems to require having an actual server running: if you're using Next to generate static files (to host on a static host like AWS S3), you can't provide nonces.
My question is simple: am I missing anything? Is there some non-nonce-based way, or a static-host-nonce-based way, to host a site on S3 using Next.js and Styled Components?
Or is it just impossible to use those libraries together with a strict CSP (without a server-generated nonce)?
I hope you:
do not use inline styles like <tag style='display:none;'> or JS call of element.setAttribute('style', ...).
do not use built-in inline event handlers like <tag onclick='...'> and JS-navigation like <a href='javascript:void(0)'>
because all of above require 'unsafe-inline' in styles/scripts respectively since 'unsafe-hashes' token is not supported by Safary and bugly supported by Firefox.
For Single Page Applications (SPA) (without server-side rendering), using 'nonce-value' is not useful, because the SPA does not reload the page, but only partially updates its contents, but you must generate new nonce for each page loading.
For serverless apps (like static file hosting) and SPA apps you can use 'hash-value' instead of 'nonce-value' to allow inline scripts and styles.
If you use Webpack, it has some plugins, for instance, csp-html-webpack-plugin plugin will generate content for your Content Security Policy meta tag and input the correct data into your HTML template, generated by html-webpack-plugin. All inline JS and CSS will be hashed, and inserted into the policy.

How do dynamic API calls work in Nuxt.js static vs SSR mode?

Even after reading through multiple articles explaining the differences between static and SSR rendering I still don't understand how dynamic API calls work in these different modes.
I know that Nuxt has the fetch and asyncData hooks which are only called once during static generation, but what if I use dynamic HTTP requests inside component methods (e.g. when submitting a form via a POST request)? Does that even work in static sites?
I'm making a site that shows user generated content on most pages, so I have to make GET requests everytime one of those pages is visited to keep the content up to date. Can I do that with a static site or do I have to use SSR / something else? I don't want to use client side rendering (SPA mode) because it's slow and bad for SEO. So what is my best option?
There is actually no difference between either asyncData() or fetch() hooks when you do use target: static (SSG) or target: server (default, SSR).
At least, not in your use-case.
They are used mainly by your hydrated app.
As a reminder, when using either SSG or SSR, your static page will be hydrated and will become an SPA with all the dynamic functionality that we love. This combo of SSG + SPA or SSR + SPA is called an universal app (or isomorphic app).
Both asyncData() and fetch() will be called upon navigation within your client side SPA.
There are also some things happening on the server side, like fetch being called (by default) when you request the server for an SSR built app.
Or the fact that when you generate your app (if using SSG), you can reach some API and generate dynamic routes (useful in the case of a headless CMS + blog combo for example).
For performance reasons and to have a quick build time, you may pass a payload and use it in an asyncData hook in the dynamic route, as explained here
Still, a static Nuxt app, is basically just an app built ahead of time, with no need for a Node.js server, hence why an SSG app can be hosted on Netlify for free (CDN) but and SSR one needs to be hosted on something like Heroku (on a paid VPS).
The main questions to ask yourself here are:
do you need to have some content protected? Like some video courses, private user info etc...already in your Nuxt project (if SSG, disabling the JS will give access to the generated content)
is your first page a login? Is it mandatory to access the rest of the content? Like an admin dashboard (you cannot generate content ahead of time if the data is private, think of Facebook's feed being generated for every account, not feasible and not secure as above)
is my API updating super often and do I need to have some super quick build time (limitation on free tiers essentially)? (SSG will need a re-generation each time the API changes)
If none of those are relevant, you can totally go SSG.
If one of those is important to you, you may consider SSR.
I do recommend trying all of them:
SSR (ssr: true + target: server) with yarn build && yarn start
SSG (ssr: true + target: static) with yarn generate && yarn start
SPA only (ssr: false + either target: static, target: server also work but who wants to pay for an SPA?!) with yarn generate && yarn start
Try to host it on some platforms too, if you want to be sure to understand the differences beyond your local build.
You can use this kind of extension to also double-check the behavior of having JS enabled or not.
I will probably recommend to take the SSG path. Even tho, if your content is always changing you will probably not benefit much from SEO (eg: Twitter or Facebook).
This github answer could maybe help you understand things a bit better (it does have some videos from Atinux).
PS: I did a video about this on the latest Nuxtnation that you can find here.
I use dynamic HTTP requests inside component methods (e.g. when submitting a form via a POST request)? Does that even work in static sites?
The short answer to this question is that yes, it does work. In fact you can have http requests in any life cycle hooks or methods in your code, and they all work fine with static mode too.
Static site generation and ssr mode in Nuxt.js are tools to help you with SEO issues and I will explain the difference with an example.
Imagine you have a blog post page at a url like coolsite.com/blogs with some posts that are coming from a database.
SPA
In this mode, when a user visits the said URL server basically responds with a .js file, then in the client this .js file will be rendered. A Vue instance gets created and when the app reaches the code for the get posts request for example in the created hook, it makes an API call, gets the result and renders the posts to the DOM.
This is not cool for SEO since at the first app load there isn't any content and all search engine web crawlers are better at understanding content as html rather than js.
SSR
In this mode if you use the asyncData hook, when the user requests for the said URL, the server runs the code in the asyncData hook in which you should have your API call for the blog posts. It gets the result, renders it as an html page and sends that back to the user with the content already inside it (the Vue instance still gets created in the client). There is no need for any further request from client to server. Of course you still can have api calls in other methods or hooks.
The drawback here is that you need a certain way for deployment for this to work since the code must run on the server. For example you need node.js web hosting to run your app on the server.
STATIC
This mode is actually a compromise between the last two. It means you can have static web hosting but still make your app better for SEO.
The way it works is simple. You use asyncData again but here, when you are generating your app in your local machine it runs the code inside asyncData, gets the posts, and then renders the proper html for each of your app routes. So when you deploy and the user requests that URL, she/he will get a rendered page just like the one in SSR mode.
But the drawback here is that if you add a post to your database, you need to generate your app in your local machine, and update the required file(s) on your server with newly generated files in order for the user to get the latest content.
Apart from this, any other API call will work just fine since the code required for this is already shipped to the client.
Side note: I used asyncData in my example since this is the hook you should use in page level but fetch is also a Nuxt.js hook that works more or less the same for the component level.

Vue: How to enable multi page in an existing SPA project?

I have a single page (SPA) application written in Vue.
Now I need a separate page that should be available without being signed in.
To me it seems like a need to enable multi page app (MPA). I see in the documentation (https://cli.vuejs.org/config/#pages) that I need to set this up in vue.config.js. But I the documentation is unclear to me. Do I need to edit/rerun the Vue CLI setup? Or do some webpack changes. Just adding a new page entry with corresponding files does not work (webpack does not insert anything in html-file).
From SPA View, i would likely go like this
Inside /views folder
- HomePage.vue (no auth)
- Login.vue
- /users/ subfolder (auth needed)
- DashBoard.vue
- About.vue
etc
Then define the routes (paths,components,etc.) with requiresAuth as auth-check, redirects back to the route with HomePage.vuecomponent then.
and SPA mostly comes with MPA Challenges such as SEO, SSR concerns. The routing roughly the same to Vue/Nuxt.

NuxtJs generate for dynamic websites?

I'm creating a simple demo app with NuxtJs. The homepage shows static content that is not changed very often. There is another route for showing a list of users: /users. And one for showing user's details: /user/id.
Now my question is what's the difference between nuxt generate and nuxt build? which one should I use?
I think nuxt generate page will not render dynamic routes like users and user/id, Am I right? If I am right, then generate command will generate a pre-rendered HTML for homepage only. So using generate is always better than using build right ?
In universal mode, nuxt generate is for static site generation. nuxt build is for SSR site.
In 2.13.0, Nuxt introduced a target: static feature, make sure to
check it.
A static site has the best performance, and it is easy to deploy on nginx or other services, like Netlify.
By default, nuxt generate only render your static home page and /users page, not the dynamic /user/:id route.
But you can config nuxt to help you generate the dynamic routes.
If you have a fixed set of users, you can use functions to generate the routes.
If the users data is constantly in change, you can config nuxt to fallback to SPA on the dynamic routes. But you can't get any benefit for SEO on the dynamic routes.
For SPA fallback, in the generate config, define a custom page for SPA fallback:
export default {
generate: {
fallback: "custom_sap_fallbackpage.html"
}
}
Config the fallback page for unknow route in your deployment, for example, in Nginx:
location / {
try_files $uri /custom_sap_fallbackpage.html;
}
nuxt build will build you a SSR site. The html is rendered on the server and sent to the client. It add some work load on the server and maybe is not that easy to deploy, but the main gain is the SEO. And to some users with low end devices or slow internet connection, maybe your site will perform better than depolying in SPA mode.
Basically, you need to consider:
The website's content is static or constantly changing?
nuxt generate for static. nuxt generate or nuxt build or spa mode for sites with dynamic routes.
Do you need SEO?
SPA wouldn't get any SEO.
How you deploy the site?
For static hosting service, only nuxt generate or spa mode will work.
your website is heavy with js code, and you want best performance for user with slow internet and slow devices. Or SEO is important for your site with a lot of dynamic content.
SSR is for you, use nuxt build.
There are three different deployment and generation options in Nuxt.
Universal Mode
In this mode you build your project and then you ship it to a node.js server, the first view is always rendered dynamically on the server and then turns into SPA, and works in the client. That's great for SEO, and for consuming API's but you cannot upload it to any hosting, for example on a shared VPS.
So - Node.js Host is required here.
SPA
Well basically how Vue.js works by default, virtually no SEO at all, you can upload it on a shared VPS hosting, because it's just an index.html and build.js file and it's working entirely on the client-side (in the browser).
We can go for a static hosting here.
Static App
This is where Nuxt.js shines, because this mode will generate an index.html file and the corresponding js/css assets for each route you have in the dist folder, and you can then just take those numerous files, and upload them to any hosting, you don't need a server here, because your first views are already pre-rendered, unlike Universal where the node server should pre-render the first view. So you get SSR here, and your main concert as far as I understand is if you get SPA too, and that's the best part as in Universal mode, after the first request the app continues in SPA mode, how great is that eh?
Anyways there are some things you should take into consideration, that if you want to generate index.html for dynamic content you need to make something that's kinda a mood killer. You need to add this to nuxt-config.js
generate: {
routes: () => {
return [
'/posts/1'
]
}
}
You can also use axios to make http request and return array here. Or even export default array from a file and include it here, where you combine all your dynamic routes. It's a one time job, but if you add new crud in your backend, that would add up 1 more request to run on executing nuxt generate that should be described in nuxt-config.
So that's the reason I would prefer to pay more for a server, but to host a Universal App, instead static generated, because that's the part that doesn't make it really great for consuming API's in my personal opinion, but it is a great future anyways.
when you website update data often you don't need to use build by using npm generate your website static, load fast and SEO friendly for search engine and more secure and if your project has data NuxtJS download all data from database and change data to .json file statically.
if your website load data from the database you must use npm build to load data dynamically from database. use mode "spa" for a single page without client-side rendering or "universal" in nuxt.config.js for client-side rendering.
for dynamic routing use npm build for change route parameters from the database.

Enabling Content-Security-Policy on a minimal web app

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.