CSP 配置指南:SpringBoot/Express 实操 + 多域名适配,防 XSS 攻击超简单

🛡️ 普通网站必看!CSP 配置指南:SpringBoot/Express 实操 + 多域名适配,防 XSS 攻击超简单

做普通网站开发时,你是不是总担心这些问题?------ 用户遭遇 XSS 攻击导致信息泄露,页面被注入恶意广告脚本,或者非法 CDN 拖慢加载速度?其实一套合理的CSP(内容安全策略) 就能解决!今天从原理到实战,手把手教你给普通网站配 CSP,还附 SpringBoot、Node.js Express 的完整代码,多域名 + 通配符场景直接抄作业~

一、先搞懂:CSP 到底是啥?普通网站为啥需要它?

CSP(Content Security Policy)简单说就是给浏览器画 "资源白名单" ------ 通过规则指定哪些域名的脚本、图片、样式能加载,哪些不能,本质是限制 "不可信资源" 的执行。

📝 Powered by Moshow 郑锴 | 更多技术干货:https://zhengkai.blog.csdn.net/

对普通网站来说,它的作用太关键了:

  1. 🚫 防御 XSS 攻击:阻断攻击者注入的恶意 JS 脚本,保护用户账号、表单数据等信息
  2. 🚩 拦截恶意资源:禁止加载非法广告、钓鱼链接等资源,避免网站被 "污染"
  3. ⚡ 优化资源加载:只允许可信 CDN 和自有域名加载资源,减少冗余请求,提升页面速度

二、CSP 核心指令:普通网站常用这 6 个,记熟够用

CSP 用 "指令 + 值" 定义规则,普通网站开发高频用到的就这几个,关键信息已加粗:

指令 作用 普通网站常用值示例
default-src 所有资源的 "默认规则"(兜底) 'self'(自身域名)、通用 HTTPS 域名
script-src 限制 JS 脚本来源(防 XSS 核心) 自身域名、可信 CDN(如 jsdelivr)、子域名
img-src 限制图片来源 自身域名、图片 CDN、data:(base64 图)
style-src 限制 CSS 样式来源 自身域名、样式 CDN(如 bootcdn)
font-src 限制字体文件来源 自身域名、字体 CDN
frame-ancestors 限制页面被 iframe 嵌套(防点击劫持) 'self'、可信合作域名(如公司其他网站)

三、框架实操:SpringBoot/Express 配置 CSP(多域名 + 通配符)

这部分是重点!直接给可运行代码,只需替换成你的网站域名和常用 CDN,支持多域名(逗号分隔)和通配符(*.xxx.com),适配普通网站的资源加载场景。

🔧 场景前提

假设你的网站需要加载这些资源:

  • 自有域名:your-site.com(主域名)、*.your-site.com(子域名,如blog.your-site.comcdn.your-site.com
  • 可信 CDN:https://cdn.jsdelivr.net(通用 JS/CSS)、https://cdn.bootcdn.net(前端库)、https://img.abc.com(图片专用 CDN)
1. SpringBoot 版本配置(2 种通用方式)

SpringBoot 推荐用拦截器 (简单通用)或Spring Security(适合有权限控制的网站,如后台管理系统),两种方式都能实现 CSP。

方式 1:拦截器配置(无权限依赖,直接用)
java 复制代码
// 1. 新建CSP拦截器:定义规则并添加响应头
@Component
public class CspInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 🌟 CSP核心规则:多域名+通配符适配普通网站
        String cspPolicy = "default-src 'self' https://cdn.jsdelivr.net; " +
                          "script-src 'self' https://cdn.jsdelivr.net https://cdn.bootcdn.net *.your-site.com; " + // 允许3个可信来源的JS
                          "img-src 'self' https://img.abc.com data: *.your-site.com; " + // 支持base64图片和图片CDN
                          "style-src 'self' https://cdn.jsdelivr.net; " + // 样式仅允许自身和通用CDN
                          "font-src 'self' https://cdn.jsdelivr.net; " + // 字体来源限制
                          "frame-ancestors 'self' https://partner.your-site.com;"; // 允许合作网站嵌套自身页面
        
        // 强制模式:违反规则的资源会被阻断(上线用)
        response.setHeader("Content-Security-Policy", cspPolicy);
        // 测试模式:只上报违规日志,不阻断资源(调试用,需加report-uri)
        // response.setHeader("Content-Security-Policy-Report-Only", cspPolicy + " report-uri /api/csp/log;");
        return true;
    }
}

// 2. 注册拦截器:指定生效的网站路径
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private CspInterceptor cspInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 对网站所有页面生效(可根据需求调整路径,如只给前台加:/front/**)
        registry.addInterceptor(cspInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/api/csp/log"); // 排除CSP日志接口,避免拦截自身
    }
}
方式 2:Spring Security 配置(适合带登录的网站)

如果网站用了 Spring Security 做登录验证,可直接集成 CSP,不用额外写拦截器:

java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated() // 示例:所有请求需登录(根据你的网站权限调整)
            )
            .headers(headers -> headers
                // 启用CSP并配置规则
                .contentSecurityPolicy(csp -> csp
                    .policyDirectives("default-src 'self' https://cdn.jsdelivr.net; " +
                                     "script-src 'self' https://cdn.jsdelivr.net *.your-site.com; " +
                                     "img-src 'self' https://img.abc.com data:; " +
                                     "frame-ancestors 'self';")
                )
                .frameOptions(frame -> frame.sameOrigin()) // 配合防点击劫持
            );
        return http.build();
    }
}
2. Node.js Express 版本配置(用 helmet 中间件,超简单)

Express 推荐用helmet中间件(专门处理安全相关的响应头,包括 CSP),先装依赖,再写配置,3 步搞定。

步骤 1:安装 helmet 依赖
复制代码
# npm或yarn都可以
npm install helmet --save
# 或
yarn add helmet
步骤 2:在入口文件(如 app.js)配置 CSP
javascript 复制代码
const express = require('express');
const helmet = require('helmet');
const app = express();

// 🌟 配置CSP:多域名+通配符适配普通网站
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'", "https://cdn.jsdelivr.net"], // 默认只允许自身和通用CDN
    scriptSrc: ["'self'", "https://cdn.jsdelivr.net", "https://cdn.bootcdn.net", "*.your-site.com"], // JS允许3个可信来源
    imgSrc: ["'self'", "https://img.abc.com", "data:", "*.your-site.com"], // 图片支持CDN、base64、子域名
    styleSrc: ["'self'", "https://cdn.jsdelivr.net"], // 样式来源限制
    fontSrc: ["'self'", "https://cdn.jsdelivr.net"], // 字体仅允许可信来源
    frameAncestors: ["'self'"], // 禁止陌生网站嵌套自身页面(防点击劫持)
    // 测试阶段加:上报违规日志到接口(上线可删除或保留)
    // reportUri: "/api/csp/log"
  }
}));

// 普通网站路由示例(如首页、文章页)
app.get('/', (req, res) => {
  res.send('普通网站首页(CSP已生效)');
});
app.get('/article/:id', (req, res) => {
  res.send(`文章${req.params.id}(CSP已生效)`);
});

// 启动服务
app.listen(3000, () => {
  console.log('Express服务启动:http://localhost:3000,CSP配置已生效');
});

四、普通网站避坑指南:这 4 个错误千万别犯!

  1. ❌ 通配符 "乱用" 导致不安全
  • *.your-site.com只匹配子域名(如blog.your-site.com),不匹配主域名your-site.com),需单独加主域名:your-site.com *.your-site.com
  • script-src别用*(会允许任何网站的 JS,等于没开 CSP),必须指定具体域名;frame-ancestors不支持*,只能写明确域名。
  1. ✅ 别漏了data:/blob:资源如果网站有用 base64 图片(如<img src="data:image/png;base64,...">)或 Blob 视频,必须在img-src/media-src里加data:/blob:,否则资源会被阻断,页面出现 "裂图""无法播放"。

  2. ❌ 保留unsafe-inline导致 XSS 防护失效unsafe-inline允许加载内联脚本(如<script>alert(1)</script>)或内联样式(如<div style="...">),会直接抵消 CSP 的 XSS 防御效果。除非是老项目兼容(实在没办法),否则坚决删除unsafe-inline

  3. ✅ 测试阶段用 "Report-Only" 模式上线前先把Content-Security-Policy换成Content-Security-Policy-Report-Only,这样违规资源不会被阻断,但会把问题上报到reportUri接口,能快速定位漏加的域名,避免影响用户。

五、测试 CSP 是否生效:2 个简单方法(普通网站通用)

  1. 浏览器控制台直接查打开网站页面,按 F12 进入 "控制台"(Console):
  • 如果 CSP 配置成功:没有 "Refused to load the script/style/image..." 的红色错误
  • 如果配置有问题:会提示 "被 CSP 阻止",并显示 "违反的指令"(如script-src漏加域名),按提示补充即可。
  1. 用 "日志接口" 收集问题在测试模式下配置reportUri: "/api/csp/log",然后写一个简单的接口接收日志(如 SpringBoot 的@PostMapping("/api/csp/log")),能收集所有用户端的 CSP 违规情况,适合多页面的大型网站。

六、总结:普通网站 CSP 配置模板(直接抄)

不管是 SpringBoot 还是 Express,普通网站的 CSP 核心规则都可以参考这个模板,只需替换your-site.com为你的实际域名、https://img.abc.com为你的图片 CDN:

复制代码
default-src 'self' https://cdn.jsdelivr.net;
script-src 'self' https://cdn.jsdelivr.net https://cdn.bootcdn.net your-site.com *.your-site.com;
img-src 'self' https://img.abc.com data: your-site.com *.your-site.com;
style-src 'self' https://cdn.jsdelivr.net;
font-src 'self' https://cdn.jsdelivr.net;
frame-ancestors 'self';

最后想问大家:你在普通网站开发中,遇到过 XSS 攻击或恶意资源注入吗?当时是怎么解决的?评论区聊聊~

📝 Powered by Moshow 郑锴 | 更多技术干货:https://zhengkai.blog.csdn.net/

相关推荐
ZHE|张恒3 分钟前
Spring Boot 3 + Flyway 全流程教程
java·spring boot·后端
隔壁阿布都20 分钟前
Spring Boot中的Optional如何使用
开发语言·spring boot·python
floret. 小花3 小时前
idea2025版本设置springboot加载热部署
spring boot
小坏讲微服务8 小时前
Docker-compose 搭建Maven私服部署
java·spring boot·后端·docker·微服务·容器·maven
suuijbd9 小时前
SpringCloud+Netty集群即时通讯项目
spring boot·分布式·spring cloud·java-rabbitmq·java-zookeeper
陈果然DeepVersion10 小时前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(十)
java·spring boot·ai·kafka·面试题·向量数据库·rag
摇滚侠11 小时前
Spring Boot3零基础教程,Reactive-Stream 四大核心组件,笔记106
java·spring boot·笔记
陈果然DeepVersion11 小时前
Java大厂面试真题:Spring Boot+微服务+AI智能客服三轮技术拷问实录(六)
java·spring boot·redis·微服务·面试题·rag·ai智能客服
爱宇阳13 小时前
从容器化到自动化:Spring Boot 项目 Docker 部署与 GitLab CI/CD 集成 Harbor 全流程
spring boot·docker·自动化