为什么 StackOverflow 上的代码片段会摧毁你的项目?

2021-01-07 10:16:41 浏览数 (1)

作者 | Mahdhi Rezvi

策划 | Tina

在 StackOverflow 上你会惊奇地发现,上面分享的一些解决常见问题的代码居然存在安全漏洞。

本文最初发布于 Mahdhi Rezvi 的个人博客,经原作者授权由 InfoQ 中文站翻译并分享。

现在,StackOverflow 已经成为许多程序员的救星。我们中的大部分人甚至从未访问过 StackOverflow 的主页。我们访问该网站的唯一方式,是通过谷歌搜索某个我们遇到的问题或 bug,然后直接进入该问题的讨论区。

尽管去 StackOverflow 上寻找问题解决办法的习惯很实用,但与此同时我们可能也会无意中使用一些包含严重 bug 或者安全缺陷的代码。众所周知,直接从 StackOverflow 上复制代码来用是不合适的,但开发人员仍会这么做,这里引用 Ryan Donovan 的一句话:

代码复制本身并非坏事,代码重用能提高软件开发效率。为什么已经被完美解决的问题,还要再去重新解决一次呢?但是当开发人员不加理解就去使用示例代码时,那么问题就来了。

你可能会认为那些安全恐慌都只是都市传说,但我可以向你保证并不是。

最近我遇到的几件事,引起了我对这个问题的关注,下面我把这几件事简单说明下。

1拷贝次数最多的 Java 代码片段,一直存在缺陷

首次知道这个信息是在一篇博客中读到的,而这篇博客的作者正是那个 Java 代码的提供者,点击这里查阅博客原文。

Andreas Lundblad 是这段代码的作者,他是 Palantir 的 Java 开发人员,同时也是 StackOverflow 上排名最高的贡献者之一,他在博客中承认了此代码的缺陷。

2018 年,Sebastian Baltes 在《实证软件工程》期刊上发表了一篇研究论文。该论文指出 Andreas 在 StackOverflow 上发布的一段 Java 代码是 StackOverflow 上被拷贝次数最多的 Java 代码,甚至被多次使用在开源项目中,在 GitHub 上至少有 6000 多个 Java 项目使用了该代码片段。

该段代码是为了回答于 2010 年发布在 StackOverflow 上的这个问题。它的功能是将字节计数转换为更易于阅读的格式。例如,它将 1024 字节转换为 1kB 或将 1048576 字节转换为 1 MB。

Andreas 在被 Sebastian Baltes 告知这段代码的惊人传播量后,重新评审了这段代码。且随后在其个人博客中发布了更正后的版本,同时在博客的最后还给出了一些有价值的建议:

  • StackOverflow 上的代码段可能存在 bug,即使它们有成千上万的赞成投票。
  • 测试所有的边缘情况,特别是从 StackOverflow 复制的代码。
  • 在复制代码时,一定要包括其来源和贡献者,当出问题时,能快速定位。

尽管这个 bug 是一个微不足道的边缘情况,只会导致对文件大小计算的不精确,但实际情况可能会更糟,我们来看更多的例子。

2流行最广的 c 代码片段存在重大安全缺陷

2019 年,Morteza Verdi 等人发表了一篇研究论文。该论文指出,过去 10 年里,StackOverflow 上流行最广的 c 代码片段中有 69 个存在重大安全漏洞。这 69 个经确认易受攻击的代码片段被使用到了 2589 个 GitHub 项目中。据研究者指出,从 StackOverflow 传播到 GitHub 上的这些代码中,最常见的安全漏洞是 CWE150:

CWE 是社区开发的常见软件和硬件安全缺陷列表。它是一种通用语言,是安全工具的衡量标准,同时也是缺陷识别、规避和预防的基础。

CWE150 指的是空间、元空间或控制空间出现不适当中和的情况。

该论文的研究人员还开发了一个 chrome 扩展,当开发者查看 StackOverflow 代码片段时可以提醒开发者当前阅读的代码是否存在安全漏洞。虽然这个扩展一般用途不大,不过如果感兴趣的话,可以点击这里查看它的源代码。

3Windows 无法同时运行 Docker 和 Razer Synapse 驱动管理工具

不能在 Windows 上同时运行 Docker 和 Razer Synapse 驱动管理工具,因为他们存在 StackOverflow 式的 bug

大约 2 年前,在 Windows 上运行 Docker 时有个奇怪的现象,即用户无法在 Windows 系统的机器上启动 Docker。这个奇怪的现象后来被人以问题的方式在 Github 提了出来。随后有很多其他人也说遇到了相同的问题。直到 Reddit 上的这篇文章发布之前,都没人知道根本原因是什么。

该文章指出,当 Windows 后台启动了 Razer Synapse 时,此时再去启动 Docker 就会触发此问题。其原因是,在 Razer Synapse 运行的时候,Docker 会认为已经有一个 Docker 实例正在运行中,所以 Docker 不会再启动一个实例。

两个应用程序各自都只允许同时启动一个自己的实例,这个需求看上去是个再合理不过的需求了。但是现实却是,这个限制确实是该 bug 的根本原因。下面是引发问题的代码片段:

代码语言:javascript复制
var name = string.Format("Global{0}", (object) 
Assembly.GetExecutingAssembly().GetType().GUID);

从上面的代码可以发现,问题就出在返回的 GUID 类型上。此处返回的 GUID 类型是 System.Reflection.RuntimeAssembly(系统层面的运行时程序集),而不是 Windows 中对应 Docker 程序集中定义的类型。

译者注:以上代码说明,在控制同一时间只允许运行一个实例,Docker 的处理方式是通过判断 GUID 是否存在,但获取在 GUID 时,用的是系统层面的而非自己独立程序集里面的。

更有趣的事情是:

如果只有一个应用程序使用了上面的错误代码,那么上述问题根本就不会出现。但现实是,很多应用程序都使用了该错误代码,结果不允许两个实例同时运行。

你认为上面两个应用程序包含的错误代码片段是从哪里来的呢?

我想你已经猜到了,没错,正是来自于 StackOverflow。

在.net2.0 中应用如何通过程序拿到 GUID,这篇不正确的 StackOverflow 文章,就是这些应用程序错误代码的来源。

你现在去看问题的答案,已经看不到有缺陷的回答了。他们已经重新编辑了答案。如果你想自己手动去查找,可以通过 Wayback Machine 来查看历史文章,查询结果如下图:

对开发人员的重要启示:

  • 考虑一下如何在自己的程序中找到这个 bug
  • 你所拷贝的代码表面上似乎能正确的运行,但其实你没有意识到的是,此代码本身就是缺陷代码——因为你的程序中没有引发错误的场景

4我们该避免拷贝吗?

并非如此,直到今天,Stack Overflow 对于任何程序员来说,都是必不可少的。但在项目中因拷贝代码引起的大多数问题都是基本的安全问题。因此如果你能事先弄懂你所拷贝的代码,那么是可以正确使用的。即使如此,当准备在生产环境中使用这些代码时,也最好先做好充分的测试,特别是一些边缘场景,下面引用 Ryan Donovan 的一句话:

“如果你引用别人的代码,但你却不理解所引用代码的内容;那么您就会陷入重用具有潜在漏洞的代码的陷阱,同时这些包含漏洞的代码也就被你传播开了。”如果您要重用代码,那么请您先理解这些代码。

原文链接

https://medium.com/better-programming/why-code-snippets-from-stack-overflow-can-break-your-project-ced579a48ddb

0 人点赞