最近网上对 ENS 的零宽字符讨论的有点多,网友们的讨论我也都看了一些。本人一直厌恶慕洋犬,再加上好奇心驱使,便特意花了点时间研究了下这个问题。
先普及几点基础知识:
不可见字符有很多种,这篇 文章 里提到的 ZWJ 只是其中一种(也是零宽字符的一种,除此之外还有 ZWNJ(U+200C)、ZWSP(U+200B) 等),还有朋友圈里某大佬提到的这种:
'🦄️' !== '🦄'
把上面的代码拿到浏览器 Console 控制台里执行会发现输出是 true
IDNA 标准对零宽字符有个 解释,但这个解释里很明确地指出了 ZWJ 和 ZWNJ 只能用于阿拉伯语和印地语。但是可笑是,某网友强行曲解文章的含义,让我看呆了:
原文1:
applications that perform IDNA2008 lookup are not required to check for these contexts, so overall security is dependent on registries having correct implementations.
做过相关开发的我表示这段文字的大意明明是:
因为检测这种环境(纯阿拉伯语或纯印地语)很难,所以具体的安全策略还是需要根据具体应用来分析。
然后被这个居心叵测的网友翻译成:
你完全可以在任意IDNA2008支持的语言中随意加入这两个字符
还有接下来的就更离谱了,原文2 是:
the IDNA2008 context restrictions do not catch most cases where distinct domain names have visually confusable appearances because of ZWJ and ZWNJ
大意明明是:
上述限制(指 ZWJ 和 ZWNJ 只能存在于阿拉伯语和印地语)很难在大多数的场景下实施
结果硬是被这文盲强行总结意淫成:
这篇报告的作者都不认为这是一个问题
真是哔了狗了,要是没这些这伪军翻译官儿,没准中日早就恢复世代友好了吧……
某些法律很难在某些场景下被执行就可以在任何场景下都无视法律了吗?再说,你有论证过就此时的这个 ENS 的案例属于无法执行的那种场景了吗?
搞懂了这些基础知识,我们再简单分析一下,域名是不是应该允许有零宽字符。
IDNA 为什么要三番五次的强调 ZWJ 和 ZWNJ 只能存在于纯阿拉伯语和印地语呢。试想一下如果存在这样的一个中文网址:
中国人民银行.网址
如果我在 银
和 行
之间插入一个 ZWJ ,那么普通网民要怎样区分真正的官方网站和钓鱼网站?这两个网址肉眼看起来就是一模一样的。而阿拉伯语和印地语则不一样,还是那个 文章 里有举例:
插入前:http://ශ්රී.com
插入后:http://ශ්රී.com
对于这些语言的某些场景来说,ZWJ 会显著改变他们的外在表现,这可以让普通人也能看出区别来。
总有人会误解 web3 就是自由,区块链就是没有任何限制。没有规则的自由就是野蛮,没有限制的发展只会导致疯狂。但是他们其实不懂。
说了这么多没用的,来点有意思的料。ENS 关于注册过程的一部分源码在区块浏览器上可以看到,关于判断注册账户名的合法性就只有短短一行代码(详情):
是要字符长度大于或等于 3 个就放行,注意,是任意字符,任意的。。。
就这啥也不做的行为都能被慕洋犬们吹成兼容了 IDN 标准?看来打鬼子还是得先把这帮伪军给锤了。
然后摸熟了这个注册合约的大致逻辑后,我开始尝试直接调用合约接口注册账户(因为很多字符会被 应用层 给拦截,这种拦截对于合约安全起不到任何作用,如果慕洋犬们非要强行说有什么作用,那就妥协一下,还是有点卵用吧)。我前前后后注册了 9 个账户(花了我将近 1k 刀,这可恶的 gas 费……),然后发现打开 ENS 的官网的时候已经出现了页面 bug,但是它的 API 接口却实实在在地返回了我注册的 钓鱼 ENS 账户:
接着打开 opensea ,只显示了其中的两个 ENS 账户,看来安全果然是做在应用层的,可以的,这很 web3。而且这还做得不够完美,我其中一个 ENS 还是被展示出来了,虽然啥也显示不了,但至少我还能挂单出来(希望一个有缘的慕洋犬能买下来,算是买个教训)。试想一下,要是另一个 ENS 的第三方市场不懂这些 ENS 的坑,把我的这些钓鱼账户都展示出来的话得有多少用户被骗。或许只有那些慕洋犬们被真正骗走了血汗钱的时候才会醒悟过来吧。
继续测试,打开 nftscan ,九个账户都展示出来了,正确展示了一个:
打开 metamask,展示出两个,正确展示了一个:
看来 metamask 和 opensea 是用的同一个 API 接口。
然后打开 nftgo 发现页面已经中招了,把我注册的钓鱼 abc.eth
已经错误地展示出来了:
本人资金有限,这个测试并没有做完,测试账户也贴 这里,我想说的是,不可见字符不仅仅只有零宽字符这一种(计算机是另外一个全新的世界,远非普通人所想象的那么简单,它很迷人,很深奥,以后一定会是一个人人都会编码的时代),能测试的东西非常的多。完全依赖应用层去解决这个问题不现实,总会有一些漏网之鱼没有被过滤完全,也总会有一些项目方忘记及时更新钓鱼库而导致用户资产丢失。
最后,希望:
少一点骗子(当然这不可能)
多一些负责人的开发者(这应该还是能做到的)
每个人都学点编程基础(这个愿望不过分吧)