
安全问题一直是一个备受关注的热门话题,几乎每周都会听到类似的消息:某些公司遭受入侵,导致数百万用户的数据泄露。
我们看到许多安全问题的部分原因是我们对待安全的方式。通常,安全被视为开发完成后才考虑的事情,类似于在设备上添加的后期附加品。然而,复杂的系统,尤其是嵌入式系统,拥有庞大的攻击面,这给了攻击者可乘之机,让他们能够在防御上找到漏洞。如果我们研究大多数黑客试图入侵系统的方式,很快就会发现他们最喜欢的工具是寻找和利用设备的软件漏洞。
如果软件漏洞是黑客入侵的途径,那么提高我们的代码质量来解决这个问题就显得尤为重要。但是,我们该如何评估这个问题的严重性?我们又能采取什么措施来加以解决呢?
代码漏洞容易成为黑客的目标
事实上,代码质量问题是一个普遍存在的难题,并且有许多证据支持这一观点:糟糕的编码直接导致漏洞。尽管多年来许多软件工程专家一直在强调这一点,但人们第一次真正意识到这一点可能是在2001年,当时红色代码蠕虫利用缓冲区溢出漏洞攻击了微软的互联网信息服务(IIS)[1]。尽管早在1988年就有了第一个被记录的缓冲区溢出攻击,那次攻击针对的是Unix的finger指令,但其对普通人的影响非常有限,因此并没有引起大规模的关注。
然而,红色代码造成了大范围的互联网减速,成为新闻头条。自此之后,缓冲区溢出攻击的数量似乎不断增加,安全研究人员和黑客在各种系统中,包括嵌入式系统中,不断寻找这类漏洞。通过利用缓冲区溢出漏洞,黑客可以在受影响的系统上执行他们想要的任意代码。这种攻击的目标是使用固定长度的缓冲区来存储文本或数据,黑客将缓冲区填满并在末端写入可执行代码。被攻击的系统会执行缓冲区末端的代码,很多情况下,攻击者可以获得控制权[2]。
这种类型的攻击变得紧迫是因为很多编码中并没有普遍检查和执行缓冲区限制的代码。然而,许多编码标准,如mitre.org的Common Weakness Enumeration,现在都建议检查这类缓冲区漏洞[3]。令人遗憾的是,开发者在编写代码时通常不会主动发现这类问题。通常需要代码分析工具来发现这些问题,才能让开发者意识到问题的存在并加以修复。而实施一个简单的代码质量改进,就可以消除黑客最常使用的工具之一,大大提高代码的安全性。因此,检查和执行编码中缓冲区的长度是好的编码实践。
不仅限于缓冲区溢出
然而,这个问题并不仅限于缓冲区溢出,实际上它是一个系统性的问题。通常情况下,粗心的编码导致了无数的安全漏洞,黑客可以利用这些漏洞来入侵系统。美国软件工程学会(SEI)在一篇论文中明确指出:“......质量性能指标用于确定高质量的产品和预测安全性,预测保障结果提供了依据。许多常见的漏洞枚举(CWE),如编程语言结构的不当使用,缓冲区溢出和验证输入值的失败,这些都可能与低质量的编码和开发过程有关。提高代码质量是解决一些软件安全问题的必要条件。”[4]
该论文还指出,安全问题--因为许多安全问题是由于软件漏洞引起的--可以像更普通的编码漏洞一样对待,因此可以应用传统的质量保证技术来帮助解决至少一些安全问题。
既然正常的软件质量保证过程可以帮助我们估计系统中剩余的漏洞数量,那么安全漏洞也可以如此吗?尽管SEI没有明确确认代码质量和安全之间的数学关系,但他们确实指出,1%到5%的软件漏洞是安全漏洞,并继续指出,他们的证据表明,在追踪安全漏洞时,他们可以准确地估计系统中的代码质量水平[4]。这最终表明,代码质量是安全的必要条件(但不是充分条件),真正实现“安全不应该只是在软件开发结束后添加的东西”这一理念是可行的。相反,安全必须贯穿整个项目的DNA,从设计、编码一直到生产。
编码标准帮助重大
编码标准对解决许多常见的安全漏洞非常有帮助,例如mitre.org的Common Weakness Enumeration (CWE),它指出了一些需要特别关注的领域,如除零错误、数据注入、循环不规范、空指针利用和字符串解析错误。MISRA C和MISRA C++也提倡编码的安全性和可靠性,以防止安全漏洞渗入代码。尽管这些标准可以捕获许多常见的漏洞,但开发人员在编写代码时必须考虑更深入的问题:黑客如何利用我刚刚编写的代码?漏洞可能存在于哪里?我是否对输入数据和输出的使用做出了合理的假设?一个好的经验法则是,如果你在做假设,那么应该将这些假设转化为代码,以确保你所期望的行为与实际结果一致。如果你忽略了这一点,黑客可能会利用这些漏洞。
但是对于开源软件呢?使用开源组件的典型论点是依赖于“在使用中被证明”的观点:因为有很多人使用它,所以一定是安全的。然而,SEI在论文中指出:“开源的好处之一是认为‘有很多人关注源代码,意味着安全问题可以很快被发现,任何人都可以修复漏洞,不需要依赖供应商’。然而,现实情况是,如果没有纪律地、一致地关注漏洞修复,安全漏洞和其他漏洞仍然会存在于代码中。”[4] 换句话说,仅仅依赖“在使用中被证明”的论点是没有意义的,而且即使你进行了测试也不能完全保证代码是令人满意的。SEI指出,像CWE这样的代码质量标准可以帮助发现代码中的问题,而这些问题通常在传统测试中无法发现,只有当黑客利用漏洞时才会被暴露出来。[4] 为了证明这一观点,2020年5月,普渡大学的研究人员展示了Linux、macOS、Windows和FreeBSD中使用的开源USB堆栈中的26个漏洞。[5] 在处理安全问题时,代码质量至关重要,无论是对于所有代码,还是对于开源组件。
代码分析工具有助于遵守标准
要提高应用程序的安全性,解决代码质量问题,我们可以采取哪些措施呢?简单的答案是使用代码分析工具,这些工具可以分为两种基本类型:静态分析和运行时(或动态)分析。静态分析仅检查应用程序的源代码,而运行时分析则在运行过程中对代码进行检测,寻找空指针和数据注入等漏洞。
优质的代码分析工具包括对CWE、MISRA和CERT C的检查。CERT C是另一个编码标准,旨在促进编码安全。这三个规则集共同构成了一个促进安全编码的强大组合:一些规则可能与其他规则重叠,但它们也提供了一些独特的功能,以确保代码的高度安全性。遵循这些标准还有助于确保代码质量的最佳水平,并可能发现代码中的潜在漏洞。
安全的代码是高质量的
确保代码质量才能保证代码的安全性。不要将代码质量的责任推卸给他人,因为别人的漏洞很可能就是你的安全噩梦。但是我们仍然可以抱有希望,因为代码分析工具可以帮助我们在漏洞变得严重之前快速发现问题。通往安全的道路必然要经过代码质量的关卡。
通过使用高质量的代码分析工具,并遵循相关的安全编码标准,我们可以大大提高应用程序的安全性,保护我们的代码免受潜在的安全漏洞和威胁。代码质量和安全是紧密相连的,而高水平的代码质量是确保系统安全的关键要素。
文章作者:Shawn Prestridge,IAR美国FAE团队负责人
参考资料
[1]https://www.caida.org/research/security/code-red/
[2]https://malware.wikia.org/wiki/Buffer_overflow
[3]https://cwe.mitre.org/data/definitions/121.html
[4]https://resources.sei.cmu.edu/asset_files/TechnicalNote/2014_004_001_428597.pdf
[5]https://www.techradar.com/news/usb-systems-may-have-some-serious-security-flaws-especially-on-linux