CSP HTTP header and Meta Tag must be synchronized. There must be two hashes one for hard coded JavaScript other for generated JavaScript tag.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Content Security Policy Demo</title>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; font-src 'self' ; img-src 'self' https://images.unsplash.com ; script-src 'self' 'sha256-B/8L7bCoRRLbK80hqzXcLc/NSWDtHVADDkdElr18Q2U=' 'sha256-BQBWQMByG186hXi3h+x/zUK8eOCr3iy91FDzS9uKCNs='; style-src 'self' https://cdn.jsdelivr.net; frame-src 'self'">
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous"
/>
<script src="node_modules/jquery/dist/jquery.min.js"></script>
</head>
<body>
<script type = "text/javascript" >
$(document).ready(function() {
$('div.grid').after('<div>new element</div>');
});
let newScript = document.createElement("script");
let inlineScript = document.createTextNode("alert('Hello World!');");
newScript.appendChild(inlineScript);
$(document.body).append(newScript);
</script>
<div class="box">
<div class="grid">
<img
src="https://images.unsplash.com/photo-1535089780340-34cc939f9996?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt=""
/>
<img
src="https://images.unsplash.com/photo-1587081917197-95be3a2d2103?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80"
alt=""
/>
<img
src="https://images.unsplash.com/photo-1502248103506-76afc15f5c45?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
alt=""
/>
</div>
</div>
</body>
</html>
server.js
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
app.use(function (req, res, next) {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; font-src 'self' ; img-src 'self' https://images.unsplash.com ; script-src 'self' 'sha256-B/8L7bCoRRLbK80hqzXcLc/NSWDtHVADDkdElr18Q2U=' 'sha256-BQBWQMByG186hXi3h+x/zUK8eOCr3iy91FDzS9uKCNs='; style-src 'self' https://cdn.jsdelivr.net; frame-src 'self'"
);
next();
});
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname)));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/index.html'));
});
const server = app.listen(process.env.PORT || 5500, () => {
const { port } = server.address();
console.log(`Server running on PORT ${port}`);
});
package.json
{
"name": "csp-javascript",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "npx nodemon server.js"
},
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"jquery": "^3.6.0"
},
"devDependencies": {
"nodemon": "^2.0.6"
}
}