<代表“)过滤特殊文字,将易冲突的字符转为无害形式
使用HTML实体编码(推荐)
通过将特殊字符转换为对应的实体引用,可使其被浏览器安全显示而不会被识别为代码。
<→<>→>&→&- →
" - →
'
| 原始字符 | 实体编码 | 说明 |
|---|---|---|
| < | < | 小于号 |
| > | > | 大于号 |
| & | & | 与符号 |
| " | 双引号 | |
| ' | 单引号 |
适用场景:动态生成用户输入内容时(如评论区),需转义后再插入到HTML标签内,若用户提交了包含<script>alert('xss')</script>,经过实体编码后会变为<script>alert('xss')</script>,此时浏览器仅会显示文本而非执行脚本。
优点:兼容性强,符合W3C标准;无需依赖第三方库。
缺点:手动替换较繁琐,建议结合后端语言工具自动处理(如Python的html模块)。
移除危险标签与属性
对于富文本编辑场景,允许部分格式但禁止脚本行为时,可通过正则表达式或DOM解析器删除高风险元素:
- 剥离所有标签:仅保留纯文本内容,例如用正则表达式
/<[^>]+>/g匹配并替换为空字符串,但此方式可能误删合法内容(如下拉菜单的<select>)。 - 白名单机制:只保留安全的标签及属性集合,例如允许
<p>,<b>,<i>等无害标签,同时过滤掉onclick,style等潜在危险属性。
示例代码片段(伪代码):
function stripUnsafeTags(html) {
const allowedTags = ['p', 'br', 'span'];
const doc = new DOMParser().parseFromString(html, 'text/html');
let elements = doc.getElementsByTagName('');
for (let el of elements) {
if (!allowedTags.includes(el.tagName.toLowerCase())) {
el.parentNode.removeChild(el);
}
}
return doc.body.innerHTML;
}
注意事项:需测试不同浏览器下的兼容性,优先选择成熟的库(如OWASP Java HTML Sanitizer)。
服务器端预处理
在数据存入数据库前进行清洗,适用于从源头控制内容安全:
- PHP中使用
htmlspecialchars()函数自动转义特殊字符; - Java可调用Apache Commons Lang的
StringEscapeUtils.escapeHtml4(); - Python推荐使用bleach库实现精细化策略配置。
对比实验:同一输入"Hello <b>world!</b>"在不同语言中的处理结果均为<b>world!</b>,证明跨平台一致性。
CDATA区块隔离解析
当需要在XML/HTML文档中嵌入代码片段时,可用<![CDATA[...]]>,告知解析器忽略内部的特殊符号,不过该方案仅适用于外部载体本身支持CDATA的情况(如RSS Feed生成)。
局限性:HTML5标准已不再支持CDATA语法,可能导致新旧浏览器行为差异。
实战案例分析
假设某论坛存在以下破绽:用户头像上传功能未限制文件类型,攻击者构造名为shell.jpg实则为PHP脚本的文件,并通过CSS背景图方式执行反面代码,修复方案应包括:
- 文件扩展名白名单校验;
- 对EXIF元数据中的UTF-8注释进行实体编码;
- 设置响应头的
Content-Type: image/jpeg强制浏览器按图片解析。
此例表明,单纯的前端过滤不足以防御多层攻击向量,必须采用纵深防御策略。
常见误区警示
过度依赖客户端验证:即使做了前端过滤,仍需重复后端校验,因浏览器调试工具可轻易绕过限制。
全盘信任innerText属性:某些浏览器实现可能存在Unicode混淆破绽,建议二次编码处理。
忽视编码声明的影响:若页面使用非UTF-8字符集,可能出现乱码导致的意外解析问题。
FAQs
Q1: 如果我只想允许用户使用加粗和斜体效果该怎么办?
A: 建立白名单机制,仅保留<b>, <i>标签及其闭合形式,同时移除其他所有标签,推荐使用专有库如DOMPurify配置策略:{allowedTags: ['b', 'i'], disallowedAttributes: []}。
Q2: 为什么转义后的HTML源码看起来有很多乱码?
A: 这是正常现象,实体编码本质是用ASCII范围内的可打印字符替代控制字符,开发者工具通常会可视化呈现这些符号(如显示为尖括号而非<),实际渲染时浏览器会自动还原为原始样式,若需人类可读的调试视图,可在开发环境启用“查看
