Appearance
OWASP HTML5 安全指南
概述
本文档整理自 OWASP HTML5 Security Cheat Sheet,涵盖 HTML5 新增安全考量。
主要议题
1. Web Messaging
HTML5 引入 postMessage API 实现跨域通信。
安全建议
javascript
// 接收消息时验证来源
window.addEventListener('message', function(event) {
// 只接受来自信任来源的消息
if (event.origin !== 'https://trusted-site.com') {
return;
}
// 验证数据结构
if (typeof event.data !== 'object') {
return;
}
// 处理消息
processMessage(event.data);
});最佳实践
- 始终验证 origin:使用
event.origin检查消息来源 - 验证数据类型:确保
event.data是预期类型 - 使用 isTrusted:检查事件是否来自用户真实交互
2. Cross-Origin Resource Sharing (CORS)
安全配置
javascript
// 服务器端:只允许信任的来源
app.use((req, res, next) => {
const allowedOrigins = ['https://trusted-site.com', 'https://app.example.com'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
next();
});不要使用
html
<!-- 危险:允许任何来源 -->
<meta http-equiv="Access-Control-Allow-Origin" content="*">3. Local Storage 安全
限制敏感数据
javascript
// 不要在 localStorage 中存储敏感信息
// 敏感数据应该:
// 1. 使用 sessionStorage(会话结束自动清除)
// 2. 使用 HttpOnly Cookie
// 3. 加密后存储
// localStorage 只能存储字符串
localStorage.setItem('userId', '12345');
localStorage.setItem('token', 'xyz'); // 不推荐XSS 防护
javascript
// 读取时转义
function getSafe(key) {
const value = localStorage.getItem(key);
// 转义 HTML 特殊字符
return value
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}4. Web Workers
安全考量
javascript
// 主线程
const worker = new Worker('worker.js');
// 消息传递是拷贝而非引用
worker.postMessage({ data: sensitiveData });
worker.onmessage = function(event) {
console.log('Received:', event.data);
};安全建议
- 不要在 Worker 中执行 DOM 操作
- 验证 Worker 脚本来源
- 限制 Worker 访问的资源
5. SVG XSS
危险示例
html
<!-- 危险:SVG 可能包含脚本 -->
<svg>
<script>alert('XSS')</script>
</svg>安全实践
html
<!-- 使用 Content Security Policy -->
<meta http-equiv="Content-Security-Policy"
content="script-src 'self'">
<!-- 或使用 sanitize 库处理 SVG -->
<script src="DOMPurify.min.js"></script>
<script>
const cleanSVG = DOMPurify.sanitize(dirtySVG);
</script>6. Form Validation
客户端验证
html
<form>
<input
type="email"
required
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
/>
<input type="submit" value="提交" />
</form>服务端验证(必须)
javascript
// 永远不要只依赖客户端验证
app.post('/submit', (req, res) => {
const { email, password } = req.body;
// 服务端验证
if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
return res.status(400).json({ error: 'Invalid email' });
}
if (!password || password.length < 8) {
return res.status(400).json({ error: 'Password too short' });
}
// 处理请求
});7. iframe 安全
sandbox 属性
html
<!-- 最安全的 iframe -->
<iframe
src="https://example.com"
sandbox="allow-scripts allow-same-origin"
referrerpolicy="no-referrer"
></iframe>注意事项
- 不要允许
allow-same-origin+allow-scripts组合 - 使用
sandbox属性限制权限 - 考虑使用
srcdoc而非src
8. Clickjacking 防护
html
<!-- X-Frame-Options 头 -->
<meta http-equiv="X-Frame-Options" content="DENY">
<!-- 或使用 CSP -->
<meta http-equiv="Content-Security-Policy"
content="frame-ancestors 'none'">9. WebSocket 安全
javascript
// 使用 WSS(WebSocket Secure)
const ws = new WebSocket('wss://secure-site.com/ws');
// 验证 WebSocket 消息来源
wss.on('connection', (ws, req) => {
const origin = req.headers.origin;
if (!allowedOrigins.includes(origin)) {
ws.close();
return;
}
// 处理连接
});