Struggling to get the Content Security Policy (CSP) to function properly within Next.js

I have been working on a NextJS project and I am currently facing a challenge in setting up secure headers in the next.config.js file of my project.

I have attempted various solutions found online, but unfortunately, none of them seem to be working for me.

My primary goal is to configure the Content-Security-Policy header to only allow essential resources such as stylesheets, scripts, fonts from fonts.googleapi.com, and images from the public folder of my project.

Despite my efforts, I have not been successful. I even tried setting the header to default-src *, but the website still loads without any styles or fonts applied.

I followed the guidelines provided by NextJS, but I am still unable to make it work. I feel quite lost and confused about the entire process.

index.js

export default function Index() {
    const router = useRouter();

    return (
        <>
            <Center h='100vh'>
                <Box display='flex' flexDirection='column' justifyContent='center'>
                    <Stack spacing='10'>
                        <Box display='inline-block' mx='auto'>
                            <Image w='75px' src="/logo.jpeg" alt="logo" />
                        </Box>
                        {/* Card */}
                        <Box w={['280px', '300px']} borderRadius='lg' border='1px' borderColor='gray.200' shadow='lg' p='6'>
                            <Box textAlign='center'>
                                <Heading size='lg'>
                                    Log in
                                </Heading>
                            </Box>
                            <Box my='6'>
                                <Divider />
                            </Box>
                            <Box>
                                <form>
                                    <Stack spacing='6'>
                                        <Box>
                                            <FormControl>
                                                <FormLabel htmlFor="username">Username</FormLabel>
                                                <Input borderRadius='lg' type="text" id="username" />
                                            </FormControl>
                                        </Box>
                                        <Box>
                                            <FormControl>
                                                <FormLabel htmlFor="password">Password</FormLabel>
                                                <Input borderRadius='lg' type="password" id="password" />
                                            </FormControl>
                                        </Box>
                                        <Box>
                                            <Button w='100%' borderRadius='lg' colorScheme='green'>
                                                Log in
                                            </Button>
                                        </Box>
                                    </Stack>
                                </form>
                            </Box>
                        </Box>
                    </Stack>
                </Box>
            </Center>
        </>
    )
}

next.config.js

const ContentSecurityPolicy = `
    default-src 'self';
    script-src 'self';
    child-src example.com;
    style-src 'self' example.com;
    font-src 'self'; 
`;

const securityHeaders = [
    {
        key: "X-Frame-Options",
        value: "deny"
    },
    {
        key: "X-Content-Type-Options",
        value: "nosniff"
    },
    {
        key: "Referrer-Policy",
        value: "strict-origin"
    },
    {
        key: "Strict-Transport-Security",
        value: "max-age=31536000; includeSubDomains; preload"
    },
    {
        key: "X-XSS-Protection",
        value: "1; mode=block",
    },
    {
        key: "Permissions-Policy",
        value: "camera=(self); battery=(); geolocation=(); microphone=()"
    },
    {
        key: 'Content-Security-Policy',
        value: ContentSecurityPolicy.replace(/\s{2,}/g, ' ').trim()
    }
];

/** @type {import('next').NextConfig} */
const nextConfig = {
    reactStrictMode: true,
    async headers() {
        return [
            {
                source: "/:path*",
                headers: securityHeaders,
            },
        ]
    },
}

module.exports = nextConfig

globals.css

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');

Chrome DevTools https://i.sstatic.net/hihd2.png


Errors after the answer from @tszhong0411 The errors I am getting now are from my service worker for my PWA app.

The red lines are my domain, but I reference them as example.com

https://i.sstatic.net/koUYI.png

Answer №1

If you're looking for an alternative method to configure CSP in Next.js, consider creating a file named _middleware.ts within the "pages" directory.

pages/_middleware.ts

import type { NextFetchEvent, NextRequest } from 'next/server'
import { NextResponse } from 'next/server'

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  const ContentSecurityPolicy = `
    default-src 'self';
    script-src 'self';
    child-src example.com;
    style-src 'self' example.com;
    font-src 'self'; 
  `

  const response = NextResponse.next()

  response.headers.set('Content-Security-Policy', ContentSecurityPolicy.replace(/\n/g, ''))
  response.headers.set('X-Frame-Options', 'deny')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('Referrer-Policy', 'strict-origin')
  response.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload')
  response.headers.set('X-XSS-Protection', '1; mode=block')
  response.headers.set('Permissions-Policy', 'camera=(self); battery=(); geolocation=(); microphone=()')

  return response
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The save feature becomes dysfunctional after switching to the Material-UI dependency in a React project

After integrating the Material-UI dependency into my ReactJS code, I encountered an issue where the "save" functionality no longer works properly. Previously, when editing a task in my simple Todo list app, the new name would be saved successfully. However ...

The Node Express.js app is functioning properly when run locally, but displays the error "Cannot GET /" when running in a Docker container

My Node application has an Express.js server defined like this: const express = require('express') const SignRequest = require('./SignRequest/lambda/index.js') const VerifyResponse = require('./VerifyResponse/lambda/index.js') ...

Converting a floating point number to a 4-byte hex string in JavaScript and reversing the process

I have received a hexadecimal data from the server side that is supposed to be in float format. I am trying to convert these hexadecimals into floats using JavaScript, but so far I have been unable to find a suitable method. Can anyone provide assistance ...

Encountering a 'Backend call failure' issue in a Nextjs application hosted on Azure's static web app

https://i.stack.imgur.com/fjUB7.png We've recently encountered a problem with backend calls failing on our Next.js app. The error message indicates a status of 500 from the server. Despite enabling App Insights, we haven't been able to pinpoint ...

What is the best way to implement a layout across all routes within a subfolder named '/pages'?

In the /pages directory of my (next.js) project, I have created some routes along with a subfolder called /account. My goal is to apply a layout to all pages within the /account subfolder. How can I achieve this without manually applying the layout to eac ...

The JSON.Parse function in Google Apps Script is leading to a 'server connection error' message during debugging

I'm not a professional developer, but I do code occasionally. Currently, I am working on some Apps Script code to interact with an API and store the data in SQL. Most of it is working fine, but I have encountered an issue while debugging in the Apps S ...

The width of Highcharts increases proportionally to the growth of the chart's width

I want to create a highcharts graph where the width increases as data points increase. Currently, I have: I am using vuejs with highcharts, but it should work similarly with jquery or other frameworks. <div class="col-md-6" style= ...

Tips for displaying nested JSON data in an Angular UI grid

I am working with an Angular UI grid where I need to display data from a nested JSON object. The JSON contains a lot of information, but I only want to show a selected set of properties on the grid. Instead of putting the entire json.Products into the grid ...

Establishing a connection to an active process within Winappdriver with the utilization of JavaScript

As someone who is fairly new to working with JS and WinAppDriver, I am currently facing a challenge with testing a Windows-based "Click Once" application built on .Net. To launch this application, I have to navigate to a website through Internet Explorer a ...

What sets declaring variables apart in Vue?

Can you clarify the distinctions among various methods of declaring variables? When should I employ each of these declaration methods? <script> const someVariable = 12345 export default { name: 'App', } </script> <script> e ...

Ways to add values to a database through modal window

There are two buttons on the interface: login and register. Clicking the login button opens the login modal, while clicking the register button should open the register modal. My objective is to validate the form and insert the values into a database aft ...

The placement of the Vuetify tooltip is incorrectly aligned when located in the footer section

Having trouble fixing the issue with the Vuetify tooltip. After scrolling on the page, the tooltip moves up despite using fixed="true". Here is the code snippet causing the problem: <v-footer app inset fixed> <v-row align="center ...

Selenium: The ultimate guide to inserting text within a div element located inside an iframe

Snippet of HTML code: <div class="listRte__editorFrame"> <iframe src="about:blank" style="height: 150px;"> #document <html> <head> <body> ...

Is it true that DOM objects in JavaScript are considered objects?

I've been searching for an official answer to this question, but it seems there is some confusion. Some people consider DOM objects to be JS objects, while others argue that they are different entities. What is the correct answer? If you search on Sta ...

Click on a Marker to automatically zoom to its location using Leaflet mapping technology

I have successfully implemented a feature to display markers on the map from a geojson file. Currently, when I hover over a marker, I can see its properties in a popup. However, I now want to enhance this functionality so that when a user clicks on a mar ...

Revamp the website's design

I am looking to revamp the color theme of my website with just a click of a button. Can someone provide me with a link to a reference website where I can get some inspiration? ...

Indeed, verifying parent.parent access

Currently, I am utilizing the yup module to validate my form. My objective is to access the parent in order to test the value. Below is my schema: enabled: yup.boolean(), contactDetail: yup.object().shape({ phoneNumber1: yup.string().nullable(), pho ...

Adjusting font size in dynamic containers relatively

Imagine we have a slider named .outer, which adjusts its height based on the width of the viewport. Inside this slider, there is an example slide called .inner that contains some text. However, when we shrink the window width, the content in slide .inner s ...

Struggling with implementing conditional validators in Angular2 form models. I have tried using myForm.setValidators(), but it doesn't appear to be functioning as expected

I have been experimenting with the model form in an Ionic/Angular2 project. My goal is to implement conditional validation on a form where users initially fill out 6 required fields, and then choose between 'manual' and 'automatic' proc ...

Is it possible to center-align the text in a Material-ui TextField and enforce a minimum numerical value at the same time?

I'm facing an issue with trying to center align the text inside the TextField and also set a minimum value of 0. It seems like I can only achieve one or the other, but not both simultaneously. I referred to the material-ui page on TextField for help, ...