XSS(跨站脚本攻击)长期占据 OWASP Top 10 的显著位置,而 Content Security Policy(CSP)是浏览器层面抵御 XSS 最有力的防线之一。本文将结合 XSS 的常见攻击方式与前端防御思路,深入讲解 CSP 的实战配置,并延伸讨论 SQL 注入防护与 Linux 服务器安全加固,帮助开发者构建纵深防御体系。
一、XSS 的常见方式与前端防御
XSS 的本质是攻击者将恶意脚本注入到页面中,使浏览器在受害者的上下文中执行。常见类型包括:
- 存储型 XSS:恶意脚本被持久化到数据库(如评论区),所有访问该页面的用户都会中招。
- 反射型 XSS:恶意脚本通过 URL 参数传入,服务器将其直接回显到页面中。
- DOM 型 XSS:前端 JavaScript 直接将不可信数据写入 DOM,如
innerHTML、document.write。
前端防御的核心原则是 “永不信任用户输入”:
- 输出编码:根据输出位置(HTML、属性、JS、URL)进行对应编码。
- 使用安全的 DOM API:优先使用
textContent而非innerHTML,使用setAttribute而非字符串拼接。 - 输入验证与白名单:对 URL、富文本等做严格过滤。
- CSP:即便前几层被绕过,CSP 也能限制脚本执行来源,成为最后一道防线。
二、CSP 是什么
CSP 通过 HTTP 响应头 Content-Security-Policy 告诉浏览器:哪些资源可以加载、哪些脚本可以执行。它本质上是一份白名单策略。
一个基础的 CSP 头如下:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'none';
关键指令说明:
default-src 'self':默认只允许同源资源。script-src:限制脚本来源,禁止内联脚本(不写'unsafe-inline')。object-src 'none':禁用 Flash 等插件,防止绕过。base-uri 'self':防止<base>标签劫持相对路径。frame-ancestors 'none':防止点击劫持。
三、CSP 实战配置策略
1. 从 Report-Only 开始
直接上线严格 CSP 可能导致页面崩溃。建议先用 Content-Security-Policy-Report-Only 观察违规:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
收集一段时间报告后,再逐步收紧策略。
2. 消除内联脚本
CSP 最大的痛点是内联脚本。解决方案:
- 将
<script>内容外移到.js文件。 - 对必须内联的脚本使用 nonce:
<script nonce="random-value">
// 内联脚本
</script>
响应头中:
script-src 'nonce-random-value' 'strict-dynamic';
'strict-dynamic' 允许被信任脚本动态加载的子脚本,现代浏览器推荐使用。
3. 避免 unsafe-inline 与 unsafe-eval
'unsafe-inline' 会让 CSP 形同虚设。若确实需要内联样式,可用 style-src 'self' 'unsafe-inline' 但应尽量避免。eval()、new Function() 等动态执行也应禁用。
4. 结合后端模板
在服务端渲染时,为每个请求生成随机 nonce,并注入到模板中。例如 Node.js + Express:
app.use((req, res, next) => {
res.locals.nonce = crypto.randomBytes(16).toString('base64');
res.setHeader(
'Content-Security-Policy',
`script-src 'nonce-${res.locals.nonce}' 'strict-dynamic'`
);
next();
});
四、CSP 不是银弹
CSP 能大幅降低 XSS 风险,但无法覆盖所有场景:
- 老版本浏览器兼容性有限。
- 配置不当(如通配符
*)会留下漏洞。 - 无法防御服务端漏洞导致的敏感数据泄露。
因此,CSP 必须与其他防御手段配合使用。
五、延伸:MySQL 防止 SQL 注入的几种写法
SQL 注入与 XSS 同属注入类漏洞,防御核心是 参数化查询:
- 预处理语句(推荐):
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
- 使用 ORM:如 Laravel Eloquent、Hibernate,自动转义参数。
- 最小权限原则:数据库账号仅授予必要权限。
- 输入验证:对类型、长度、格式做校验,但不可替代参数化。
切忌字符串拼接 SQL,也不要依赖 addslashes 等手工转义。
六、Linux 服务器安全加固清单
服务器是应用的最后一道屏障,建议定期检查:
- 更新补丁:
apt update && apt upgrade或yum update。 - SSH 加固:禁用 root 登录、改用密钥认证、修改默认端口、使用
fail2ban。 - 防火墙:仅开放必要端口,使用
ufw或iptables。 - 最小化服务:卸载无用软件,关闭不必要端口。
- 日志审计:启用
auditd,集中收集日志。 - 文件权限:敏感文件设置
600,目录750。 - 定期备份:离线备份并验证可恢复性。
七、总结
CSP 是抵御 XSS 的重要武器,但它的价值在于 纵深防御 中的一环。前端做好输出编码与安全 DOM 操作,后端使用参数化查询防止 SQL 注入,服务器层面持续加固,三者结合才能构建真正健壮的 Web 安全体系。从今天开始,为你的站点加上 CSP 报告头,迈出安全加固的第一步。
未经允许不得转载:任鹏个人博客 » Content Security Policy 实战:用 CSP 降低 XSS 风险


朋友圈点赞图在线生成源码