译者丨明知山
策划丨 Tina
Curl 作为一个安装量超过 200 亿次的开源项目,承载着极高的安全性和稳定性要求。其作者 Daniel Stenberg 通过严格的代码规范、工具化的错误预防、海量的测试体系,以及高效的漏洞修复流程,确保项目的可靠性。面对“是否用 Rust 重写 Curl”的讨论,他明确表示,Curl 不会被重写,而是通过持续迭代和精细打磨来提升安全性。项目团队不仅采用多层次的测试方法,还通过安全审计、漏洞赏金计划等手段,不断优化代码质量。这种对细节的极致追求,为开源软件的长期维护和安全保障提供了宝贵的经验。
在本年度的 FOSDEM 开源大会上,Curl 作者 Daniel Stenberg 分享了“如何在你的 C 语言代码安装量达到 200 亿次时依然能睡得安稳”的秘诀。
Stenberg 认为,全球的 Curl 安装量达到 200 亿次可能还只是一个保守的估计。
这个数字无疑让这个由他独立开发的开源数据传输工具项目承担起了“一点点”责任。
“当然,我们用的是最安全的编程语言。”他说道,这引得观众们一阵笑声——因为 Curl 是用 C 语言编写的。
他的演讲既有趣又干货满满,令人信心倍增。
它还提供了一个鼓舞人心的例子,展示了当一个项目专注于更高层次的安全性时会发生什么,以及这种承诺如何转化为实际行动——尤其是在风险异常高的情况下。
这不是一个副业项目
在演讲的最后,Stenberg 展示了一张有趣的幻灯片,模仿 O'Reilly 出版社的书皮,书名是《用 Rust 重写 Curl,一个副业项目》(书皮上方还加了一句标语:“与其亲自动手,不如告诉别人怎么做”)。
“这本书非常受欢迎。”Stenberg 说道,并尖锐地指出,“但没有人真正实现过。”
Curl 包含 18 万行 C 语言代码,相当于《战争与和平》这部小说长度的 1.14 倍。Stenberg 说:“对于它的功能来说,这些代码算相当多了……它只是一个用来传输数据的工具。我们不会用 Rust 重写 Curl,也不会用任何其他语言——我们不会重写它。它已经在那里了。”Stenberg 承认 Rust “可能是一种很棒的语言”,并表示第三方依赖项可以用 Rust 编写,他预测未来在 Curl 项目中会有更多这样的情况。
但目前 Curl 的代码库仍然用 C 语言编写,“我们只是耐心地迭代和打磨,随着时间的推移不断完善。不会有任何重写。”
因此,他在演讲中展示的其实是他在保持 Curl 安全性方面所做的工作。
虽然他们用 C 语言编写代码,但 Stenberg 表示,他们已经禁止使用“一些容易出错的函数”。
在演讲结束时,有人要求举例,Stenberg 首先提到了 gets()(Stack Overflow 上有评论者称其为“制造缓冲区溢出的恶魔工具”),还有 scanf()、strcopy() 和 sprintf()。
“不管你经验有多丰富——C 标准库中的一些函数真的不建议在代码中使用。我们用工具检查并禁止使用它们,这样就不会不小心让它们混进去了。”
测试,测试……
他们还有一种特殊的“折磨测试”,在调试构建过程中,每个可能发生内存分配失败的函数(如 malloc 或 calloc)都有一个包装器,让他们可以反复调用这些函数——一直调用直到失败。Stenberg 解释说:“它们应该是优雅地失败——没有内存泄漏,没有崩溃,只以错误码的形式退出。这是测试退出路径的绝佳方式,确保我们在退出时总是释放和清理了资源。”
开发团队并不会测试所有东西。他笑着说:“这可不是一个快速的过程。”因此,他们设计了一个系统,随机测试一个较小的子集。他们还使用了持续集成,每一个拉取请求和代码提交都会运行 40 多万个测试。“我记得大概一年前运行这些测试需要花费数小时,”他回忆道,但在对测试进行了优化之后,现在只需要 30 分钟。“快速运行测试让我们能够立即了解代码变更的最新状态。”
你可能听说过“ CPU 秒”这个词,即全功率使用服务器级 CPU 一秒钟—— 86400 个 CPU 秒加起来就是一整天的 CPU 时间。Stenberg 表示,目前“我们每天在 CI 上平均花费大约 10 个 CPU 天。”
为了确保整个项目的安全性,Stenberg 还提到了其他各种各样的测试——甚至有一个是测试“代码风格是否正确,以及代码中的缩进和拼写是否准确”。他们还有一个 CI 任务,用于确保代码中没有任何二进制代码块。
还有单元测试、库测试、工具测试,“当然,我们还有一直在检查代码的分析器”——包括静态和动态分析器。Curl 还是谷歌 OSS-Fuzz 项目的一部分。
“我们希望确保这 200 亿次安装都能正常运行。”
修复和发现漏洞
谈到漏洞时,Stenberg 表示:“我们会尽快修复漏洞,按规定通知发行版,并非常详细地记录所有信息,包括以 JSON 格式列出受影响的 Curl 版本。”这些信息也会发布在 Curl 的官方网站上。Curl 项目现在也是一个官方的 CVE 编号机构,“这样我们可以更好地管理我们自己的 CVE。”
他们非常重视发现漏洞,Stenberg 补充说:“我们进行了多次审计。”
Stenberg 回忆说,他们在 2016 年的第一次审计“发现了 7 个 CVE”,2022 年的审计又发现了 2 个 CVE。但他自豪地表示,2024 年的一次更严格的审计结果是 0 个 CVE——这是一个令人振奋的趋势。审计是一项艰巨的任务。“有人会花大量工时来查看代码……对于一个小型开源项目来说,这不是一件容易做好的事情。你需要有足够的资金支持,才能让这一切成为可能。”
他指出,审计的成本“比我们多年的漏洞赏金计划的总成本还要高”——尽管漏洞赏金计划最终发现了更多的 CVE。
这个漏洞赏金计划与 HackerOne 和互联网漏洞赏金计划(Internet Bug Bounty Program)合作开展。Stenberg 表示,自 2019 年 4 月启动计划的六年来,他们已经支付了超过 85000 美元。在 500 份漏洞报告中,有 76% 导致了 CVE(有 19% 是非 CVE 级别的漏洞)。“其他的报告并不都是无效的,”Stenberg 说,“但也确实有不少……我们会公开所有报告的后续讨论,方便大家跟进……”
尽管“漏洞赏金”幻灯片上的最后一项只是提到“AI 垃圾报告越来越多”。
“实际上,目前我们收到的有效报告和‘AI 垃圾报告’的比例差不多,”Stenberg 表示——大约有 10% 到 15% !
全方位的安全性
该项目致力于实现最高级别的安全性,这种承诺似乎渗透到了每一个层面。
所有提交的代码都经过仔细评审——既有人工评审,也有机器评审。Stenberg 说:“现在我们有一个非常严格的代码风格”,这让整个 18 万行的代码库看起来像是由一个作者编写的(这种一致性使得代码更容易阅读和调试)。
“我们有大量的文档,涵盖了源代码、内部 API 和所有相关内容。”后来 Stenberg 解释说,甚至还有文档检查工具,不仅限于检查拼写和语法。“例如,我们会尽量避免在文档中使用英语缩写,像“isn't”这样的表达是不被允许的……诸如此类……”
该项目的开发团队在访问托管在 GitHub 上的源代码时都使用双因子认证……
GitHub 为他们提供了额外的测试资源,导致在 Mastodon 上引发了一些有趣的讨论,例如,其他开源项目是否也应该从一开始就采用最严格的安全措施。
“我认为大多数开源项目都是从‘小’和‘简单’起步的,”Stenberg 回应说,并补充道,“从一开始就做到尽善尽美,确保一切严格无误,甚至是在还不确定项目是否能成功之前,可能并不明智。我认为很少有项目能做到……我们开始时几乎每个环节都很松散……”
在后续的讨论中,Curl 开发者 Stefan Eissing 开玩笑说,有时候感觉风险巨大。“我们有一些开源项目,‘感觉如果搞砸了,几个星球的文明就会终结’。这可不是文明该有的运作方式。”
Stenberg 对 GitHub 给予他们的帮助心存感激,也许他希望这种水平的支持能够延伸到更多正在努力解决自身问题的开源代码库上。
“放眼世界,许多项目仍然需要得到一些帮助……”
原文链接:
https://thenewstack.io/curls-daniel-stenberg-on-securing-180000-lines-of-c-code/
声明:本文为 InfoQ 整理,不代表平台观点,未经许可禁止转载。