Skip to content

Instantly share code, notes, and snippets.

@akkuman
Last active October 25, 2023 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akkuman/593a0ab69e7bfa111eb51f191a067695 to your computer and use it in GitHub Desktop.
Save akkuman/593a0ab69e7bfa111eb51f191a067695 to your computer and use it in GitHub Desktop.
前端项目构建时自动更新csp

先安装 csp-hash

npm install github:apaatsio/csp-hash-from-html
diff --git a/Dockerfile b/Dockerfile
index 7eb74fd7..c35d6945 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,9 +6,13 @@ WORKDIR /app
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global \
PATH=$PATH:/home/node/.npm-global/bin
+# 安装国内镜像
+RUN npm install -g mirror-config-china --registry=https://registry.npmmirror.com
+# 安装 CSP hash 计算工具
+RUN npm install -g github:apaatsio/csp-hash-from-html
+
COPY package*.json ./
-RUN npm install -g mirror-config-china --registry=https://registry.npmmirror.com && \
- npm install
+RUN npm install
COPY . .
RUN npm run build:prod
diff --git a/package.json b/package.json
index e42a38f5..5e22d477 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"private": true,
"scripts": {
"dev": "vue-cli-service serve",
- "build:prod": "vue-cli-service build",
+ "build:prod": "vue-cli-service build && node update_csp.js",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --fix --ext .js,.vue src",
diff --git a/public/index.html b/public/index.html
index 97cb494b..a5276766 100644
--- a/public/index.html
+++ b/public/index.html
@@ -9,6 +9,13 @@
<link rel="stylesheet" href="https://at.alicdn.com/t/font_2776755_qgop6g08bnq.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/font_2950190_s1zn60qmw4r.css">
<meta property="og:image" content="https://greatmessage.688023.cn/logo.png">
+ <% if (htmlWebpackPlugin.options.isProduction) { %>
+ <!-- 在这里放置只在生产环境下生成的标签 -->
+ <meta
+ http-equiv="Content-Security-Policy"
+ content="script-src 'self' bootstrapcdn.com *.bootstrapcdn.com *.jsdelivr.net googleapis.com *.googleapis.com *.dingtalk.com {{CSP_SCRIPT_SRC_SHAS}};"
+ />
+ <% } %>
<meta
name="description"
content="专业的安全信息情报平台"
diff --git a/update_csp.js b/update_csp.js
index e69de29b..d7c4f0ad 100644
--- a/update_csp.js
+++ b/update_csp.js
@@ -0,0 +1,44 @@
+/**
+ * 更新csp script-src sha的脚本
+ */
+const glob = require("glob");
+const fs = require("fs");
+const path = require("path");
+const { execSync } = require("child_process");
+
+const distDir = "./dist";
+
+const globPattern = path.join(distDir, "**/*.html");
+
+function trimString(str, trimStr) {
+ let result = str;
+
+ // 去除开头的指定字符串
+ while (result.startsWith(trimStr)) {
+ result = result.substring(trimStr.length);
+ }
+
+ // 去除结尾的指定字符串
+ while (result.endsWith(trimStr)) {
+ result = result.substring(0, result.length - trimStr.length);
+ }
+
+ return result;
+}
+
+// 计算 csp hash
+const hashResult = execSync(`npx csp-hash -d script-src ${globPattern}`)
+ .toString()
+ .trim();
+const firstSpaceIndex = hashResult.indexOf(" ");
+const shaText = hashResult.substring(firstSpaceIndex + 1);
+
+// 补全 html 中的 csp 策略
+glob.sync(globPattern).map(function(filePath) {
+ const content = fs.readFileSync(filePath, "utf-8");
+ const modifiedContent = content.replace(
+ /\{\{\s*CSP_SCRIPT_SRC_SHAS\s*\}\}/g,
+ trimString(shaText, ";")
+ );
+ fs.writeFileSync(filePath, modifiedContent, "utf-8");
+});
diff --git a/vue.config.js b/vue.config.js
index 2e3ca4a5..46bc6522 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -68,6 +68,7 @@ module.exports = {
config.plugin('html')
.tap(args => {
args[0].title = '天禹漏洞情报平台'
+ args[0].isProduction = process.env.NODE_ENV === 'production'
return args
})
/**
* 更新csp script-src sha的脚本
*/
const glob = require("glob");
const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
const distDir = "./dist";
const globPattern = path.join(distDir, "**/*.html");
function trimString(str, trimStr) {
let result = str;
// 去除开头的指定字符串
while (result.startsWith(trimStr)) {
result = result.substring(trimStr.length);
}
// 去除结尾的指定字符串
while (result.endsWith(trimStr)) {
result = result.substring(0, result.length - trimStr.length);
}
return result;
}
// 计算 csp hash
const hashResult = execSync(`npx csp-hash -d script-src ${globPattern}`)
.toString()
.trim();
const firstSpaceIndex = hashResult.indexOf(" ");
const shaText = hashResult.substring(firstSpaceIndex + 1);
// 补全 html 中的 csp 策略
glob.sync(globPattern).map(function(filePath) {
const content = fs.readFileSync(filePath, "utf-8");
const modifiedContent = content.replace(
/\{\{\s*CSP_SCRIPT_SRC_SHAS\s*\}\}/g,
trimString(shaText, ";")
);
fs.writeFileSync(filePath, modifiedContent, "utf-8");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment