从右到左装饰字符的隐藏陷阱
速览
从右到左装饰字符(如Unicode控制字符)可能被恶意利用来篡改代码或文本的显示顺序,造成安全漏洞。本文分析了这些字符的工作原理,展示了实际攻击案例,并提供了防御建议。对于开发者而言,理解并正确处理这些字符至关重要。
AI 深度解读
背景
在排版领域,装饰性符号(如花饰符 ❦、❧)早在活字印刷时代就已存在,数字时代它们被纳入 Unicode 标准,逐渐出现在博客样式和正式文章中。然而,这些符号往往带有隐含的书写方向属性——例如摩尼教(Manichaeism)曾使用从右到左书写的文字,其对应的 Unicode 字符 𐫱(Manichaean Punctuation Fleuron)就被标记为“右向”(Right-to-Left,R类型)。当这类字符与数字、英文等左向文本混合排列时,可能会打乱浏览器双向文本渲染算法,导致显示异常。
核心内容
原文作者在探索使用 𐫱 作为日期与文章分类之间的分隔符时,发现该符号意外地将后面的文本“拽”到了它前面,导致 𐫱 400 Divisadero 渲染为 𐫱 400 Divisadero(实际上,由于 𐫱 是 R 类型,它将其右侧的弱类型数字 400 视为右侧方向,重新排列为 𐫱 400,但数字内部顺序保持 400 而非 004)。作者原本期望的效果是 𐫱 400 Divisadero 正常从左到右显示。
Unicode 双向算法(Bidirectional Algorithm,简称 Bidi)定义了字符的布局规则:每个字符都有一个双向类型(如 L 表示左向、R 表示右向、EN 表示欧洲数字、WS 表示空白等)。强类型字符(如 L 或 R)会主导周围弱类型或中性字符的方向。𐫱 属于强 R 类型,因此它会让紧随其后的弱类型数字 400 变为右向排列,但数字内部仍是 400(因为数字是弱类型,会跟随强类型的方向,但不会反转内部顺序)。
修复方法有两种:
- 使用 HTML 标签
<bdi>(Bi-Directional Isolation)包裹该符号,使其方向与周围文本隔离:<bdi>𐫱</bdi> 400 Divisadero。 - 使用 CSS 属性
unicode-bidi: bidi-override;强制覆盖双向行为,例如:<span style="unicode-bidi: bidi-override;">𐫱</span> 400 Divisadero。后者在浏览器兼容性上略好(但 IE 已无人在意)。
关键要点
- 摩尼教花饰符
𐫱是 Unicode 中的 R 类型字符,继承自摩尼教从右到左的书写传统。 - 双向文本渲染算法:Unicode 双向算法用约 2 万字和 51 次修订来规范,核心是字符的强类型(L/R)决定弱类型(如数字、标点)的方向。
- 问题现象:
𐫱 400 Divisadero中的𐫱将数字400拉向右侧,显示为𐫱 400 Divisadero(数字顺序不变,但整体位置被右置)。 - 修复方案:
- 使用
<bdi>标签隔离方向性。 - 使用 CSS
unicode-bidi: bidi-override;覆盖双向行为。
- 使用
- 注意事项:类似的 R 类型装饰符号还有
𞢹、𐩕等,使用时需主动处理方向问题。
意义与影响
随着 Web 内容日益国际化,Unicode 包含越来越多来自不同文化、不同书写系统的符号。这些符号可能带有隐式的方向属性,在普通文本中容易被忽略,却可能导致意料之外的布局混乱。本文提醒开发者,当使用装饰性符号(尤其是来自 RTL 书写系统的符号)时,必须考虑双向文本算法的行为,并主动通过 HTML 或 CSS 手段进行隔离控制。这不仅关乎排版美观,更涉及信息可读性与准确性。对于内容管理系统、博客平台、在线文档工具等需要处理多语言、多符号的软件,理解并应用 <bdi> 或 unicode-bidi 是提升国际化质量的关键细节。
