From 991e64cbc84c6aa7df4e371d0ece31c0415cc619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Varga?= Date: Mon, 9 Dec 2024 09:32:29 +0100 Subject: [PATCH] feat: Enhance CSP implementation and dependencies - **Dependencies**: - Added `@melloware/csp-webpack-plugin` for improved CSP handling. - Introduced `dompurify` for safer DOM manipulation. - Added `trusted-types` to enhance script security. - **Webpack Configuration**: - Replaced custom CSP plugin with `@melloware/csp-webpack-plugin`. - Configured `crossOriginLoading: 'anonymous'` for improved script integrity. - **Caching**: - Updated `Cache-Control` header values to include both `max-age` and `s-maxage` for enhanced caching strategies. - **Other Changes**: - Updated `package.json` and `package-lock.json` to reflect added and updated dependencies. - Integrated stricter CSP policies with subresource integrity. **Impact**: - Strengthens security against XSS attacks. - Optimizes caching and delivery of static assets. - Aligns project with modern web security standards. --- package-lock.json | 223 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 5 +- webpack.config.js | 3 +- 3 files changed, 228 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 635ba48..05028fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,12 @@ "version": "0.2.0", "license": "Apache-2.0", "dependencies": { - "firebase": "^11.0.0" + "dompurify": "^3.2.2", + "firebase": "^11.0.0", + "trusted-types": "^2.0.0" }, "devDependencies": { + "@melloware/csp-webpack-plugin": "^6.0.4", "copy-webpack-plugin": "^12.0.0", "csp-html-webpack-plugin": "^5.1.0", "css-loader": "^7.1.2", @@ -2560,6 +2563,23 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, + "node_modules/@melloware/csp-webpack-plugin": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@melloware/csp-webpack-plugin/-/csp-webpack-plugin-6.0.4.tgz", + "integrity": "sha512-vQTMpWS5zVDqSVGwQb7DjEJ/jrk8RFypkugDcyCf4E2yGX6Ufpi3tSE1RCPhjv5+lOCQt2nli+wsxIhEGv+ETw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio": "^1.0.0-rc.5", + "lodash": "^4.17.20", + "webpack-inject-plugin": "^1.5.5", + "webpack-subresource-integrity": "^5.0.0" + }, + "peerDependencies": { + "html-webpack-plugin": "^4 || ^5", + "webpack": "^4 || ^5" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3408,6 +3428,13 @@ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", "dev": true }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -4200,6 +4227,16 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/bignumber.js": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", @@ -7160,6 +7197,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.2.tgz", + "integrity": "sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -7356,6 +7402,16 @@ "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", "dev": true }, + "node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", @@ -11295,6 +11351,19 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -18029,6 +18098,12 @@ "node": ">= 14.0.0" } }, + "node_modules/trusted-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trusted-types/-/trusted-types-2.0.0.tgz", + "integrity": "sha512-Eam+AUp6lg04YjmYkuLNhEJX+6ByocrKTpY/TtfRK/gV6OmxeN0OwkIasor28SUJ606snArpPLGtPMGbqdaaUA==", + "license": "W3C-20150513" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -18080,6 +18155,13 @@ "node": ">= 0.6" } }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true, + "license": "MIT" + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -18686,6 +18768,34 @@ } } }, + "node_modules/webpack-inject-plugin": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/webpack-inject-plugin/-/webpack-inject-plugin-1.5.5.tgz", + "integrity": "sha512-cYhj/3X6m19zmIEb/Y09/VjCf9SeL+/7Wv6YrUi/wBGFQPFMINEfzHBJV0qokeqvUwE23h8NzrTIrkHALZ9PaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "~1.2.3" + }, + "peerDependencies": { + "webpack": ">=4.0.0" + } + }, + "node_modules/webpack-inject-plugin/node_modules/loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -18710,6 +18820,28 @@ "source-map": "~0.6.1" } }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -20514,6 +20646,18 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, + "@melloware/csp-webpack-plugin": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@melloware/csp-webpack-plugin/-/csp-webpack-plugin-6.0.4.tgz", + "integrity": "sha512-vQTMpWS5zVDqSVGwQb7DjEJ/jrk8RFypkugDcyCf4E2yGX6Ufpi3tSE1RCPhjv5+lOCQt2nli+wsxIhEGv+ETw==", + "dev": true, + "requires": { + "cheerio": "^1.0.0-rc.5", + "lodash": "^4.17.20", + "webpack-inject-plugin": "^1.5.5", + "webpack-subresource-integrity": "^5.0.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -21137,6 +21281,12 @@ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", "dev": true }, + "@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "optional": true + }, "@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -21747,6 +21897,12 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "bignumber.js": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", @@ -23933,6 +24089,14 @@ "domelementtype": "^2.3.0" } }, + "dompurify": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.2.tgz", + "integrity": "sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==", + "requires": { + "@types/trusted-types": "^2.0.7" + } + }, "domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -24100,6 +24264,12 @@ "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", "dev": true }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==", + "dev": true + }, "enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", @@ -27003,6 +27173,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -31809,6 +31988,11 @@ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", "dev": true }, + "trusted-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trusted-types/-/trusted-types-2.0.0.tgz", + "integrity": "sha512-Eam+AUp6lg04YjmYkuLNhEJX+6ByocrKTpY/TtfRK/gV6OmxeN0OwkIasor28SUJ606snArpPLGtPMGbqdaaUA==" + }, "tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -31845,6 +32029,12 @@ "mime-types": "~2.1.24" } }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -32282,6 +32472,28 @@ } } }, + "webpack-inject-plugin": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/webpack-inject-plugin/-/webpack-inject-plugin-1.5.5.tgz", + "integrity": "sha512-cYhj/3X6m19zmIEb/Y09/VjCf9SeL+/7Wv6YrUi/wBGFQPFMINEfzHBJV0qokeqvUwE23h8NzrTIrkHALZ9PaA==", + "dev": true, + "requires": { + "loader-utils": "~1.2.3" + }, + "dependencies": { + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + } + } + }, "webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -32303,6 +32515,15 @@ "source-map": "~0.6.1" } }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, "websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index 07d19d7..bcc7eee 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "homepage": "https://bvarga.dev", "devDependencies": { + "@melloware/csp-webpack-plugin": "^6.0.4", "copy-webpack-plugin": "^12.0.0", "csp-html-webpack-plugin": "^5.1.0", "css-loader": "^7.1.2", @@ -55,6 +56,8 @@ "webpack-dev-server": "^5.0.0" }, "dependencies": { - "firebase": "^11.0.0" + "dompurify": "^3.2.2", + "firebase": "^11.0.0", + "trusted-types": "^2.0.0" } } diff --git a/webpack.config.js b/webpack.config.js index 77861fd..2558b28 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,7 +13,7 @@ const HtmlInlineScriptWebpackPlugin = require('html-inline-script-webpack-plugin const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); const SitemapWebpackPlugin = require('sitemap-webpack-plugin').default; const HtmlNewLineRemoverPlugin = require('./html-new-line-remover-plugin.js'); -const CspHtmlWebpackPlugin = require('./inline-script-csp-html-webpack-plugin.js'); +const CspHtmlWebpackPlugin = require('@melloware/csp-webpack-plugin'); const generateFirebaseJson = require('./generate-firebase-json.js'); const { interpolateName } = require('loader-utils'); const fs = require('fs'); @@ -44,6 +44,7 @@ module.exports = { sourceMapFilename: '[name].[contenthash:8].js.map', chunkFilename: '[id].[contenthash:8].js', clean: true, + crossOriginLoading: 'anonymous', }, module: { rules: [