CSP block Google Tag Manager in NextJs still using nonce - reactjs

I am using google tag manager in my project, but when I add the CSP, it blocks GTM.
CSP:
default-src https: http: 'strict-dynamic' 'nonce-{NONCE-KEY}' 'unsafe-inline' 'self' https://www.googletagmanager.com;
Code:
<Html lang='es'>
<Head nonce='{NONCE-KEY}'>
<script
nonce='{NONCE-KEY}'
aria-hidden='true'
dangerouslySetInnerHTML={{
__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;var n=d.querySelector('[nonce]');
n&&j.setAttribute('nonce',n.nonce||n.getAttribute('nonce'));f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${GTM_ID}');`,
}}
/>
</Head>
<body aria-label='Cargando'>
<noscript
aria-hidden='true'
dangerouslySetInnerHTML={{
__html: `<iframe src="https://www.googletagmanager.com/ns.html?id=${GTM_ID}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
}}
/>
<Main />
<div id='tooltip' />
<NextScript nonce='{NONCE-KEY}' />
</body>
</Html>
Error:
According to the documentation adding only nonce should work, as I don't want to add the 'unsafe-eval' directive to my CSP for security reasons.

It is not clear from your error message whether it is caused by GTM or some other script. However 'unsafe-eval' is required for GTM only when custom JavaScript variable names are used in the "Custom HTML tags".
To get rid of 'unsafe-eval' you can use custom templates instead of custom JavaScript variable names.
Never use strict Content Security Policy based on the default-src directive because it leads to fatal security consequences in Firefox.

Related

React app hosted on IPFS gives "default-src 'self'". 'connect-src' was not explicitly set, so 'default-src' is used as a fallback error

I have a react app here https://github.com/ChristianOConnor/spheron-react-api-stack. I'm trying to host it on IPFS. I deployed this with 2 main steps: 1) cd frontend, npm run build and 2) upload the build folder to pinata.cloud. Before it works on IPFS I had to make a few changes such as converting the paths in the manifest.json to include a ./, for example I changed "main.js": "/static/js/main.HASH_HERE.js", to "main.js": "./static/js/main.HASH_HERE.js". But 1 problem still remains.
The react site loads just fine.
But when I click the "click this to call API" button, I get this in my console.
The error is: Refused to connect to 'https://<MY API'S DOMAIN NAME>/hello' because it violates the following Content Security Policy directive: "default-src 'self'". Note that App.tsx: 17 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.
I tried to fix this with a meta tag in the index.html file created in the root of the build directory. It looks like this now:
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; connect-src https://<MY API'S DOMAIN NAME>/hello" />
<meta charset="utf-8" />
<link rel="icon" href="./favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="./logo192.png" />
<link rel="manifest" href="./manifest.json" />
<title>React App</title>
<script defer="defer" src="./static/js/main.<HASH HERE>.js"></script>
<link href="./static/css/main.<HASH HERE>.css" rel="stylesheet">
</head>
Notice <meta http-equiv="Content-Security-Policy" content="default-src 'self'; connect-src https://<MY API'S DOMAIN NAME>/hello" /> in the above code. I re-deployed this build folder to IPFS and got exactly the same error when I clicked the "click this to call API" button. So what am I doing wrong? I added default-src and connect-src to the meta tag.
The problem is likely that another Content-Security-Policy is set in a response header by another component. Adding another CSP in a meta tag can only make the total policy stricter. You will need to identify where the header is being set and modify or remove that header, not add a meta tag.

How to Add html in React

I'm starting to learn reactjs at the moment. I'm wondering how to add normal HTML-Tags in a react-app. Is i just possible to add them by using the render function or can I also just write normal HTML-Tags in my index.html file?
Cause when I'm doing so they're not displayed.
Just like:
const myelement = (<h1>some element</h1>);
ReactDOM.render(myelement, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div>
<div id="root"></div>
<div>just normal html</div>
</div>
Well, it works just fine here.. so there must be something wrong with my build..
If you're starting out, I recommend you bootstrap your apps using npx create-react-app. It'll give you a good sense of what a React app could look like, and some pointers for file structure.
Most React apps have an index.html file, which you can use like any normal HTML file. But, for the majority of your app, it's recommended to write your content in JSX (otherwise, you aren't getting the benefits of using React in the first place).
JSX
JSX looks very similar to regular HTML, with a handful of key differences:
Tag attributes tend to be in lowerCamelCase (onChange rather than onchange)
Instead of class (which is a reserved keyword in JavaScript), you need to use className
An Example Component
I've borrowed this sample code from React's official tutorial, which you should definitely check out if you haven't already.
This is a class Component, and your JSX goes inside of the render method:
import React from 'react';
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
What goes in index.html?
The only essential part of index.html is a <div id="root"></div>, which React will use to append the rest of the JSX.
This is also the place to add the usual metadata and icons.
As an example, here's the index.html file that comes with create-react-app. For most of my projects, I leave this pretty-much as-is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
In any given React component, there can only be one parent/top layer html element. You can get around this by using <React.Fragment> ...the rest of your html ... </React.Fragment> (or <>...</> depending on your version) or simply add a wrapping <div> around everything. JSX doesn't distinguish between "normal" html and "React" html, it just turns the React stuff into normal html (over simplification, but close enough for this question). Try it again and let me know if you encounter any problems.
const reactElement = (
<div>
React stuff
</div>
);
ReactDOM.render(
reactElement,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div>
<div id="root">
</div>
<div>
just normal html
</div>
</div>

Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”) firefox webextensions

Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
Get this error to in console when trying to add onclick event to button in sidebar
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id = "content"></div>
<script src="panel.js"></script>
<button id="createNewInstance" onclick="openDb()">New Category</button>
</body>
</html>
why is that?
You can't use inline scripts or define event handlers in WebExtension pages. You have to add your event handler in an external JavaScript file.
panel.js
document.getElementById("createNewInstance").addEventListener("click", openDb)

Why are the DOM plain html elements rendered only after my Angular APP is done loading?

I am trying to display a plain html/css loading spinner on first load in my Angular APP. The spinner code is included in my index.html.
However, the dom seems not to be rendered until my angularjs APP starts kicking in, causing a very lengthy display of a white screen until this finally happens. Is there any way to prevent that?
I would like to understand how to load my plain html/css spinner right after the css code in the head is done loading so as to improve user experience.
Test on webpagetest.org seem to confirm this diagnosis (the /settings, /introductions, /menus lines are all calls to an external API done by an AngularJS service before render):
Here is a simplified version of my build code:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<title ng-bind="($title || 'Home') + ' - WalktheChat'">WalktheChat</title>
<link rel="stylesheet" href="styles/lib.css">
<link rel="stylesheet" href="styles/app.css">
</head>
<body>
<div id="base-container" ng-controller="Shell as main">
<div ng-include="'app/layout/header.html'"></div>
<div id="content" ui-view ng-cloak autoscroll="true"></div>
<div ng-include="'app/layout/footer.html'"></div>
</div>
<!-- This is the spinner I would like to display on first load -->
<div ng-show="::false" class="spinner-container">
<div class="spinner sk-spinner sk-spinner-pulse"></div>
</div>
<script src="js/lib.js"></script>
<script src="js/app.js"></script>
</body>
</html>
whatever the complexity of your application,all your controllers are within the same angular application, all scopes within the same application inherits from the same root, whatever you define on the $rootScope will be available to all child scopes.
we have two ways to resolve this problem:
use $broadcast(), $emit() and $on() that facilitate event driven publisher-subscriber model for sending notifications and passing data between your controllers.(professional solution)
declare $rootScope variable and watching changement.(simple way)
It turns out the problem was coming from "render-blocking javascript", I had to add the "async" tag to my JS to fix it.
When adding async to both my lib.js and app.js, I had an issue with app.js loading before angular scripts were loaded (thus causing the APP to throw an error). In order to solve this issue, I combined my lib.js and app.js into one single file and then added the async tag.
My final build code looks like that (the magic happens on the final "script" tag):
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<title ng-bind="($title || 'Home') + ' - WalktheChat'">WalktheChat</title>
<link rel="stylesheet" href="styles/lib.css">
<link rel="stylesheet" href="styles/app.css">
</head>
<body>
<div id="base-container" ng-controller="Shell as main">
<div ng-include="'app/layout/header.html'"></div>
<div id="content" ui-view ng-cloak autoscroll="true"></div>
<div ng-include="'app/layout/footer.html'"></div>
</div>
<!-- This is the spinner I would like to display on first load -->
<div ng-show="::false" class="spinner-container">
<div class="spinner sk-spinner sk-spinner-pulse"></div>
</div>
<!-- This app.js now also contains lib.js from my question !-->
<script src="js/app.js" async></script>
</body>
</html>

Serving default index.html page when using Angular HTML5mode and Servicestack on the backend

I am new to ServiceStack and Angular. Apologies if this is verbose.
with reference to Html5 pushstate Urls on ServiceStack
I would like to be able to have my api service served up from the root. ie http://mydomain.com/
If a user browses the route, I would like to serve up a default html page that bootstraps my angular app.
In the the app itself if angular calls mydomain.com/customer/{id} json should be served but if this is browsed directly it should serve the default html page and keep the url but the route in the service method does not need to be called. as this will be resolved by angular which will call the customer service itself for a json result.
There are probably a few different ways to make this work, as long as you don't need to support html5mode urls. I have hope that I'll be able to leverage this code to eventually support html5mode, but at the moment, I've resigned myself to hash based URLs.
Given urls like: http://example.com/ or http://example.com/#/customer/{id}, here's how to bootstap an angularjs single page app on a self-hosted servicestack project from the root of the domain.
To enable the markdown razor engine, add this to your AppHost config (not absolutely necessary, but my preference over the default razor engine):
Plugins.Add(new RazorFormat());
Place a file, default.md, in the root of your project, and ensure it's properties are "content/copy when newer". Put whatever content you want in there. The important thing is to assign the template file. (If you're using the default razor engine, an equivalent default.cshtml file should also work, but I've never tried it. ) The template file is what will bootstrap your angularjs app. This is what I have in my default.md:
#template "Views\Shared\_Layout.shtml"
# This file only exists in order to trigger the load of the template file,
# which bootstraps the angular.js app
# The content of this file is not rendered by the template.
My _Layout.shtml file looks like this (omitting irrelevant details). Note ng-app in the html tag, and the ng-view div in the body. Also note that I don't include <!--#Body--> in the file. I'm not using server side templates for this project.
<!DOCTYPE html>
<html lang="en" ng-app="MyApp">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="Content/css/app-specific.css"/>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<!-- Navbar goes here -->
<div class="container">
<header id="header">
<!-- Header goes here -->
</header>
<div ng-view></div>
<hr>
<footer id="footer">
<!-- Footer goes here -->
</footer>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="/Scripts/app-specific/app.js?3ba152" type="text/javascript"></script>
<script src="/Scripts/app-specific/app-services.js?3ba152" type="text/javascript"></script>
<script src="/Scripts/app-specific/app-controllers.js?3ba152" type="text/javascript"></script>
</body>
</html>

Resources