首页>参考读物>计算机科学与技术>综合

C安全编码标准
作者 : (美)Robert C. Seacord
译者 : 徐波 等译
出版日期 : 2009-11-10
ISBN : 978-7-111-28442-0
定价 : 69.00元
扩展资源下载
扩展信息
语种 : 简体中文
页数 : 514
开本 : 16
原书名 : The Cert C Secure Coding Standard
原出版社: Pearson Education Asia
属性分类: 店面
包含CD :
绝版 : 未绝版
图书简介

本书是一本重要的桌面参考手册,它记录了《CERT C安全编码标准》的第1次官方发布。这个标准逐项描述了C语言程序中导致软件潜在风险根源的编码错误,并根据严重性、被利用的可能性以及修补成本设置了优先级。每个指导方针提供了不安全代码的例子以及安全的替代方案。如果统一应用这些指导方针,它们可以消除可能导致缓冲区溢出、格式字符串潜在风险、整数溢出和常见的软件潜在风险的关键编码错误。

图书特色

每一位C程序员的案头必备
实现C安全编程的权威指南

C安全编码标准
(美)Robert C. Seacord  著
 徐 波 等译

“我是CERT安全编码活动的热情支持者。程序员可以找到关于正确性、清晰性、可维护性、性能等方面的很多建议,但对于特定的语言特性如何影响安全性方式的建议则明显缺乏。本书填补了这个空白。”
—— Randy Meyers,ANSI C主席
“在过去的几年里,我们依赖于CERT/CC公布各种建议,它们记录了无尽的安全问题。现在,CERT已经汇集了前沿技术专家的建议,向程序员和项目经理提供了实用的指导方针,避免在新的应用程序中出现这些问题,并帮助实现安全的遗留系统。干得好!”
—— Thomas Plum,Plum Hall,Inc.创始人
“互联网的存在极大地增加了对安全、防黑客应用程序的需要。通过组合这个CERT标准和其他安全指导方针,顾客可以获得全面的保护以及创建零缺陷软件的方法。”
—— Chris Tapp,领域应用程序工程师,LDRA Ltd.
“我觉得这个标准是无可代替的,它汇集了许多专家信息,让我们了解现代的软件系统在实践中是如何失败的。它是创建一个国际安全编码指导方针的良好起点。其他地方找不到这样的信息。就软件安全这个问题而言,你不知道的东西常常会给你带来伤害。”
—— John McDonald,《The Art of Software Security Assessment》的作者之一

软件安全性对于公司的运作和财富具有很大的影响,与个人的生活也息息相关。为了创建安全的软件,开发人员必须知道什么地方存在危险。C的安全编码要比许多经验丰富的程序员所想像的更为困难。
本书是一本重要的桌面参考手册,记录了《CERT C安全编码标准》的第一次官方发布。这个标准逐项描述了C语言程序中导致软件潜在风险根源的编码错误,并根据严重性、被利用的可能性以及修补成本设置了优先级。每个指导方针提供了不安全代码的例子以及安全的替代方案。如果统一应用这些指导方针,可以消除可能导致缓冲区溢出、格式字符串潜在风险、整数溢出和常见的软件潜在风险的关键编码错误。

作者简介
Robert C. Seacord 在位于宾夕法尼亚州匹兹堡市的软件工程协会(SEI)的CERT小组倡导了安全编码活动。他是《Secure Codeing in C and C++》(Addison-Wesley,2005)和另外两本书的作者。除了其他与安全相关的活动,CERT还定期分析软件潜在风险报告,并评估它们对Internet和其他关键的基础结构的风险。无数的专家为这个开放的开发过程作出了贡献,并对组成这个标准的规则和建议进行了审核。

图书前言

在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次发布相关的补丁或者这个潜在风险的描述被贴到一个公开的邮件列表时。在默认情况下,这个日期被设置为这个潜在风险说明的公布日期。
  潜在风险的名称。潜在风险的名称是一个简单的描述,对问题的本质以及所影响的软件产品进行了总结。虽然这个名称可能包含了一个条款,描述了这个潜在风险的后果,但大多数名称专注于导致问题发生的缺陷本质。

上架指导

程序设计

封底文字

“我是CERT安全编码活动的热情支持者。程序员对于正确性、清晰性、可维护性、性能等方面的建议具有很多需求,但对于特定的语言特性如何影响安全性方式的建议则明显缺乏。《CERT? C安全编码标准》填补了这个空白。”
——Randy Meyers,ANSI C主席

“在过去的几年里,我们依赖CERT/CC公布各种建议,它们记录了无尽的安全问题。现在,CERT已经汇集了前沿技术专家的建议,向程序员和项目经理提供了实用的指导方针,避免在新的应用程序中出现这些问题,并帮助实现安全的遗留系统。干得好!”
——Thomas Plum,Plum Hall,Inc.的创始人

“互联网的存在极大地增加了对安全、防黑客应用程序的需要。通过组合这个CERT标准和其它安全指导方针,顾客可以获得全面的保护以及创建零缺陷软件的方法。”
——Chris Tapp,领域应用程序工程师,LDRA Ltd.

“我觉得这个标准是无可代替的,它汇集了许多专家信息,让我们了解现代的软件系统在实践中是如何失败的。它是创建一个国际安全编码指导方针的良好起点。其它地方找不到这样的信息。就软件安全这个问题而言,你不知道的东西常常会给你带来伤害。”
——John McDonald,《软件安全评估艺术》的共同作者

软件安全性对于公司的运作和财富具有很大的影响,对于个人的生活也是息息相关。为了创建安全的软件,开发人员必须知道什么地方存在危险。C的安全编码要比许多经验丰富的程序员所想像的更为困难。

本书是一本重要的桌面参考手册,它记录了《CERT? C安全编码标准》的第1次官方发布。这个标准逐项描述了C语言程序中导致软件潜在风险根源的编码错误,并根据严重性、被利用的可能性以及修补成本设置了优先级。每个指导方针提供了不安全代码的例子以及安全的替代方案。如果统一应用这些指导方针,它们可以消除可能导致缓冲区溢出、格式字符串潜在风险、整数溢出和常见的软件潜在风险的关键编码错误。

Robert C. Seacord在位于宾夕法尼亚州匹兹堡市的软件工程协会(SEI)的CERT小组倡导了安全编码活动。他是《Secure Codeing in C and C++》(Addison-Wesley,2005)和另外两本书的作者。CERT以及其它与安全相关的活动定期分析软件潜在风险报告,并评估它们对Internet和其它关键的基础结构的风险。无数的专家为这个开放的开发过程作出了贡献,并对组成这个标准的规则和建议进行了审核。

作者简介

(美)Robert C. Seacord:暂无简介

译者简介

徐波 等译:暂无简介

图书目录

关于作者
前言
第1章本标准使用说明系统质量
自动生成的代码
顺应性
第2章预处理器(PRE)
建议和规则
风险评估汇总
相关规则和建议
PRE00C用内联函数或静态函数代替与函数相似的宏
PRE01C在宏参数名两边加上括号
PRE02C宏替换列表应该加上括号
PRE03C应该使用typedef定义编码类型
PRE04C不要复用标准头文件名
PRE05C理解连接标记或执行字符串化时的宏替换
PRE06C把头文件放在包含防护条件中
PRE07C避免使用连续的问号
PRE08C保证头文件名惟一
PRE09C不要用不安全的函数替换安全函数
PRE10C在一个dowhile循环中包装多条语句的宏
PRE30C不要通过连接创建统一字符名称
PRE31C不要在不安全宏的参数中包含赋值、增值、减值、volatile访问或函数调用
第3章声明和初始化(DCL)
建议和规则
风险评估汇总
DCL00C 用const限定不可修改的对象
DCL01C不要在子作用域中复用变量名
DCL02C使用视觉区别明显的标识符
DCL03C使用静态断言测试常量表达式的值
DCL04C不要在一个声明中声明超过1个的变量
DCL05C使用typedef声明提高代码的可读性
DCL06C使用有意义的符号常量表示程序逻辑中的字面值
DCL07C在函数声明器中包含适当的类型信息
DCL08C在常量定义中对关系进行正确的编码
DCL09C把返回errno错误代码的函数的返回类型声明为errno_t
DCL10C维护变参函数的编写者和调用者之间的契约
DCL11C理解与变参函数相关联的类型问题
DCL12C使用不透明类型实现抽象数据类型
DCL13C把不会被函数修改的值指针参数声明为const
DCL14不要对跨翻译单元的全局变量的初始化顺序作出假设
DCL15C把不需要外部链接的对象声明为static
DCL30C声明具有正确存储持久期的对象
DCL31C在使用标识符之前声明它们
DCL32C保证相互可见的标识符是惟一的
DCL33C保证函数实参中具有限制性限定的源指针和目标指针不引用重叠的对象
DCL34C对无法缓存的数据使用volatile
DCL35C不要使用与函数定义不匹配的类型转换函数
DCL36C不要声明具有冲突链接属性的标识符
第4章表达式(EXP)
建议和规则
风险评估汇总
相关的规则和建议
EXP00C使用括号保证操作的优先级
EXP01C不要用指针的长度确定它所指向类型的长度
EXP02C注意逻辑AND和OR操作符的短路行为
EXP03C不要认为结构的长度等于它的各个成员的长度之和
EXP04C不要在结构之间执行逐字节的比较
EXP05C不要转换掉const限定
EXP06C sizeof操作符的操作数不应该包含副作用
EXP07C不要在表达式中对常量的值作出假设而削弱常量的优点
EXP08C确保正确地使用指针运算
EXP09C使用sizeof确定类型或变量的长度
EXP10C不要依赖子表达式的求值顺序或副作用的发生顺序
EXP11C不要把期待一种类型的操作符应用于一种不兼容的类型
EXP12C不要忽略函数的返回值
EXP30C不要依赖序列点之间的求值顺序
EXP31C避免断言的副作用
EXP32C不要转换掉volatile限定
EXP33C不要引用未初始化的内存
EXP34C保证不对null指针进行解引用
EXP35C不要在后续的序列点之后访问或修改一个函数的调用结果中的数组
EXP36C不要把指针转换为对齐要求更严格的指针类型
EXP37C调用函数时使用API所指定的参数
EXP38C不要在位段成员或非法类型上调用offsetof()
第5章整数(INT)
建议和规则
风险评估汇总
相关的规则和建议
INT00C理解编译器所使用的数据模型
INT01C使用rsize_t或size_t类型表示所有表示对象长度的整数值
INT02C理解整数转换规则
INT03C使用安全的整数库
INT04C对来自不信任来源的整数值实行限制
INT05C如果输入函数无法处理所有可能出现的错误就不要用它们转换字符数据
INT06C使用strtol()或相关函数把字符串标记转换为整数
INT07C只使用显式的有符号或无符号char类型表示数值
INT08C验证所有的整数值位于范围内
INT09C保证枚举常量映射到惟一数值
INT10C使用%操作符时不要假设余数总是正的
INT11C把指针转换为整数或者把整数转换为指针时需要小心
INT12C当普通的整数位段用于表达式时,不要对它的类型作出假设
INT13C只对无符号操作数使用位操作符
INT14C避免在同一个数据上执行位操作和算术运算
INT15C在程序员定义的整数类型的格式化I/O中使用intmax_t或uintmax_t
INT30C保证无符号整数运算不产生回绕
INT31C保证整型转换不会丢失或错误解释数据
INT32C保证有符号整数运算不会产生溢出
INT33C保证除法和求模运算不会导致除零错误
INT34C移位的数量不能是负数或大于操作数的位数
INT35C把整型表达式比较或赋值为一种较大类型之前用这种较大类型对它进行求值
第6章浮点数(FCP)
建议和规则
风险评估汇总
相关规则和建议
FLP00C理解浮点数的限制
FLP01C在重新排列浮点表达式时需要注意
FLP02C需要精确计算时避免使用浮点数
FLP03C检测和处理浮点错误
FLP30C不要使用浮点数作为循环计数器
FLP31C不要用复数调用期望接受实数的函数
FLP32C防止或检测数学函数中的定义域错误和值域错误
FLP33C执行浮点运算时把整数转换为浮点数
FLP34C保证浮点转换位于新类型的范围之内
第7章数组(ARR)
建议和规则
风险评估汇总
相关规则和建议
ARR00C理解数组的工作方式
ARR01C获取数组的长度时不要对指针应用sizeof操作符
ARR02C显式地指定数组的边界,即使它已经由初始化值列表隐式地指定
ARR30C保证数组索引位于合法的范围之内
ARR31C在所有源文件中使用一致的数组记法
ARR32C保证变长数组的长度参数位于合法范围之内
ARR33C保证复制的目标具有足够的存储空间
ARR34C保证表达式中的数组类型是兼容的
ARR35C不允许循环迭代到数组尾部之后
ARR36C不要对两个并不指向同一个数组的指针进行相减或比较
ARR37C不要把一个指向非数组对象的指针加上或减去一个整数
ARR38C如果结果值并不引用合法的数组元素,不要把指针加上或减去一个整数
第8章字符和字符串(STR)
建议和规则
风险评估汇总
相关规则和建议
STR00C使用适合的类型表示字符
STR01C采纳和实现一致的字符串管理计划
STR02C对传递给复杂子系统的字符串数据进行净化
STR03C不要意外地截断null结尾的字节字符串
STR04C使用普通char类型表示基本字符集中的字符
STR05C引用字符串常量时使用const指针
STR06C不要以为strtok()会使解析的字符串不被修改
STR07C使用TR 24731修正现在的字符串操纵代码
STR08C使用托管字符串开发新的字符串操纵代码
STR30C不要试图修改字符串常量
STR31C保证字符串的存储具有足够的空间容纳字符数据和null结尾符
STR32C根据需要将字符串用null结尾
STR33C正确地判断宽字符串的长度
STR34C在转换为更大的整型长度时把字符转换为无符号类型
STR35C不要把未检查边界来源的数据复制到固定长度的数组
STR36C不要指定用字符串常量初始化的字符数组的边界
STR37C字符处理函数的参数必须能够用unsigned char表示
第9章内存管理(MEM)
建议和规则
风险评估汇总
相关规则和建议
MEM00C在同一个模块、同一个抽象层中分配和释放内存
MEM01C在free()之后立即在指针中存储一个新值
MEM02C把内存分配函数的调用结果立即转换为指向被分配类型的指针
MEM03C及时清除存储在可复用资源中的敏感信息
MEM04C不要执行零长度的分配
MEM05C避免大型的堆栈分配
MEM06C保证敏感数据不会被写入到磁盘
MEM07C保证calloc()的参数相乘后可以用size_t表示
MEM08C只把realloc()用于改变动态分配数组的大小
MEM09C不要假设内存分配函数会对内存进行初始化
MEM10C定义和使用指针验证函数
MEM30C不要访问已经被释放的内存
MEM31C动态分配的内存只应释放一次
MEM32C检测和处理内存分配错误
MEM33C使用正确的语法表示灵活数组成员
MEM34C只释放动态分配的内存
MEM35C为对象分配足够的内存
第10章输入/输出(FLO)
建议和规则
风险评估汇总
相关规则和建议
FIO00C在创建格式字符串时应该小心
FIO01C调用通过文件名标识文件的函数时必须小心
FIO02C对来自不信任来源的路径名进行标准化
FIO03C不要对fopen()和文件的创建作出假设
FIO04C检测和处理输入和输出错误
FIO05C使用多个文件属性标识文件
FIO06C创建具有正确访问权限的文件
FIO07C用fseek()代替rewind()
FIO08C在打开的文件上调用remove()时应该小心
FIO09C跨系统传输二进制数据时应该小心
FIO10C使用rename()函数时应该小心
FIO11C指定fopen()的mode参数时应该小心
FIO12C使用setvbuf()代替setbuf()
FIO13C不要压回多于1个的字符
FIO14C理解文件流的文本模式和二进制模式的区别
FIO15C保证文件操作在安全目录中执行
FIO16C通过创建jail限制对文件的访问
FIO30C排除格式字符串中的用户输入
FIO31C不要打开已经被打开的文件
FIO32C不要在专用于文件的设备上执行操作
FIO33C检测和处理导致未定义行为的输入输出错误
FIO34C使用int捕捉字符I/O函数的返回值
FIO35C当sizeof(int) == sizeof(char)时使用feof()和ferror()检测文件尾和文件错误
FIO36C不要假设fgets()会读取换行符
FIO37C不要假设被读取的是字符数据
FIO38C不要使用FILE对象的拷贝进行输入和输出
FIO39C不要在没有干预刷新或定位调用的情况下在一个流中交替地执行输入和输出
FIO40C在fgets()失败时重置字符串
FIO41C调用getc()或putc()时不要使用具有副作用的流参数
FIO42C保证当文件不再需要时及时将它们关闭
FIO43C不要在共享目录中创建临时文件
FIO44C只在fsetpos()中使用fgetpos()所返回的值
第11章环境(ENV)
建议和规则
风险评估汇总
相关规则和建议
ENV00C不要存储指向getenv()返回的字符串的指针
ENV01C不要对环境变量的长度作出假设
ENV02C注意具有相同有效名称的多个环境变量
ENV03C 调用外部程序时对环境进行净化
ENV04C如果不需要命令处理器就不要调用system()
ENV30C不要修改getenv()所返回的字符串
ENV31C在可能无效化环境指针的操作之后不能再依赖它
ENV32C所有的atexit处理函数都不能以除了正常返回之外的其他任何方式终止
第12章信号(SIG)
建议和规则
风险评估汇总
相关规则和建议
SIG00C屏蔽由不可中断的信号处理函数所处理的信号
SIG01C理解与信号处理函数的持久性有关的平台特定的细节
SIG02C避免使用信号实现常规的功能
SIG30C只在信号处理函数中调用异步安全的函数
SIG31C不要访问和修改信号处理函数中的共享对象
SIG32C不要在信号处理函数中调用longjmp()
SIG33C不要递归地调用raise()函数
SIG34C不要在不可中断的信号处理函数内部调用signal()
第13章错误处理(ERR)
建议和规则
风险评估汇总
相关规则和建议
ERR00C采用和实现一致的、全面的错误处理策略
ERR01C使用ferror()而不是errno检查FILE流错误
ERR02C避免带内错误指示符
ERR03C调用TR24731-1所定义的函数时使用运行时约束处理函数
ERR04C选择一种适当的终止策略
ERR05C独立于应用程序的代码应该在不提示错误处理的情况下提供错误检测
ERR06C理解assert()和abort()的终止行为
ERR30C调用设置errno的库函数之前把errno设置为0,并且在函数返回一个提示失败的值之后检查errno
ERR31C不要重定义errno
ERR32C不要依赖errno的不确定值
第14章其他(MSC)
建议和规则
风险评估总结
MSC00C在高警告级别进行干净的编译
MSC01C实现逻辑完整性
MSC02C避免因为省略所导致的错误
MSC03C避免因为多余所导致的错误
MSC04C用一种可读的风格一致地使用注释
MSC05C不要直接维护time_t类型的值
MSC06C处理敏感数据时注意编译器的优化
MSC07C检测和删除死代码
MSC08C库函数应该对形参进行验证
MSC09C字符编码:使用ASCII的子集以保证安全
MSC10C字符编码:UTF8相关的问题
MSC11C使用断言进行诊断测试
MSC12C检测和删除没有效果的代码
MSC13C检测和删除未使用的值
MSC14C不要引入不必要的平台依赖性
MSC15C不要依赖未定义的行为
MSC30C不要使用rand()函数产生伪随机数
MSC31C保证返回值与适当的类型进行比较
附录POSIX(POS)
建议和规则
风险评估汇总
相关的规则和建议
POS00C避免多线程的竞争条件
POS01C检查链接是否存在
POS02C遵循最小特权原则
POS30C正确地使用readlink()函数
POS31C不要解锁或销毁另一个线程的mutex
POS32C在多线程环境中使用位段时包含一个mutex
POS33C不要使用vfork()
POS34C不要用一个指向自动变量的指针为参数调用putenv()
POS35C避免检查符号链接是否存在时的竞争条件
POS36C在撤消特权时注意正确的撤消顺序
POS37C保证特权的撤消是成功的词汇表
参考资料

教学资源推荐
作者: 徐洁磐
作者: (美)M. Morris Mano; Charles R. Kime 著
作者: 蒋榴英 孙金秋 傅忠云 编著
作者: Larry Snyder; Calvin Lin
参考读物推荐
作者: [美]查克·希曼(Chuck Hemann) 肯·布尔巴里(Ken Burbary) 著
作者: 恽如伟 董浩 等编著
作者: 刘显铭 等著