首页/开发/正则与编码速查/归一化引发的安全绕过问题

归一化引发的安全绕过问题

归一化引发的安全问题来自「校验与使用不是同一个字符串」:攻击者用同形不同码点的字符(组合标记、兼容字符、视觉相似字符)绕过黑名单或伪造重复账号,防御要点是在归一化之后统一校验。

正则与编码速查开发更新于 2026-10-17
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌​‌‌‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌​‌​​‌​‌‌‌‌​‌​​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​‌​‌​‌‌​​​‌‌​‌‌‌​‌​‌​‌‌‌​​‌​​‌‌​‌​​‌​‌‌‌​‌​​​‌‌‌‌​​‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌‌​​‌‌​‌‌‌​​‌‌​‌‌‌​‌​‌​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

三类绕过手法

第一类是形式差异绕过:同一可见内容存在规范或兼容等价的多种码点写法,过滤器只识别其中一种。第二类是视觉相似字符:用西里尔字母、希腊字母或相似形状字符伪装成标准字符,构造看起来完全相同的账号名或域名。第三类是控制与格式字符:零宽字符、双向控制符插入后肉眼不可见,却会改变比较与显示顺序,用于隐藏恶意内容或破坏审计。这三类都能用「先归一化、再校验、再使用」的顺序加上显式字符白名单来约束。

基本信息

根因校验对象与最终使用对象不一致
手法一规范或兼容等价的形式差异(不同码点,同形)
手法二视觉相似字符(不同脚本的相似字形)
手法三不可见控制与格式字符
防御顺序归一化 → 字符白名单/黑名单校验 → 使用
配套手段唯一约束用折叠值、显式拒绝格式字符、日志记录原始码点

典型使用场景

  • 账号体系:防止同形不同码点的用户名并存,避免钓鱼式冒充
  • 域名与链接校验:识别视觉相似域名与不可见字符拼接的钓鱼链接
  • 内容风控:黑名单匹配前折叠兼容字符,避免用全角写法绕过
  • 日志审计:不可见字符会破坏日志结构与检索,需要在入口清洗
  • 文件命名:跨系统同名文件因归一化形式不同被当成两个文件

校验顺序示例

校验顺序示例
# 错误顺序:先校验后归一化,攻击者可用等价形式绕过
python -c "import unicodedata as u; s='\uff21dmin'; print('blocked' if 'admin' in s else 'allowed')"      # 全角 A 绕过
# 正确顺序:先兼容折叠再校验
python -c "import unicodedata as u; s=u.normalize('NFKC','\uff21dmin'); print('blocked' if 'admin' in s else 'allowed')"
# 检测不可见格式字符(Cf 类)
python -c "import unicodedata as u; s='us\u200ber'; print([hex(ord(c)) for c in s if u.category(c)=='Cf'])"
# 唯一性判断使用折叠后的值,展示仍用原值
python -c "import unicodedata as u; print(u.normalize('NFKC','\uff41pple') == u.normalize('NFKC','apple'))"

风险与对策

风险表现对策
等价形式绕过过滤规则被另一种码点写法跳过先归一化(含兼容)再校验
同形账号冒充两个账号肉眼无法区分唯一性用折叠值,必要时限制可用脚本
不可见字符注入内容比较与显示顺序异常拒绝或剥离格式字符,日志记录码点
钓鱼域名域名与正牌仅差相似字符域名展示与校验使用 punycode 与相似性检测
文件名冲突同一文件被系统视为两个统一归一化形式后再做去重与同步
「看起来一样」不能作为安全判据:人眼无法分辨同形字符与不可见字符。所有涉及身份、权限与唯一性的判断都必须基于归一化并显式校验后的值,而不是原始输入。
限制字符集是最有效的防御之一:账号名、标识符这类不需要复杂文字的场景,直接限定可用字符范围(字母数字加少量符号),可以一次性消掉大部分同形与不可见字符风险,代价是对多语言用户不够友好,需要与业务权衡。
排查可疑输入时按码点打印是基本功:把字符串转成 U+XXXX 列表,同形字符与零宽字符会立刻暴露。这一步应作为风控与审计工具的常规能力,而不是临时手工操作。

易错点

  • 校验与使用用不同的字符串:校验通过的内容在使用时被归一化成另一形态,规则被绕过 → 归一化一次后全程使用同一变量
  • 只做规范归一化不做兼容折叠:全角与连字写法仍能绕过过滤 → 安全校验场景使用 NFKC/NFKD
  • 唯一性约束建立在原始输入上:同形账号可以并存 → 用折叠值建唯一索引
  • 忽略不可见字符:零宽与双向控制符藏进内容,破坏比较与日志 → 显式校验并拒绝 Cf 类字符
  • 排查只看显示结果:同形字符肉眼无法分辨,误判为误报 → 输出码点后再判断

数据来源与参考

  • Unicode 官方:Unicode Security Considerations(同形与不可见字符)
  • Unicode 官方:Normalization(UAX #15)与等价性
  • Unicode 官方:Confusables 与视觉相似字符数据

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/regex/normalization-security-issue.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌​‌‌‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌​‌​​‌​‌‌‌‌​‌​​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌​​‌​‌​‌‌​​​‌‌​‌‌‌​‌​‌​‌‌‌​​‌​​‌‌​‌​​‌​‌‌‌​‌​​​‌‌‌‌​​‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌‌​​‌‌​‌‌‌​​‌‌​‌‌‌​‌​‌​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​