TypechoJoeTheme

至尊技术网

统计
登录
用户名
密码

如何构建安全的JavaScript转义函数防御XSS攻击

2025-08-19
/
0 评论
/
26 阅读
/
正在检测是否收录...
08/19


一、XSS攻击的本质与防御层次

去年某社交平台因未过滤用户输入导致大规模XSS蠕虫传播,造成数百万用户数据泄露。这再次印证了前端安全防护的重要性。XSS攻击的本质是攻击者通过注入恶意脚本破坏页面DOM结构,传统防御存在三大盲区:

  1. HTML上下文:未转义的尖括号会生成新节点
  2. 属性上下文:未处理引号导致属性逃逸
  3. JavaScript上下文:字符串拼接直接执行代码

javascript // 典型漏洞示例 document.getElementById('output').innerHTML = '<a href="' + userInput + '">点击</a>';

二、上下文感知的转义体系

2.1 HTML实体编码

采用双重编码策略应对不同场景:
javascript function escapeHTML(str) { const div = document.createElement('div'); div.appendChild(document.createTextNode(str)); return div.innerHTML .replace(/"/g, '&quot;') .replace(/'/g, '&#39;'); }

注意:此实现避免使用正则替换,利用DOM API自动处理所有特殊字符

2.2 属性值编码

针对HTML/URL属性需要差异化处理:
javascript function escapeAttribute(str) { return escapeHTML(str) .replace(/%/g, '%25') // URL编码保留 .replace(/\+/g, '%2B'); }

2.3 JavaScript字符串编码

采用JSON序列化+截断防御:
javascript function escapeJS(str) { return JSON.stringify(str.toString()) .slice(1, -1) .replace(/\//g, '\\/'); }

三、进阶防御方案

3.1 基于白名单的DOM净化

javascript
const ALLOWED_TAGS = { a: ['href', 'title'], span: [] };

function sanitizeHTML(html) {
const doc = new DOMParser().parseFromString(html, 'text/html');
const nodes = doc.body.childNodes;

return Array.from(nodes).map(node => {
if (!ALLOWED_TAGS[node.tagName]) return '';

const attrs = Array.from(node.attributes)
  .filter(attr => ALLOWED_TAGS[node.tagName].includes(attr.name))
  .map(attr => ` ${attr.name}="${escapeAttribute(attr.value)}"`);

return `<${node.tagName}${attrs.join('')}>${sanitizeHTML(node.innerHTML)}</${node.tagName}>`;

}).join('');
}

3.2 CSP策略兜底

即使转义失败,内容安全策略可作为最后防线:
http Content-Security-Policy: default-src 'self'; script-src 'unsafe-inline' 'unsafe-eval'; style-src 'self' https://cdn.example.com;

四、实战检验方案

通过单元测试验证防御效果:javascript
describe('XSS防御测试', () => {
it('应阻断脚本注入', () => {
const malicious = '';
expect(escapeHTML(malicious)).not.toContain('  湘ICP备2023005853号  RSS MAP