烟消火灭网

2021年冬天,Log4j2的那个漏洞把半个互联网搅翻了天。安全圈的人连夜爬起来改配置,运维群里消息刷得比过年还快。可真正让我后背发凉的,不是这个漏洞本身——是它暴露出来的那层东西:我们写的代码,和代

映射漏洞

2021年冬天,映射漏洞Log4j2的映射漏洞那个漏洞把半个互联网搅翻了天。安全圈的映射漏洞人连夜爬起来改配置,运维群里消息刷得比过年还快。映射漏洞可真正让我后背发凉的映射漏洞,不是映射漏洞这个漏洞本身——是它暴露出来的那层东西:我们写的代码,和代码实际运行时的映射漏洞行为之间,存在一条巨大的映射漏洞裂缝。

这条裂缝,映射漏洞就是映射漏洞映射漏洞。

说人话就是映射漏洞:你脑子里想的、代码里写的映射漏洞、机器实际跑的映射漏洞,是映射漏洞三个不同的东西。而漏洞,映射漏洞往往就藏在这三者之间的翻译误差里。

拿一个最简单的例子。你写了一段用户输入校验,正则表达式写得严丝合缝,测试全过。上线三个月没出事。然后某天有人传了个文件名带Unicode右到左覆盖字符(U+202E)的文件上来,你的校验逻辑看到的是"gpj.exe",系统实际存的是"exe.jpg"。绕过去了。你没写错代码,你的正则也没问题。问题出在"字符串"这个东西从你眼前到磁盘上,中间被转了好几手,每转一手就可能变一次脸。

这就是映射漏洞的本质:两个系统对同一个数据的理解不一致,而中间那层转换没人负责。

它为什么比普通漏洞更难防

普通漏洞,比如缓冲区溢出、SQL注入,你至少知道要去哪里找——输入点、拼接点、边界条件。映射漏洞不一样,它经常出现在两个看起来都没问题的模块之间。

我见过一个真实案例。某电商平台的优惠券系统,前端JS算了一遍折扣金额,后端Java又算了一遍。两边用的都是浮点数,但JS的Number和Java的double在极端值上舍入行为不同。结果就是:前端显示优惠100.00元,后端实际扣了99.99元。差了1分钱。正常人不会在意这1分钱,但有人写了脚本,专门构造特定金额的订单,每次薅1分,一天跑几十万单。

前端有问题吗?没有,它按IEEE 754算的。后端有问题吗?也没有,它也按IEEE 754算的。问题在于两个"按标准算"的实现,在某些边界上就是不一致。而系统设计时假设了它们一致。

更隐蔽的那种

上面说的还是技术层面的映射。还有一种更麻烦的:语义映射。

比如权限系统。你定义了一个角色叫"编辑",可以改文章但不能删文章。前端按钮灰掉了删除功能。后端API也校验了权限。看起来没问题。但有人发现"复制文章"这个接口没有做权限校验——因为它不属于"编辑"也不属于"删除",开发的时候归类到了"查看"权限下。于是任何人只要能查看文章,就能复制出一篇一模一样的,然后对复制出来的那篇执行删除。绕了一圈,还是把文章删了。

权限的语义映射错了。"复制"这个操作在业务上到底属于读还是写?不同的人有不同的理解,代码里选了其中一种,攻击者选了另一种。

怎么对付它

没有银弹。但有几件事做了之后会好很多。

第一,在系统边界上做规范化。数据进来的时候统一编码、统一类型、统一精度。别让同一个东西在系统里有两种表示。第二,别信任任何隐式转换。JS里"1"+1等于"11",Python里1+"1"直接报错。哪个对?都对你写代码的那个上下文。但跨系统的时候,显式转换比隐式转换安全一个数量级。第三,把映射关系写下来。不是写文档那种写下来,是写成测试用例。前端算100.00,后端也必须算100.00,写个测试盯着它。别靠"我觉得应该一样"。

Log4j那个漏洞,说到底也是映射问题:日志里的${ }被当成表达式解析了,而写日志的人以为它只是普通文本。一个字符串,两种解读,中间没有隔离层。

这种漏洞不会消失。因为只要有人写代码,就有人假设"对方应该和我理解的一样"。而攻击者,恰恰靠这个假设吃饭。

访客,请您发表评论:

© 2026. sitemap