在C编程语言中,安全编码的一个本质要素是具有良好文档的、可实行的编码标准。编码标准鼓励程序员遵循一组根据项目或组织的要求所确定的统一指导方针,而不是根据程序员的熟悉或偏好来作出决定。编码标准一经确立之后,就可以作为标尺,对源代码进行评估(使用手工或自动的过程)。.
《CERT C安全编码标准》(The CERT C Secure Coding Standard)提供了在C编程语言中进行安全编码的指导方针。这些指导方针的目标是消除不安全的编码实践以及可能被利用而导致潜在风险的未定义行为。在开发代码时遵循这些标准将会产生高质量的软件系统,使它们具有更健壮的行为,对攻击的抵抗性也更强。
本标准受到软件工程协会(SEI)和其他得到许可的伙伴培训部门的支持,并可以作为全球信息保证认证(GIAC)安全软件程序员-C(GSSP-C)考试和认证的基础。
安全软件的需求
1988年11月发生的Morris蠕虫事件导致10%的Internet系统中止,并使人们对安全软件系统有了一个新的、准确的认识。20年后,许多安全分析师、软件开发人员、软件用户和策略制定者都在问同一个问题:“为什么软件不能变得更安全?”
首要的问题是“软件安全”这个术语用在当今已经没有意义。和其他人一样,我也试图定义这个术语,但是并不存在被广泛接受的定义。这是为什么呢?
人们已经提出了软件不能变得更安全的各种原因:工具不够充足、程序员缺乏足够的培训、开发周期太短等。但是,这些都是可以克服的问题。问题的根源在于其他方面。
软件不能变得更安全的原因是缺少对安全软件的需要。简单地说,如果一家开发商已经推出了一种功能更丰富、性能更出色的产品,而另一家开发商却提供了一种虽然安全但功能和性能稍差的产品,并且6个月之后才能上市。毫无疑问,顾客会购买第一种产品,生产商也深知这一点。
为什么顾客不愿购买安全产品呢?这是由于“安全”这个词在这种情况下是没有意义的。顾客为什么要放弃看得到的好处,而去购买一种定义不明确的、不可触摸的属性呢?
本编码标准就致力于解决这个问题。虽然在开发代码时遵循这个标准并不保证软件系统的安全性,但是它向我们提供了大量与代码的质量和安全有关的知识。它告诉我们在开发软件时应该遵循一组由该领域的前沿专家所开发的行业标准的规则和建议。它还告诉我们在开发软件时遵循这个标准可以使我们把注意力和精力集中在编写代码上,而不会受到一些常见的编码错误的困扰。在过去的20年里,CERT协作中心(CERT/CC)已经接到报告并发表了无数由于这些编码错误导致的潜在风险。它告诉我们生产代码的软件开发人员对违反这个标准可能导致并被利用的各种潜在风险具有深入的理解,因此在开发软件时头脑中已经形成了真正的安全思想。
因此,我们在本书中已经着手处理的一个“小”问题是改变开发和购买软件系统的市场动态。通过为C语言程序产生一个“可供行动参考的和可测量的”定义,即遵循这个标准中的规则和建议。我们定义了一种机制,顾客可以通过这种机制来要求安全的软件系统,而生产商也可以根据这种机制来满足顾客的要求。而且,由于“安全”这个词有了确切的含义,因此安全系统这个概念也开始变得有价值。
社区开发过程
《CERT C安全编码标准》的开发历时两年半的时间,是226位撰稿人和评论人共同努力的结晶。
这个标准的开发过程如下:
1)编码标准中的建议和规则来自致力于C编程语言开发和应用的社区,包括负责C标准和用户组的正式标准机构。
2)这些规则和建议的内容和风格由CERT技术部门和业界专家通过CERT安全编码标准wiki(www.securecoding. cert. org)进行编辑。
3)用户社区通过穿插讨论和其他通信工具对公开张贴的内容进行审查和评论。这个标准的草案在London和Kona会议上由ISO/IEC WG14进行审阅,并接受公众(包括C和C++用户协会ACCU以及comp.lang.c新闻组)的审查。
Wiki和本书
在wiki上开发一个安全编码标准具有许多优势。但是,它的一个缺点是其内容不断发生变化。如果希望得到最新的信息或者有兴趣研究还没有完全通过审查的新变化,这当然是很理想的。但是,许多软件开发组织需要一个最终文档,然后它们才能致力于遵循一组(固定的)规则和建议。本书的目标就是作为《CERT C安全编码标准》的1.0版。
自2008年6月本书出版之后,1.0版就开始和安全编译标准的wiki版本出现差异。由于它们所讨论的都是C语言,并且我们对如何安全地使用C语言的认识仍在进步之中,所以CERT将继续在安全编码wiki上发展《CERT C安全编码标准》。这些变化可能会在将来融入到本标准的官方发布版本中。
. 目标
本书向开发人员提供了用C编程语言进行安全编码的指导方针。这些指导方针具有各种用途。首先,它们列举了在C语言编程中可能导致缺陷、漏洞和软件潜在风险的常见错误。对于这些错误,标准并没有要求遵循标准的编译器产生致命的诊断信息。换句话说,编译器常常在不发出任何警告的情况下产生可执行文件,并可以被部署和发行。最终的软件仍然可能包含缺陷,具有被攻击的潜在风险。
其次,这个编码标准提供了如何创建安全代码的建议。不遵循这些标准并不意味着软件一定是不安全的,但是如果遵循这些建议,它们可以成为强大的工具,帮助消除软件中的潜在风险。
再次,这个编码标准标识了不可移植的编码实践。移植性并不是安全的严格需求,但代码中不可移植的假设总是一个隐患,当代码移植到这些假设不再有效的平台时,就会导致潜在风险。
规则
本书的指导方针分为规则和建议两种。如果满足下面的条件,指导方针就会定义为规则:
1)违反编码实践有可能导致安全缺陷,产生可被利用的潜在风险。
2)违反这种编码实践仍然可以保证正确行为的情况是屈指可数的。
3)可以通过自动分析、形式方法或手工检查技巧检查是否遵循编码标准。
要保证用C编程语言所开发的软件系统的安全性,实现本标准所定义的安全编码规则是必需的(但并不充分)。图P-1展示了这个安全编码标准的89个规则是如何分类的。
建议
如果满足下面的条件,指导方针就会定义为建议:
1)应用这种编码实践可能会提高系统的安全性。
2)由于未满足一个或多个编码实践的需求,而不能定义为规则。
特定的开发实践所采纳的建议数量取决于最终的软件产品的安全需求。具有很高安全需求的项目可能会重视安全方面的资源,因此所采纳的建议可能更多。
图P-2展示了这个安全编码标准中的132个建议是如何分类的。
图P-1CERT安全编码规则
为了保证源代码遵循这个安全编码标准,有必要采取措施检查违反规则的情况。实现这个目的的最有效方法就是使用一种或多种静态分析工具。如果工具无法检查某个规则,就需要采用手工检查的办法。
为了自动检测违反CERT C安全编码标准的规则和建议的情况,可以使用免费的和商业的源代码分析工具,包括Compass/ROSE,它是由Lawrence Livermore National Laboratoy开发的,并由CERT进行了扩展(www.rosecompiler.org)。
范围
《CERT C安全编码标准》专门用于下面这些出版物所定义的C编程语言的各个版本:
ISO/IEC 9899:1999,Bogramming Languages-C,第2版【ISO/IEC 9899:1999】
技术勘误TC1、TC2和TC3
ISO/IEC TR 24731-1,Extensions to the C Library,第1部分:边界检查接口【ISO/IEC TR 24731-1:2007】
ISO/IEC TR 24731-2,Extensions to the C Library,第2部分:动态分配函数【ISO/IEC TR 24731-2】
图P-2 CERT安全编码建议
这个标准所包含的大多数材料也适用于早期版本的C编程语言。
这个标准所包含的规则和建议是为了实现代码的操作系统和平台独立性。但是,安全编码问题的最佳解决方案常常是平台特定的。在大多数情况下,这个标准为遵循POSIX的操作系统和Windows操作系统提供了顺应性解决方案。在许多情况下,也为像Linux和OpenBSD这样的特定平台提供了顺应性解决方案。偶尔,我们会在相关的场合指出平台特定的行为。
基本原则
C编程语言的安全编码标准专注于C99和相关的后C99技术报告,可以在最长时间内创造最大的价值。另外,由于开发新代码所耗费的金钱和努力远远多于维护现有的代码,最大的投资回报来自于开发新代码的有影响的程序员【Seacord 03】。但是,维护现有的代码仍然是一个重要的问题。
C标准(C99)尽可能地记录了现有的实践【ISO/IEC 9899:1999】。也就是说,大多数特性必须在一种实现中进行测试,然后才能添加到标准中。《CERT C安全编码标准》的目标不是这样。如果现有的实践符合它的目标,那当然很好。但是,它的目标是创建一组新的实践,包括引入一些尚未广为人知的概念。换句话说,CERT C安全编码指导方针试图驱使人们采用新的实践,而不仅仅是用文档记录它们。
例如,C函数库技术报告第1部分(TR 24731-1)正在日益壮大,但是目前只有少数厂商实现了它。它引入了像memcpy_s()这样的函数,这个函数通过在API中添加目标缓冲区的长度来实现安全目的。有远见的文档不会仅仅因为这些函数还没有广泛实现就忽略它们。
C99的实现较TR 24731-1更为普及。但是,即使在它尚未实现的场合,它仍然是业界前进的方向。尤其是开发新的C代码的开发人员,更希望能够最大限度地利用现在正在开发并对将来提供支持的编译器和其他工具。
有些厂商提供了C的扩展,还有些厂商在停止开发之前只实现了C标准的一部分。因此,不可能倒退回来,只讨论C90或C95。厂商对这个标准的支持非常复杂,很难简单地划一条线,表示一种特定的编译器正好支持标准的某一部分。不管选择的分界点是什么,站在对立面的厂商会抓住语言的不同部分各执一词。支持所有的可能性就需要在每个编译器上对每个语言特性都进行测试。因此,最近所选择的一个分界点是尽可能地使这个标准所定义的规则和建议可以应用。作为不同支持形式的结果,如果程序员只使用C90所指定的特性,就可以提高源代码的可移植性。这是C语言所固有的安全和移植性之间的许多权衡之一。
具有远见的信息的价值随着时间的增长会增加,而缺乏远见的信息的价值会很快变小。
由于这些原因,这个标准优先支持使用C99和后C99技术报告进行新代码的开发,另一个差不多的优先支持是使用C99和技术报告修正旧代码。
如果作用重大并且不会影响其他优化的目的,这个标准还会努力提供对旧式编译器的支持。它的意图并不是捕捉标准的所有偏离,只是捕捉其中一些较为重要的偏离。
未处理的问题
有一些问题是这个安全编码标准并没有解决的。
编码风格。编码风格问题是主观的,不可能在什么是最适当的编码风格上达成一致。因此这个标准并没有要求实行任何特定的编码风格,只要求用户定义编码风格的指导方法,并坚持使用这些指导方针。一致地使用一种编码风格最容易的方法是使用一种代码格式化工具。许多交互性开发环境(IDE)提供了这样的功能。
工具。作为政府资助的研究和开发中心(FFRDC),SEI所处的位置并不是推荐特定的厂商和工具以实行这些指导方针。这个文档的用户可以自由地选择工具,并且鼓励厂商提供工具实行这些标准。
有争议的规则。一般而言,CERT安全编码标准试图避免包含缺乏广泛一致的具有争议的规则。
本书适合的读者
本书主要适用于C语言程序的开发人员。虽然安全对于面向Internet的系统非常重要,但是对于那些可能被包含或部署在安全软件系统中的任何软件组件,安全也是非常重要的。由于越来越多的软件系统是由软件组件所组成的,甚至是由其他软件系统组成的,因此很难保证软件不在需要安全的环境中使用,甚至是在安全要求极为严格的环境中使用。
本书还适用于那些没有意识到安全问题的C语言程序员,因为这些指导方针对于实现其他质量属性(如安全、可靠、健壮、可用和可维护性)也有很大的实用价值。
虽然本书并不面向C++程序员,但是由于C语言程序所涉及的许多问题在C++程序中也存在,因此,尽管在许多情况下它们的解决方案是不同的,但是本书对C++编程也有一定的参考价值。
本书的组织形式
本书包括一个介绍性章节,13个包含了特定主题领域的指导方针的章节,一个包含了POSIX指导方针的附录,演示了这个安全编码标准如何针对一个特定平台进行自定义。POSIX附录是非正式的,并不是这个标准的规定部分。
大多数指导方针具有一致的结构。这个标准中的每个指导方针都具有惟一的标识符,包含在标题中。指导方针的标题和介绍段落定义了规则或建议,接下来,一般是一对或多对非顺应性代码例子和顺应性解决方案。每个指导方针还包括了风险评估和参考资料。指导方针有可能包含一张相关潜在风险的表格。
指导方针标识符
指导方针标识符由3个部分组成:
由3个字母组成的助记符,表示标准中的节。
范围在00-99之间的一个两位数。
字母C表示这是C语言指导方针。..
三字母助记符可以用于对相似的指导方针进行分组,并提示一个指导方针属于哪个分类。
两位数用于为每个指导方针提供一个惟一的标识符。范围在00-29的数值为建议而保留,范围在30-99的数值为规则而保留。
非顺应性代码例子和顺应性解决方案
非顺应性代码例子是违背了当前所讨论的指导方针的不安全代码例子。注意,这些只是例子,消除这些例子并不意味着代码已经遵循了当前的指导方针。
在非顺应性代码例子之后一般是顺应性解决方案,它显示了非顺应性代码例子可以怎样以安全、顺应的方式重新实现。除非另有说明,非顺应性代码例子应该只包含对当前所讨论规则的违反。顺应性解决方案应该遵循所有的安全编码规则,但偶尔可能无法遵循某个建议。
风险评估
每个指导方针都包含了一个风险评估小节,它试图对违反每个指导方针的风险都进行量化和质化。这个信息主要用于在修补项目时帮助确认修补的优先级,并假设新代码的开发完全遵循整个标准。
每个规则和建议都具有一个优先级。优先级是根据失败模式、效果和危急分析(FMECA)进行度量的【IEC/ 60812】。每个规则分别设置3个1-3之间的值。
严重性:忽略这个规则后果的严重程度。
1:低(拒绝服务攻击、异常终止)。
2:中等(数据完整性被破坏、违背意图的信息泄露)。
3:高(运行任意代码)。
可能性:忽略这个规则所产生的缺陷导致可被利用的潜在风险的可能性。
1:不太可能。
2:有可能。
3:很可能。
修补成本:遵循这个规则的代价有多大。
1:高(手工检测并修正)。
2:中等(自动检查和手工修正)。
3:低(自动检测并修正)。
每个规则的这3个值相乘产生一个度量,可以作为应用这个规则的优先级。乘积的范围是1-27。优先级在1-4范围的规则和建议属于第3级别的规则,6-9属于第2级别的规则,12-27属于第1级别的规则。因此,可能通过实现某一个级别的所有规则,声明达到对一个标准的第1级顺应性、第2级顺应性和完全顺应性(级别3),如图P-3所示。
建议并不是强迫的,提供风险评估只是作为参考。
图P-3优先级和级别
参考资料
指导方针经常包含了对CERT/CC潜在风险备注数据库的潜在风险说明【CERT/CC VND】、MITRE的常见脆弱列举(CWE)中的CWE ID【MITRE 07】和来自MITRE的常见潜在风险和暴露的CVE编号的引用。
读者可以创建一个惟一的URL,通过在一个固定的字符串末尾添加一个相关的ID,获取与任何主题有关的信息。例如:
为了获取与VU#551436“Moxilla Firefox SVG浏览器的整数溢出潜在风险”有关的详细信息,可以在https://www.kb.cert/org/vulnotes/id/后面添加551436,并在浏览器中输入结果URL:https://www.kb.cert/org/vulnotes/id/551436。
为了获取与CWE ID 192“Integer Coercion Error”有关的详细信息,可以在http://cwe.mitre. org/data/definitions/后面添加192.html,并在浏览器中输入结果URL:http://cwe.mitre.org/data/definitions/192.html。
为了获取与CVE-2006-1174有关的详细信息,可以在http://cve.mitre.org/cgi_bin/ cvename. cgi?name=后面添加CVE-2006-1174,并且在浏览器中输入结果URL:http://cve.mitre.org/cgi_bin/cvename.cgi?name=CVE-2006-1174。
指导方针经常与“信息技术—编程语言—通过语言的选择和使用避免编程语言中的潜在风险”中的语言潜在风险相关【ISO/IEC PDTR 24772】。
相关潜在风险
与违背CERT/CC潜在风险备注数据库所公布的实际潜在风险相联系的规则和建议具有“相关潜在风险”这个小节,以表格形式出现,如下例子所示:
度量ID公布日期名称
1.62VU#6067002007年3月19日文件整数溢出潜在风险
2.06VU#5594442007年3月13日Apple Mac OS X ImageIO整数溢出潜在风险
22.22VU#5514362007年2月23日Mozilla Fireofx SVG浏览器存在整数溢出潜在风险
0VU#1622892006年4月17日C编译器可能会安静地丢弃一些回绕检查
新的链接不断地添加。最新的相关潜在风险的列表可在以下网址找到:
https//www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+XXXNN-X
其中,XXXNN-X是所搜索的规则或建议的ID。
这种表格由4个字段组成:度量、ID、公布日期和名称。
潜在风险的度量。CERT潜在风险的度量值是一个0-180之间的整数,近似地模拟了这个潜在风险的严重性。这个值合并了7个要素:
与这个潜在风险有关的信息是否广泛可知。
是不是向CERT或其他事件响应小组报告了由于这个潜在风险所导致的事件。
由于这个潜在风险的存在,是否对Internet基础结构(例如路由器、名称服务器、关键的Internet协议)产生了风险。
Internet上的多少系统受这个潜在风险的影响。
利用了这个潜在风险的后果有多严重。
这个潜在风险是不是很容易利用。
利用这个潜在风险是不是需要前提条件。
由于对这些问题的回答是根据潜在风险分析师的判断所产生的近似值,在不同的网站可能有明显的区别,因此不应该过度依赖潜在风险的度量来确定它们的响应优先级。度量值的主要作用是把严重的潜在风险从数据库中大量的不严重的潜在风险中分离出来。由于这些问题的权重不同,因此结果也不是线性分布的(也就是说,度量为40的潜在风险的严重性并不是度量为20的潜在风险的严重性的两倍)。
另一种潜在风险严重程序度量是公用潜在风险评分系统(CVSS)【Mell 07】。
潜在风险ID。潜在风险ID号是随机赋值的,是为了惟一地标识一个潜在风险。这些ID为4-6位数字,通常具有VU#前缀,表示它们是潜在风险ID。
公布日期。这是这个潜在风险被公开发布的日期。通常这个日期是在第1次公布这个潜在风险说明时、第1次被发现这个潜在风险的利用时、厂商第1次发布相关的补丁或者这个潜在风险的描述被贴到一个公开的邮件列表时。在默认情况下,这个日期被设置为这个潜在风险说明的公布日期。
潜在风险的名称。潜在风险的名称是一个简单的描述,对问题的本质以及所影响的软件产品进行了总结。虽然这个名称可能包含了一个条款,描述了这个潜在风险的后果,但大多数名称专注于导致问题发生的缺陷本质。...