你好吗?
我在 ExpressJS 中有一些 CSP 问题。如果我只使用头盔,它不会发生。但是,当我使用带头盔的 cors 包时,浏览器会抛出有关字体的错误。我不明白这个问题。
nodeJS 版本 14.16.1 express 版本 4.17.1 头盔版本 4.6.0 cors 版本 2.8.5
我阅读了有关 cors 和 csp 的文档。所以,我用头盔写了关于 csp 的代码。
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
"script-src": ["'unsafe-eval'"], //development mode should allow 'unsafe-eval' because eval function
"img-src": ["'self'", "data:", "https:"],
"frame-src": "https://www.youtube.com/",
"font-src": ["'self'", "data:", "https:"],
"style-src": [
"'self'",
"'unsafe-inline'",
"https://cdnjs.cloudflare.com",
],
},
}),
);
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap");
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v107/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2)
format("woff2");
}
它没有问题。但是,问题是当我编写有关 cors 的代码时,浏览器会抛出如上图所示的错误。
const whitelist = ["http://localhost:4000", "https://fonts.googleapis.com", "https://fonts.googleapis.com"];
export const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error());
}
},
};
app.use(cors(corsOptions));
我不明白这个问题。我找不到解决方案。
我该如何解决这个问题?
========== 完整代码 =======
import express from "express";
import morgan from "morgan";
import rootRouter from "./router/root.router";
import worshipRouter from "./router/worship.router";
import noticeRouter from "./router/notice.router";
import api from "./router/api.router";
import userRouter from "./router/user.router";
import session from "express-session";
import cookieParser from "cookie-parser";
import MongoStore from "connect-mongo";
import helmet from "helmet";
import { locals, preUrl, corsOptions, csrfProtection } from "./middleWare";
import documentsRouter from "./router/documents.router";
import blogRouter from "./router/blog.router";
import permissionsPolicy from "permissions-policy";
import cors from "cors";
const app = express();
app.use((req, res, next) => {
if (req.get("X-Forwarded-Proto") == "https" || req.hostname == "localhost") {
next();
} else if (
req.get("X-Forwarded-Proto") != "https" &&
req.get("X-Forwarded-Port") != "443"
) {
res.redirect(`https://${req.hostname}${req.url}`);
}
});
app.use(helmet());
app.use(
helmet.contentSecurityPolicy({
useDefaults: true,
directives: {
"script-src": ["'unsafe-eval'", process.env.URL], //development mode should allow 'unsafe-eval' because eval function
"img-src": ["'self'", "data:", "https:"],
"frame-src": "https://www.youtube.com/",
"font-src": ["'self'", "data:", "https:"],
"style-src": [
"'self'",
"'unsafe-inline'",
"https://cdnjs.cloudflare.com",
],
},
}),
);
app.use(
helmet.hsts({
maxAge: 31536000,
preload: true,
}),
);
app.use(helmet.xssFilter());
app.use(
permissionsPolicy({
features: {
fullscreen: ["self", '"https://www.youtube.com"'],
displayCapture: ["self"],
autoplay: [],
camera: [],
},
}),
);
const whitelist = ["http://localhost:4000"];
export const corsOptions = {
origin: (origin, callback) => {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error());
}
},
};
app.use(cors(corsOptions));
app.use(morgan("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
expires: 1000 * 60 * 60 * 24,
httpOnly: true,
secure: true,
store: MongoStore.create({
mongoUrl: process.env.MONGO_URL,
}),
}),
);
app.use(csrfProtection);
app.use(function (err, req, res, next) {
if (err.code !== "EBADCSRFTOKEN") return next(err);
res.status(403).json({ error: "session has expired or tampered with" });
});
app.set("views", process.cwd() + "/src/views");
app.set("view engine", "pug");
app.use("/static", express.static("client"));
app.use("/favicon", express.static("favicon"));
app.use("/uploads", express.static("uploads"));
app.use((req, res, next) => {
req.sessionStore.all((error, sessions) => {
next();
});
});
app.use(locals);
app.use("/", rootRouter);
app.use("/notice", noticeRouter);
app.use("/documents", documentsRouter);
app.use("/blog", blogRouter);
app.use("/user", userRouter);
app.use("/api", api);
export default app;