《高质量程序设计艺术》样章连载——3.1 脆弱代码
<!---->1. <!---->深入剖析著名开源软件的质量问题<o:p></o:p>
<!---->2. <!---->全面阐述C、C++和Java代码中的常见编程错误<o:p></o:p>
<!---->3. <!---->指导你编写优秀代码的圣经<o:p></o:p>
<o:p> </o:p>
3.1 脆弱代码
错误潜藏在周围各处,一有机会就偷偷潜入。任何方法都是不完美的。<o:p></o:p>
(Error is all around us and creeps in at the least opportunity. Every method is imperfect.)<o:p></o:p>
——查尔斯·尼科尔(Charles Nicolle),法国细菌学家,诺贝尔医学奖得主
<o:p> </o:p>
软件安全性是一个复杂又独特的难题。可以用最弱环现象(weakest-link phenomenon)来描述软件安全性,不管你为系统的一部分提供的保护有多么完善,如果另一部分有安全漏洞,而你又碰上一个顽强的对手,那么你所有的努力都将付诸东流。相比之下,为满足其他非功能性软件需求,如为了让软件更加可移植、可靠、可用或者高效而采取的每个步骤,都将对最终的结果有着积极的作用。另外,只有根据需求才能正确判断安全性,在不同环境中需求的差别是很大的。同样的代码在某个环境中(例如,受防火墙保护的关系密切的用户团体)可能被认为是安全的,但是在另一个环境中(例如,互联网)则是不安全的。<o:p></o:p>
评估现有安全措施并规划新的安全措施时,正确的方法是进行安全专家们所说的风险分析(risk analysis):确定你想要保护的是什么,以及这些被保护的对象对你的重要性(你的资产以及它们的价值),找出你的资产所面临的风险,并对降低这些风险的各种方法进行评估。例如,本书就是你的资产之一,毫无疑问你认为这本书是一个非常宝贵的专业资源。本书面临的风险之一就是你把它借给一位同事,然后该同事相当自然地就忘记归还了。你可以拒绝出借本书以消除这种风险,但是这未免让你显得占有欲过强而且又过于猜疑;或者你可以将名字写在书的显著之处,这似乎是一个更好的方法。你拥有的另一项资产可能就是刚从饮水机里倒来的一杯水,可能会有人把它偷走。但是,因为这种事情发生的可能性很低,而且换杯水也是轻而易举的事,因此你的决定是接受这个风险,不采取任何措施。
评估一个系统时,解决各种复杂交互的典型方法是将注意力从产物转移到生产它的过程上。例如,新药的生产商不会呈交一瓶子药给监管局请求批文。实际上,药品公司需要提供各种文件,文件内容包括药品成分、研制过程以及严格书面证明的临床实验结果的细节。与此类似,为了判断软件的安全性,我们需要看到它的宿主环境的风险分析、综合需求、开发的详细过程以及完整的测试结果。<o:p></o:p>
上述各种因素的大部分都超出了本书的范围,在“进阶阅读”一节将列出一些很好的参考书目,对此这些书中有详细的介绍。在本章中,我们将局限在很窄的范围内,即给定一段源代码,我们要能够理解为满足典型安全需求所使用的一些重要实现模式与习惯用法,另外,同样重要的是还要能够嗅出危险的气味,即发现有可能导致安全漏洞的代码元素。因此,我们将首先研究哪些代码元素有益于我们的研究,然后转而关注一些普遍的代码安全问题:缓冲区溢出、竞态条件、问题API、不可信输入、结果验证以及数据泄漏和特权泄漏。最后,我们将讨论特洛伊木马代码以及能够帮助我们检查代码发现安全漏洞的工具。
<!---->
3.1 脆弱代码
在查找代码的漏洞时,忽略可以被攻击者任意修改和部署的代码(这种代码显然是不可信的),而将精力集中在可能会导致安全问题的代码,这样做可以提高效率。这样双管齐下,可以很快淘汰代码中不相干的绝大部分,把注意力集中在可能会被利用的有安全漏洞的代码上。在本节,我们将讨论如何分离出有危险的完整程序,而在3.7.4节中将研究如何分离出一个程序中的一部分。
<!----><!----><!---->让我们举一些例子来说明,在考虑了攻击者的能力的基础上如何缩小分析的范围。如果攻击者可以随便安装和运行应用程序(例如,正如一般Unix工作站上用户所能做的),那就没有必要对现有以普通用户权限运行的应用程序做脆弱性分析了,攻击者不大会在能够安装自己的攻击代码的情况下还费事去琢磨一个现有的应用。相反,如果有些应用程序是以特殊的权限(例如Unix环境中的setuid程序,或者在Windows系统中具有SeAssignPrimaryTokenPrivilege的程序)运行的,而攻击者缺乏安装此类程序的特权,那么这些程序就应该放在分析的范围之内。同样,从不可信的数据源接收数据的应用程序(例如,Web浏览器与邮件客户端)是应该做脆弱性分析的,因为攻击者有可能会利用这些程序来获得本地的访问权限,然后再利用其他漏洞来获得更高的特权。此外,如果攻击者可以物理地访问计算机并且安装不同版本的操作系统,那么针对该攻击者对操作系统源代码进行分析查找漏洞也就没有什么必要了(当然了,对于其他特权较低的攻击者而言该操作系统还是有漏洞的)。最后,考虑客户机/服务器应用,客户机被部署在不安全的计算机上,而服务器负责保护有价值的数据——这是很典型的情况。把某种攻击归咎于客户端程序的某个实现上的错误是没有诚意甚至是荒谬的,攻击者可以很轻松地将客户端程序用符合他们需要的某个程序替换。因此,客户端的代码不需要被考虑在安全性分析之列。以下摘自微软的安全建议的文字就是一个广为人知的例子,文中Samba CIFS客户端就被指责为对一个服务器的漏洞负有部分责任: 它说明了在错误的地点实施安全策略所导致的一个安全问题。
微软(R)WinNews 电子简讯
特刊,1995年10月20日
[...]
Samba SMB客户端允许其用户通过网络发送非法的网络命令。
<!---->迄今为止,Samba客户端是唯一不过滤此类非法命令的SMB客户端。
[...]
使用更新后的驱动程序,SMBCLIENT用户将只能访问由Windows 95
<!----><!----><!---->用户指定的共享文件夹。
<!----><!----><!---->要做到将精力集中在可能导致安全问题的代码上会更困难,主要是因为代码之间的交互是非常微妙的,而忽视这些交互恰恰就是很多安全漏洞之后潜藏的典型模式。尽管如此,以下两个属性通常标示出潜在的脆弱代码。
(1) 这些代码运行时具有的特权级别比攻击者的要高。
(2) 攻击者可以输入数据给这些代码,或者以其他方式来操作这些代码。
请注意,将这些代码放在防火墙或者安全的Web服务器之后并不能解决问题,只要不可信的数据能够输入给这些代码,就有安全性问题。
<!----><!----><!---->举例来说,如果有人试图通过互联网来攻击某台计算机,那么所有接收网络连接的程序(以及所有这些程序运行的其他程序)所包含的代码都应该接受安全漏洞检查。可以使用netstat –a命令(在Unix与Windows系统上均可用)来列出特定主机上接收来自互联网的连接的IP端口列表。表3-1和表3-2分别列出了在一台Windows工作站与一台Unix服务器上运行netstat命令的输出结果。在Unix系统上,fstat与lsof 程序可以用于将这些端口名映射到对应的程序。在Windows XP系统上,netstat的–o选项会列出在每个端口上监听的进程的进程ID,这些进程ID则可以进一步被用于映射到进程所对应的程序的名字,只要检查tasklist命令输出的任务列表即可。使用Process Explorer应用程序可以获得更多的细节信息。
<!----><!----><!----><!----><!----><!---->本地用户也可以利用代码的漏洞来获取更高级别的特权。Unix系统支持标记为setuid与setgid的文件,这种文件的代码执行时所具有的特权级别是由文件的属主或者所属组决定的。与此类似,在Windows系统中,一个对象(例如可执行文件或者服务)可以以某个特定用户、用户组或者安全主体的有效许可来运行,前提是具有适当权限的进程使用诸如CreateProcessAsUser的调用来激活它。这些程序中存在的安全漏洞会让攻击者获得对应用户或者用户组的特权。因此,这种程序也是很容易受到本地攻击的,具有在特定主机上执行程序的权限的用户能够利用这些程序的漏洞来获得进一步的权限。请注意有些攻击所做的是连续特权提升(privilege escalation):远程用户首先利用某个网络程序的漏洞获得对计算机的普通用户访问权限,然后基于这种访问权限利用某个在更高权限级别上运行的程序的漏洞获取更多的特权。请记住在某些情况下,一个网络程序可能会利用setuid机制,以更低的特权级别来运行,将攻击成功对系统带来的伤害降到最低。在Unix主机上,可以使用如下的命令获得以不同的特权级别运行的程序的列表:<o:p></o:p>
<!----><!----><!----><!----><!----><!---->
<o:p> </o:p>
<!----><!----><!---->另外,请注意典型的操作系统内核完全控制着特权管理。因此,内核代码总是会受到本地与远程攻击。在大多数情况下,内核代码还包含设备驱动程序与可加载到内核的模块。
表3-1 Unix服务器上开放的网络端口列表<o:p></o:p>
当前的网络连接(包括服务器)<o:p></o:p>
|
<!----><!----><!---->协议<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
tcp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
udp4<o:p></o:p>
|
接收队列<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
|
发送队列<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
0<o:p></o:p>
|
本地地址<o:p></o:p>
*.http<o:p></o:p>
*.submission<o:p></o:p>
*.smtp<o:p></o:p>
*.ssh<o:p></o:p>
*.imaps<o:p></o:p>
localhost.domain<o:p></o:p>
istlab.domain<o:p></o:p>
*.ntalk<o:p></o:p>
localhost.ntp<o:p></o:p>
istlab.ntp<o:p></o:p>
*.ntp<o:p></o:p>
*.1024<o:p></o:p>
localhost.domain<o:p></o:p>
istlab.domain<o:p></o:p>
*.syslog<o:p></o:p>
|
远程地址<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
*.*<o:p></o:p>
|
状态<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
LISTEN<o:p></o:p>
|
最后,需要提醒的是成功的攻击并不一定做了特权提升。有些攻击者可能会发动拒绝服务(denial-of-service,DoS)攻击,让某个系统或者某项服务不可用。任何通过网络提供服务的程序,如果在收到恶意编排的数据时会崩溃,那么这种攻击对于这个程序来说就是危险的。
表3-2 微软Windows工作站上开放的网络端口列表<o:p></o:p>
当前的网络连接<o:p></o:p>
|
<!----><!----><!---->协议<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
TCP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
UDP<o:p></o:p>
|
本地地址<o:p></o:p>
eagle:epmap<o:p></o:p>
eagle:microsoft-ds<o:p></o:p>
eagle:3891<o:p></o:p>
eagle:netbios-ssn<o:p></o:p>
eagle:1277<o:p></o:p>
eagle:1296<o:p></o:p>
eagle:1359<o:p></o:p>
eagle:netbios-ssn<o:p></o:p>
eagle:microsoft-ds<o:p></o:p>
eagle:isakmp<o:p></o:p>
eagle:netbios-ns<o:p></o:p>
eagle:netbios-dgm<o:p></o:p>
eagle:1900<o:p></o:p>
eagle:ntp<o:p></o:p>
eagle:netbios-ns<o:p></o:p>
eagle:netbios-dgm<o:p></o:p>
|
分享到:
相关推荐
### 如何避免脆弱的代码 #### 一、引言 在软件开发领域,代码的脆弱性一直是困扰开发者和团队的一大难题。脆弱的代码不仅难以维护,而且修改时极易引发新的问题,导致项目延期甚至失败。ThoughtWorks公司在过去十...
贫困脆弱性分为三种主要类型:风险暴露脆弱性(VER)、期望效用脆弱性(VEU)和预期贫困脆弱性(VEP)。在实际研究中,由于数据限制,VEP方法更为常用,因为它可以通过未来的期望福利来度量脆弱性。 在STATA中,对贫困...
在“脆弱水印算法,基于matlab的代码实现”这个主题中,我们可以深入探讨以下几个关键知识点: 1. **脆弱水印的概念**:脆弱水印与稳健水印相反,它设计用于敏感数据的完整性验证。它通常包含一个校验码或指纹,当...
代码表征方式是将源代码转换成数值型向量,以便于机器学习算法学习和检测脆弱性。传统的代码表征方式包括抽象语法树、代码度量等信息。 为了提高对未知脆弱性的检测效果,本文提出了一种基于代码属性图和Bi-GRU的...
【基于特征矩阵的软件脆弱性代码克隆检测方法】 软件脆弱性是指软件中存在的弱点,可能导致安全漏洞或系统崩溃。为了增强软件的安全性,检测并修复这些脆弱性至关重要。本文介绍的是一种利用特征矩阵来检测软件代码...
).docx" 这个文件提供了关于如何计算贫困脆弱性的详细步骤和所使用的统计软件Stata的源代码。Stata是一款广泛应用于社会科学领域的统计分析软件,其强大的数据处理和建模功能使其成为计算贫困脆弱性指数的理想工具...
脆弱水印检测是一种数字图像处理技术,主要用于保护图像的版权和原始信息。在这个领域,"脆弱水印"一词指的是那些容易受图像处理操作影响的、微妙的标识或信息,通常嵌入在图像中,一旦图像被篡改,水印会相应地发生...
贫困脆弱性计算方式STATA代码 包含计算参考公式和文献以及STATA代码等 我 采用的是VEP方法。 贫困脆弱性计算方式STATA代码 包含计算参考公式和文献以 及STATA代码等 我采用的是VEP方法。
脆弱目标检测是网络安全领域中的一个重要话题,主要涉及的是识别网络环境中可能存在安全漏洞或者易受攻击的系统、服务或应用程序。这种检测工具可以帮助管理员发现并修复潜在的安全风险,防止恶意攻击者利用这些脆弱...
"彩色图像的可逆鲁棒脆弱多水印方案matlab代码.zip"是一个包含Matlab代码的压缩包,专门用于实现一种适用于彩色图像的可逆、鲁棒且脆弱的多水印方案。以下是对这个主题的详细解释: 1. **可逆水印**:可逆水印技术...
郁金香代码注入器是一种可能涉及黑客攻击技术的工具,主要原理是利用程序漏洞或不安全的设计,将自定义的代码植入到正在运行的进程之中。在IT安全领域,代码注入是一种常见的攻击手段,通常被用于执行恶意操作,如...
《信息安全风险评估——脆弱性识别:服务器脆弱性表格详解》 信息安全风险评估是保障组织信息资产安全的重要环节,其中脆弱性识别是评估的核心部分。针对服务器的脆弱性识别,我们通常依据国家标准GB/T21028-2007...
OpenVAS(Open Vulnerability Assessment Scanner)是一个强大的网络安全性评估系统,专用于发现远程系统和应用程序中的潜在漏洞。作为Nessus的开源分支,OpenVAS继承了Nessus的强大功能,并在此基础上进行了开源...
Java程序脆弱性静态分析技术
### 用于内容认证的半脆弱音频水印算法 #### 概述 数字水印技术作为一种新兴的信息保护手段,在网络环境中对于保护版权、认证来源及确保数据完整性方面具有重要作用。随着互联网的发展,数字水印的应用范围不断...
项目中提供的“报告”可能是对整个实施过程的详细记录,包括理论背景、算法描述、代码实现以及实验结果分析。在实际应用中,除了基本的嵌入和提取,可能还需要考虑水印的鲁棒性,以抵抗常见的图像处理操作,如缩放、...