最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
HTML国际化如何安全?过滤机制工程化规范
时间:2026-07-10 12:08:52 编辑:袖梨 来源:一聚教程网
不能用strip_tags()做国际化HTML过滤,因为它不校验属性、协议、嵌套结构和大小写,会放行onclick、javascript:等危险内容,且无法处理动态插值、实体编码冲突及多语言语义属性(如lang/dir),导致XSS漏洞。
为什么不能用 strip_tags() 做国际化 HTML 过滤
很多团队在做多语言富文本时,误以为 strip_tags($html, '<p><strong><em>') </em></strong></p> 就够了——它确实能留下标签,但完全不管属性、事件、协议和嵌套结构。比如用户提交:<p onclick="alert(1)">Hello</p>,strip_tags() 会原样保留 onclick;又比如 <a href="javascript:alert(1)">click</a>,链接照样可执行。
更麻烦的是国际化场景常含动态插值(如 "<b>{name}</b> logged in"),若插值前未净化,恶意内容直接注入 DOM;若插值后净化,又可能破坏已转义的实体(如把 © 变成 ©)。
- 它不解析 DOM,无法识别注释、CDATA、自闭合标签中的陷阱
- 对大小写不敏感(
<SCRIPT>逃逸) - 不校验 URI 协议,
data:、vbscript:、javascript:全部放行 - 无法处理嵌套 XSS,例如
<img src=x onerror=alert(1)>在<div>内仍生效
DOMPurify 白名单配置必须显式声明协议与属性
前端做国际化渲染时,DOMPurify 是唯一靠谱选择,但默认配置不安全。必须显式限制协议、禁止危险属性,并适配多语言常见需求(如支持 lang、dir、title 等语义属性)。
示例配置(支持中/英/日/阿语等多语言排版):
立即学习“前端免费学习笔记(深入)”;
const config = { ALLOWED_TAGS: ['p', 'br', 'b', 'i', 'u', 'em', 'strong', 'span', 'a', 'code', 'sub', 'sup'], ALLOWED_ATTR: ['href', 'title', 'lang', 'dir', 'class'], // 显式放开 dir="rtl"、lang="ar" 等 FORBID_ATTR: ['onerror', 'onclick', 'onload', 'javascript:', 'data-*'], FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'style', 'noscript'], ALLOWED_URI_REGEXP: /^https?:///i, // 强制 http(s)://,拒绝 javascript: 或 mailto:(除非明确需要) KEEP_CONTENT: true};
注意:ALLOWED_URI_REGEXP 比 ALLOWED_PROTOCOLS 更可靠,后者在某些版本里有绕过漏洞;lang 和 dir 必须进 ALLOWED_ATTR,否则多语言文本会丢失语义。
后端净化不可省略,且必须与前端配置严格对齐
国际化内容常由 CMS 或翻译平台批量导入,前端 JS 可被绕过,所以服务端必须做同等强度净化。PHP 项目应使用 HTMLPurifier,并确保配置与前端白名单完全一致——不是“类似”,而是字段级对齐。
关键配置项(PHP):
$config = HTMLPurifier_Config::createDefault();$config->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title|lang|dir],br,span[lang|dir|class]');$config->set('URI.AllowedSchemes', ['http', 'https']); // 不要漏掉 https$config->set('Attr.AllowedFrameTargets', []); // 禁用 target="_blank"(除非加 rel="noopener")$config->set('HTML.Trusted', false); // 关键!禁用可信模式,否则 script 可能复活$purifier = new HTMLPurifier($config);
常见坑:
- 没设
HTML.Trusted = false→style标签可能被放行 - 前端允许
lang,后端没放开 → 多语言<span lang="ja">こんにちは</span>被删 - 前后端
ALLOWED_URI_REGEXP/URI.AllowedSchemes不一致 → 某些链接在预览时正常,上线后 403 或被截断 - 入库前净化一次,渲染前又调一次 → 实体重复编码(
→)
插值环节最容易被忽略的安全断裂点
国际化框架(如 i18next、vue-i18n)常提供 HTML 插值语法:t('welcome', { name: '<b>admin</b>' })。这里 name 若来自用户输入,且未提前净化,就等于把 XSS 直接塞进模板。
正确做法只有两种:
- 所有变量在传入
t()前,必须经DOMPurify.sanitize()处理(前端)或$purifier->purify()(后端) - 禁用 HTML 插值,改用纯文本占位 + 客户端 DOM 构建(如
<span data-i18n="welcome"></span>+ JS 注入安全节点)
绝对不要做:先插值再净化整个字符串——因为 t() 返回的已是带标签的 HTML,再跑一遍 DOMPurify 可能破坏原有结构(比如把 <b>{name}</b> 中的 {name} 当作文本节点误删)。
多语言 JSON 文件本身也要扫描:CI 流程中加入正则检测(如 /onw+s*=/i、/javascript:/i),防止翻译人员误填恶意内容。
相关文章
- 死亡搁浅2全部34个武器的解锁方法条件是什么 07-17
- 星塔旅人全部角色特殊回忆触发条件方式合集 07-17
- Palia帕利亚1.12至1.18村民需求物品清单大全 07-17
- 舒舒服服小岛时光全部魔法种子分布详情图 07-17
- 创造与魔法坐骑类饲料配方制作所需材料 07-17
- 喵妃APP官方正版下载 - 2026最新漫画阅读平台 07-17