写点什么

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

  • 2020-11-27
  • 本文字数:2585 字

    阅读完需:约 8 分钟

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

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


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


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


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


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


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


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



插图Mateusz Kupilas提供


StackOverflow 上拷贝次数最多的 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 是一个微不足道的边缘情况,只会导致对文件大小计算的不精确,但实际情况可能会更糟,我们来看更多的例子。


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


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


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


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


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


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


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


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


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


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

  • 你所拷贝的代码表面上似乎能正确的运行,但其实你没有意识到的是,此代码本身就是缺陷代码——因为你的程序中没有引发错误的场景


所以,我们该避免拷贝吗?


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


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


祝您编程愉快!


原文链接:


Why Code Snippets From Stack Overflow Can Break Your Project


2020-11-27 17:001544

评论

发布
暂无评论
发现更多内容

避免 10 大 NGINX 配置错误(下)

NGINX开源社区

nginx 配置 配置分析 故障排除

头脑风暴:最长递增子序列

HelloWorld杰少

算法 LeetCode 数据结构, 8月月更

IPv6邻居发现协议详解

穿过生命散发芬芳

NDP 8月月更

百炼成钢 —— 声网实时网络的自动运维丨Dev for Dev 专栏

声网

Dev for Dev 自动运维

5 分钟温故知新 RxJS 【转换操作符】

掘金安东尼

前端 函数式编程 8月月更

把充电宝拆了看看

Sher10ck

拆解 充电宝

微服务的拆分与设计原则

阿泽🧸

微服务 8月月更

大专的我狂刷29天“阿里内部面试笔记”最终直接斩获十七个Offer

收到请回复

Java 程序员 阿里 面试八股文 Java面试八股文

字节跳动嵌入式数据分析最佳实践

字节跳动数据平台

字节跳动 数据分析 BI 嵌入式分析 数据看板

个推TechDay直播预告 | 8月24日晚19:30,实时数仓搭建保姆级教程开课

个推

数据仓库 实时数仓 Flink 平台

深度学习公式推导(3):初探神经网络

老崔说架构

RocksDB在大规模分布式系统应用中的经验

CnosDB

时序数据库 开源社区 CnosDB 工程师有话说 CnosDB Tech Talk

C语言基本的窗口开发

计算机魔术师

8月月更

[极致用户体验] 网页里的「返回」应该用 history.back 还是 push ?

HullQin

CSS JavaScript html 前端 8月月更

HTML

武师叔

8月月更

ABAP工作进程对数据库表读取操作的检测

汪子熙

数据库 SAP abap Netweaver 8月月更

每日一R「09」类型系统(三)

Samson

8月月更 ​Rust

【源码解析】MyBatis结果集映射和参数绑定

小明Java问道之路

源码解析 mybatis源码 mybaits 深度 8月月更

程序员面试太卷?我选择背这份阿里最新Java面试八股文(详解版)

Java面试那些事儿

Java 面试 Java 面试 java程序员 java 编程

开源贡献者计划 2022 第二期正式启动!争做战“码”先锋!

InfoQ写作社区官方

开源 OpenHarmony 热门活动

【Java】:数组的创建、赋值、访问以及长度

翼同学

Java 学习 编程语言 分享 8月月更

打破底层技术瓶颈,RTC技术或成为物联网市场的强劲引擎

擎声科技

物联网 RTC sdk 实时音视频 擎声Qtt

短视频源码APP开发——短视频的功能

开源直播系统源码

软件开发 直播系统源码 短视频直播系统

leetcode 303. Range Sum Query - Immutable 区域和检索 - 数组不可变(简单)

okokabcd

LeetCode 算法与数据结构

openEuler代码贡献之星:麒麟软件裴建康

openEuler

开发者 成长 代码规范 openEuler 开源社区

关于 SAP ABAP 字符变量和字符串变量字符个数的一个知识点

汪子熙

字符串 SAP abap Netweaver 8月月更

从函数计算到 Serverless 架构

阿里巴巴中间件

阿里云 开源 Serverless 云原生

新书上市 | 连载 5 年,千万读者追更,这本书讲透了通信背后的故事!

图灵教育

HPC、AI与云计算:当智能时代三叉戟在亚马逊云科技完美融合

脑极体

开源一夏 | Node.js实战对于Buffer和Stream模块系统的深入剖析

恒山其若陋兮

开源 8月月更

【Django | 开发】面试招聘信息网站(快速搭建核心需求)

计算机魔术师

8月月更

为什么StackOverflow上的代码片段会摧毁你的项目_语言 & 开发_Mahdhi Rezvi_InfoQ精选文章