Files
lotteryFront/src/lib/csp-config.ts

108 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Content Security Policy (CSP) 配置
*
* 支持 iframe 嵌入场景,允许主站加载彩票系统
*/
// 允许的主站来源
const ALLOWED_PARENT_ORIGINS: string[] = [
process.env.NEXT_PUBLIC_MAIN_SITE_URL,
process.env.NEXT_PUBLIC_PARENT_ORIGIN,
// 开发环境
"http://localhost:5173",
"http://127.0.0.1:5173",
"http://192.168.0.101:5173",
"http://localhost:3801",
"http://127.0.0.1:3801",
"http://192.168.0.101:3801",
// 生产环境应从环境变量读取
].filter((o): o is string => Boolean(o));
/**
* 生成 CSP 指令字符串
*/
export function generateCSP(): string {
const directives: Record<string, string[]> = {
// 默认只允许同源
"default-src": ["'self'"],
// 脚本允许同源和内联Next.js 需要)
"script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
// 样式允许同源和内联
"style-src": ["'self'", "'unsafe-inline'"],
// 图片允许同源、data URL 和 blob
"img-src": ["'self'", "data:", "blob:"],
// 字体允许同源
"font-src": ["'self'"],
// 连接允许同源和 API 域名
"connect-src": [
"'self'",
process.env.NEXT_PUBLIC_API_URL || "",
// WebSocket 连接
"ws:",
"wss:",
].filter(Boolean),
// 媒体允许同源和 blob
"media-src": ["'self'", "blob:"],
// 对象不允许
"object-src": ["'none'"],
// 框架允许同源和指定父站
"frame-src": ["'self'", ...ALLOWED_PARENT_ORIGINS],
// 允许被嵌入到指定父站
"frame-ancestors": ["'self'", ...ALLOWED_PARENT_ORIGINS],
// 表单提交允许同源
"form-action": ["'self'"],
};
// 构建 CSP 字符串
return Object.entries(directives)
.map(([key, values]) => {
if (values.length === 0) return key;
return `${key} ${values.join(" ")}`;
})
.join("; ");
}
/**
* 检测是否允许被 iframe 嵌入
* @param parentOrigin 父窗口来源
*/
export function isAllowedParent(parentOrigin: string): boolean {
if (ALLOWED_PARENT_ORIGINS.length === 0) return true; // 未配置时允许所有
return ALLOWED_PARENT_ORIGINS.some(
(origin) => origin && parentOrigin.startsWith(origin),
);
}
/**
* 安全头配置(用于 next.config.ts
*/
export const securityHeaders = [
{
key: "Content-Security-Policy",
value: generateCSP(),
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=()",
},
];