Content Security Policy for React Apps
- 5 minutes to read
A Content Security Policy (CSP) is an additional layer of security built into most modern browsers. It allows the browser to recognize and mitigate certain types of risks, including Cross Site Scripting (XSS) and data injection attacks. These attacks include, but are not limited to, data theft, page spoofing, and malware distribution.
The CSP defines a list of policies/directives and initial values that specify which resources your site allows/disallows.
To enable CSP, specify a Content-Security-Policy
header or use the <meta>
tag to explicitly define authorized functionality with CSP directives.
The following meta
tag specifies the minimum required directives for the DevExpress Web BI Dashboard:
<head>
<!--...-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self';
img-src data: https: http:;
connect-src 'self' http:my_backend_url;
script-src 'self';
style-src 'self' 'nonce-test-random-value'; "/>
<!--...-->
</head>
Note
We use the test-random-value
placeholder to denote the nonce. You need to generate a unique number for each HTTP request.
default-src 'self';
- Fallback for other fetch directives.
img-src data: https: http:;
- Allows components to load specific images and document pages.
connect-src 'self' 'http:my_backend_url';
- The
my_backend_url
value specifies the server endpoint. This is necessary for applications where the client and server have different URLs. script-src 'self;
- Allows only scripts loaded from the same source as the current page protected with CSP.
style-src 'self' 'nonce-test-random-value';
Allows the use of stylesheets from the same source as the current page protected with CSP and inline styles with the specified nonce. Specify other sources for allowed stylesheets (for example,
https://fonts.googleapis.com/
).Refer to the following section for more information on how to implement a nonce-based CSP: Disallow Inline Styles.
#Disallow Inline Styles (Nonce-Based CSP)
The dashboard control requires the unsafe-inline
source expression for the styles-src
directive since some styles are applied dynamically at runtime.
Use the nonce property to specify the nonce value for the dashboard control:
// ...
function App() {
return (
<div style={{ position : 'absolute', top : '0px', left: '0px', right : '0px', bottom: '0px' }}>
<DashboardControl style={{ height: '100%' }}
endpoint="http://localhost:5000/api/dashboard"
nonce="test-random-value">
</DashboardControl>
</div>
);
}
// ...
Note
We are using the placeholder test-random-value
to denote the nonce. You need to generate a random number, unique for each HTTP request.
Update the <meta>
tag in the index.html file accordingly:
<!--...-->
<head>
<!--...-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self';
connect-src http://localhost:5000/;
img-src data: https: http:;
script-src 'self';
style-src 'self' 'test-random-value'; "/>
</head>
<!--...-->
Some frameworks/build tools also require the unsafe-inline
expression. If the expression is missing, the following error may appear in the browser console: Refused to apply inline style because it violates the following Content Security Policy directive: “style-src ‘self’”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-CNgxrZ5v26epzgS3ZS4Ezqzhyb5CRvs1pkcHTYTK4fI=’), or a nonce (‘nonce-…’) is required to enable inline execution..
To resolve this error, refer to the documentation of the framework or build tool, such as:
#Troubleshooting
#Error: Refused to Evaluate a String as JavaScript
The Dashboard control relies on the Knockout.js library. This library requires a unsafe-eval
expression in the script-src
directive. If the expression is missing, the following error occurs:
Refused to evaluate a string as JavaScript because ‘unsafe-eval’ is not an allowed source of script…
To remove the unsafe-eval
source expression from the script-src
directive, follow the steps below. These steps are specific to applications built with Vite, and may require adjustments depending on your project setup.
Create a src/knockout_global.js file with the following content:
js(function () { window.eval = function (p) { if (p !== "this") { throw new Error("Invalid argument for eval. Only 'this' is allowed."); } return window; }; })();
Reference the created file in the index.html page:
html<!DOCTYPE html> <html lang=""> <head> <!--...--> </head> <body> <div id="app"></div> <script src="/src/knockout_global.js"></script></head> <script type="module" src="/src/main.js"></script> </body> </html>
Note
Application runs in debug mode may require additional permissions. For example, a debug session establishes a Web
#Custom Templates Do Not Work
Custom templates are based on the Knockout JavaScript library. The Knockout library uses the data-bind
attribute to render a value in the following manner — it generates a function as a JavaScript string and passes the string to the new Function
constructor.
To function properly, Knockout templates require the script-src 'unsafe-eval'
CSP directive.
Important
We do not recommend the inclusion of script-src 'unsafe-eval'
directive in your content security policy. This directive may introduce a vulnerability as it enables script execution from a string on your page.
DevExpress components stores JavaScript functions related to data-bind
attributes in the cache, thus eliminating the need to run the script on the page. Our components do not need the ‘unsafe-eval’ directive.
Follow the steps below to use custom templates.
#Call the addToBindingsCache Function
To add a custom template to the function cache, call the addToBindingsCache
function before the component is rendered. You can handle the BeforeRender
event to call the function.
Example: DevExtreme Template
<div data-options="dxTemplate: { name: 'content' }"></div>
Example: Knockout Binding
<div data-bind="text: text, attr: { title: text }"></div>
#Use the CLI Utility
v22.2 ships with our @devexpress/analytics-core-cli
CLI utility package. It includes the processBindings
command. You can use this command to automatically generate a file with the code that calls the addToBindingsCache
function to add your templates to the cache.
Run the following command to install the package:
npm i @devexpress/analytics-core-cli
To process custom templates, execute the following command:
node node_modules/@devexpress/analytics-core-cli/utils/processBindings <templates folder path> <result file path>
Command parameters are as follows:
- templates folder path
- A folder that contains template files (.HTML)
- result file path
- Path to the file being created
When prompted, select application type (Modules or Namespaces):
The generated file contains JavaScript code that must be run in the component’s BeforeRender
event handler.