← 安全上网
ASTERXOR / 安全上网

看起来相似的链接,字节可能不同

百分号编码是网址的表示方法,读懂显示与判断含义却是两回事。

为《看起来相似的链接,字节可能不同》绘制的解释性示意图。
原创示意图,仅使用虚构样本。
安全上网ASTERXOR / LEON LEUNG

斜杠何时是分隔符,何时只是编码值的一部分?

网址是有结构的文字,有些字符负责分隔,有些属于传递的数据。百分号加十六进制数字可以表示字节,但软件仍要决定正在解释哪个部分,以及何时解码。更易读的显示,有时会隐藏这些区别。

显示清楚,不等于解释完整。
THE QUESTION

编码不是保密

%20 常表示网址组成部分中的空格字节,读取它不需要密钥。百分号编码不是加密,也不是目的地可信的证据。充满转义的长地址可能只是正常数据,简洁地址也可能提出不合适的要求。

应区分原字符串、解析出的组成部分,以及某一部分解码后的显示。混淆这些阶段容易出问题。例如斜杠通常分隔路径段,而编码斜杠在不同服务器和路由层中可能得到不同处理。含义由处理系统决定,不能仅凭外观。

A SMALL MODEL

解码一次后,两条路径可能相同

本地样本包含 https://example.com/a%2Fb 与 https://example.com/a/b。原始路径不同,但前者通用解码一次后变为 /a/b。两个原网址的主机都是 example.com。这只说明字符串解析结果,不证明真实服务器会返回同一资源。

另一例把编码后的 example.org 地址放进 example.com 网址的查询参数,外层主机仍是 example.com。嵌套地址此时只是数据,要等应用决定用途,可能用于稍后跳转,也可能另有作用。实验没有联系任一目的地。

前两条原路径解码后相同;双重编码路径再次解码时还会变化。
FIG 01前两条原路径解码后相同;双重编码路径再次解码时还会变化。
READ THE RESULT

解码两次,是另一种操作

/%252F 第一次解码变成 /%2F,因为 %25 表示百分号;第二次则变成两个斜杠。几个字符串确实不同,不能匆忙当作同一种写法。意外解码两次的软件,可能与只解码一次的软件产生不同解释。

我们用标准库和固定字符串演示,没有构造实际攻击。浏览器、代理、框架和服务器各有规则。美化网址的函数不能自动成为安全过滤器;判断哪些表示等价,需要真实系统行为和明确策略。

THE BOUNDARY

对读者,换条路常常更简单

决定是否输入密码前,不必亲自破解复杂网址。消息声称账户有事时,可以从惯用应用或书签进入核对。熟悉主机名有帮助,但请求是什么、从哪里来的仍需判断。HTTPS 不会让所有要求都变合理。

读地址时先找真正的协议和主机,不要只在整串中寻找熟悉词。留意所谓目的地是否仅出现在路径或查询里。短链接和跳转还会增加无法单靠字面确认的后续步骤。涉及重要行动时,不确定本身就是暂停的理由。

先区分网址组成部分,再讨论解释方式,最后单独判断所要求的操作。
FIG 02先区分网址组成部分,再讨论解释方式,最后单独判断所要求的操作。
IN PRACTICE

对开发者,要保留上下文

开发者应使用成熟的网址和框架 API,而不是拼接临时替换规则。验证与比较必须和最终使用网址的组件一致;一层检查一种表示,另一层按另一种行动,会留下差距。本文不提供可部署的允许列表或规范化算法。

普通读者只需记住:地址格式有时确实复杂,但不该因此被催着信任不透明请求。为重要服务保留独立入口。会读链接很有用,知道何时不必自己解开歧义,同样是实用能力。

留一个想法带走

地址有自己的语法。显示过于轻巧时,让语法提醒你慢一点决定。