内容安全策略(Content Security Policy,简称 CSP)
#前端安全
目录
- 总结
- 1. 定义
- 2. CSP 的工作原理
- 3. CSP 的主要目标
- 4. CSP 指令
- 5. CSP 实现示例
- 6. CSP 的特殊关键字
- 7. CSP 报告
- 8. CSP 的优势
- 9. CSP 的挑战
- 10. CSP 与其他安全措施的结合
- 11. CSP 3 的新特性
总结
- CSP 通过声明一系列内容限制来==告诉浏览器从哪些源加载内容是安全的==
- 这些限制通常通过 HTTP 头部或 meta 标签来实现
- CSP 对 CSRF 的防护能力有限,对 XSS 更有效
- CPS 指令
- 控制 JavaScript、CSS、字体、音视频、iframe 的==源==
- 其他
- CSP 可以配置为仅报告违规,而不实际阻止内容
- 可配置不准使用
eval()
等动态代码执行方法 - 也可配置:控制 Web Worker 的行为
1. 定义
CSP 是一种额外的安全层,用于检测和缓解某些类型的攻击,包括跨站脚本(XSS)和数据注入攻击。
- CSP 对 CSRF 的防护能力有限
2. CSP 的工作原理
CSP 通过声明一系列内容限制来告诉浏览器从哪些源加载内容是安全的。这些限制通常通过 HTTP 头部或 meta 标签来实现。
3. CSP 的主要目标
- 缓解 XSS 攻击
- 防止未经授权的数据注入
- 控制资源加载
- 报告违规行为
4. CSP 指令
CSP 使用多种指令来控制不同类型的资源。以下是一些常见的指令:
default-src
:- 为其他 CSP 指令提供一个默认值
script-src
:- 控制 JavaScript 源
style-src
:- 控制 CSS 源
img-src
:- 控制图片源
connect-src
:- 控制可以通过脚本接口加载的 URL
font-src
:- 控制字体文件源
object-src
:- 控制插件源(如 Flash)
media-src
:- 控制音频和视频源
frame-src
:- 控制框架源
5. CSP 实现示例
5.1. 通过 HTTP 头部
使用
;
分隔开了
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; img-src 'self' https://img.example.com; style-src 'self' 'unsafe-inline';
5.2. 通过 HTML meta 标签
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://trusted.cdn.com; img-src 'self' https://img.example.com; style-src 'self' 'unsafe-inline';">
6. CSP 的特殊关键字
'self'
:- 允许来自同一源的内容
'unsafe-inline'
:- 允许内联脚本和样式
'unsafe-eval'
:- 允许使用
eval()
等动态代码执行方法
- 允许使用
'none'
:- 不允许任何内容
7. CSP 报告
CSP 可以配置为仅报告违规,而不实际阻止内容:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-violation-report-endpoint/
8. CSP 的优势
- 减少 XSS 攻击面
- 控制资源加载,提高安全性
- 提供违规报告机制
- 强制执行最佳安全实践
9. CSP 的挑战
- 可能需要大量的初始配置
- 可能影响某些遗留代码或第三方脚本
- 需要持续维护和更新
10. CSP 与其他安全措施的结合
- 结合 HTTPS 使用以确保策略的完整性
- 与
X-XSS-Protection 头部
一起使用 - 配合
Subresource Integrity (SRI)
使用,进一步验证外部资源
后文有介绍
11. CSP 3 的新特性
- 严格动态代码执行:
'strict-dynamic'
- 外部脚本散列:
- 允许特定的外部脚本
- Worker 支持:
- 控制 Web Worker 的行为
示例代码(使用 Express.js 设置 CSP):
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'https://trusted.cdn.com'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https://img.example.com"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
}
}));
// 其他应用程序代码...
app.listen(3000, () => console.log('Server running on port 3000'));