我是如何利用 NPM 下载的……以及为什么不应该相信它们

2025-06-08

我是如何利用 NPM 下载的……以及为什么不应该相信它们

在过去的一个月里,我成功让一个几乎没有用户的软件包累计下载量超过一百万次🚀。

它不需要花费任何金钱,没有违反任何法律(我认为),而且几乎不需要付出任何努力。

以下是您需要了解的有关 NPM 的下载统计数据。

🔮 下载的幻觉

如果您曾经考虑过使用 NPM 的新包,那么您很可能考虑过“每周下载”统计数据。

这是页面上显示的第一个指标 - 因此它对用户来说一定是有用的信息......对吗?

Twitter民意调查

参与本次调查的三分之一的人似乎都这么认为,甚至表示这对他们决定采用新方案有很大影响。

但问题是,由于以下两个原因,它并不是一个有用的指标:

  • 用户数和下载量之间的关系(最好是松散的)
  • 该系统很容易被利用

什么是下载

NPM 博客对此进行了很好的讨论,但总结一下,它是从 NPM 注册表中成功下载的任何包(tarball)。

NPM 已公开声明,此统计数据不考虑来源(IP、用户代理等)。这意味着所有下载都是平等的,无论来自:

  • 用户向其项目添加新包
  • CI 运行安装依赖项
  • 机器人反复下载软件包,营造出流行的假象(这里有一些伏笔)

你可以想象,这意味着一个频繁运行 CI 的项目可能会比任何一组个体对下载统计数据产生更大的影响(尤其是在考虑 npm 客户端缓存时)。

注册表

注册表数量过多也是下载量无法准确反映使用情况的另一个原因。NPM 下载量仅包含官方 NPM 注册表的下载量,而不包括unpkggithub等注册表。

🧑‍💻 利用系统


免责声明:我记录此内容是为了说明下载统计数据是多么容易被利用。但是,我强烈建议您不要这样做,因为这既不诚实,又会浪费 NPM 公司的资源。


如果您已经阅读了到目前为止的所有内容,您就会知道不需要任何类型的“天才黑客攻击”。

相反,我们需要的是某种多次下载包的方法。

使用某种 cron 作业在本地运行脚本应该没问题 - 但这并不是太令人兴奋...让我们使用无服务器吧!

您可以在此处查看完整的 repo

创建脚本

对于 Lambda,我创建了一个采用以下参数的函数:

  • package- 要下载的包
  • probability- 给定运行的下载可能性

后一种论点旨在增加噪音——模拟下载随时间的变化性质。

每次运行都会进行一次“抛硬币”,并probability使用参数来衡量成功率。如果抛硬币成功,则下载该软件包。



export const handler = async ({ package, probability }) => {
  // Simulate coin flip
  if (Math.random() > probability) {
    // Flip fail
    return;
  }

  // Flip success
  await downloadPackage({ package });
};


Enter fullscreen mode Exit fullscreen mode

触发 Lambda

为了使该脚本定期运行,设置了以每分钟一次的频率触发的 CloudWatch 事件。



// Terraform example
resource "aws_cloudwatch_event_rule" "lambda_trigger_rule" {
  name = "trigger-npm-install"
  description = "Trigger an NPM install"
  schedule_expression = "rate(1 minute)"
}


Enter fullscreen mode Exit fullscreen mode

Terraform 中的示例 CloudWatch 事件规则。

为了在触发此事件时执行某些操作,我们设置了一个事件目标,并使用我们所需的参数指向 Lambda。



resource "aws_cloudwatch_event_target" "lambda" {
  arn = aws_lambda_function.install_package_lambda.arn
  rule = aws_cloudwatch_event_rule.lambda_trigger_rule.name
  input = jsonencode({
    package = "is-introspection-query"
    probability = 0.8
  })
}


Enter fullscreen mode Exit fullscreen mode

Terraform 中的示例 CloudWatch 事件目标。

🚀 结果

部署了一周之后,结果......其实并不那么令人印象深刻;事实证明,一周内的秒数并没有我预期的那么多🤔。

但遗憾的是,经过一些调整后,我们每周的下载量已接近 100 万次!

下载次数

是的,没错,一个实际上没有用户的软件包的下载量比urql和之类的软件包还要多mobx

您现在看到问题了吗?

下载统计数据不起作用

事实是,简单的下载统计数据在最好的情况下是无用的,在最坏的情况下是具有误导性的。

NPM 网站上的大型图表、在线庆祝下载 的文化、以及显示软件包下载“趋势”的第三方网站。所有这些都助长了这样一种说法:NPM 的下载量可以某种程度上反映软件包的受欢迎程度,但事实并非如此。

即使忽略恶意行为者(比如我自己)的可能性,大量的注册表和缓存实现也使得这些统计数据变得毫无用处。

“人气”

幸好,NPM 有个救星——流行度统计!我们干脆把下载次数换成其他更有用的统计信息吧……对吧?

不对——看来热门度统计只是伪装的下载量@prisma/engines统计。正如你下面看到的,我的软件包在热门度方面超越了其他软件包。

NPM搜索结果

以下是两个包的快速并排比较。

@prisma/引擎 是自省查询
每周下载量 约10万 约80万
星星 264 0
叉子 三十五 0
贡献者 二十六 1
用户 可能不是 0 肯定是 0

结论

如果您从本次讨论中得出一个结论,那就是下载量本身并不是一个有用的指标。

虽然我毫不怀疑 NPM 可以创建一个聚合包的许多不同属性的流行度指标(npms.io已经做到了这一点),但从现在开始,我将在信任NPM 🕵️ 上的下载量流行度指标之前做更多的背景研究。


希望你觉得这篇文章有趣!如果你有任何想法或评论,欢迎在下方留言,或者在推特上联系我 -  @andyrichardsonn

免责声明:本文中表达的所有想法和观点均为我个人的。

鏂囩珷鏉ユ簮锛�https://dev.to/andyrichardsonn/how-i-exploited-npm-downloads-and-why-you-shouldn-t-trust-them-4bme
PREV
在 Node.js 中构建安全的用户注册和身份验证
NEXT
开发人员的🦣机会 Mastodon 嵌入示例