软件代码

2024-07-29

软件代码(共10篇)

软件代码 篇1

0 引言

软件漏洞是信息安全风险的主要根源之一, 是网络攻防对抗中的重要目标, 无论从国家层面的网络安全战略, 还是社会层面的信息安全防护, 安全漏洞已经成为信息对抗双方博弈的核心问题之一[1,2]。2014年, 国家信息安全漏洞库收集并公布漏洞6824 个, 高危漏洞2440 个, 比例逐步上升, 相关报告显示境外有近7.3 万个IP地址作为木马或僵尸网络控制服务器参与攻击我国境内主机, 境内被控制主机数量高达1419万台, 增幅近60%。信息安全形势不容乐观。

同时, 针对源代码漏洞的取证成为构建安全体系的重要战略之一, 国内信息安全体系的建立和实施需要安全平台的技术支持与安全管理的体系支撑, 为了保障信息基础平台, 有必要进行源代码漏洞取证的深入研究, 来确保应用程序或者Web程序在信息平台上的安全性, 而另一方面, 对于源代码的漏洞取证研究已然不仅仅局限在PC端和Web层面上, 随着移动互联网大力发展的趋势, 国家对于Android, IOS等移动平台上的源代码漏洞取证也同样重视。因此, 从某种程度上来说, 源代码漏洞取证的研究工作对于信息基础平台的安全性保障十分重要。

1 软件漏洞

程序或硬件逻辑中设计和实现上的缺陷、人为设计和实现的隐蔽功能以及因使用管理不当造成的安全隐患统称为漏洞[3], 其主要特征是被人利用后会造成控制权的部分或全部转移, 往往使系统遭到非法操控或破坏, 丧失合法控制权。

软件漏洞是当今信息系统绝大多数安全漏洞的来源[4]。软件漏洞是软件中存在的一些缺陷, 这些缺陷可以被第三方或程序利用来进行未经授权的资源访问, 或改变控制权限来执行其他操作。软件漏洞轻则造成相应的经济或财产损失 (如敏感信息被盗, 不可用的服务) , 重则导致严重的灾难, 尤其是发生在被人类生活和生计所依赖的关键基础设施的软件系统上 (如核, 生物, 化学实验室, 电网, 水处理和分配系统, 空中交通控制和交通信号系统) 。

目前代码安全审查和白盒安全测试被广泛用于分析源代码并检测安全漏洞。可这些代码安全审查解决方案有很多不足 (例如精度问题, 产生大量的误报和漏报;可扩展性问题, 为复杂的应用程序支持不足, 无法处理的大型应用程序;适用性问题, 需要大量的额外的人工操作的工作量等) , 导致它们无法广泛的为程序员或测试人员应用。

自动代码安全审查技术利用分析工具来执行所有的代码检查, 这就避免了安全审查人员手动代码审查的过程, 也节省了很多高度密集的工作量[5]。但在自动代码安全审查实践中, 会存在精度和可扩展性之间的权衡。目前有两种不同的解决方案:

(1) 牺牲精确度, 一些自动化代码审计工具利用字符串匹配或其它简单的方法来快速检查代码, 但它会产生大量的误报和漏报。这些解决方案都是基于词法检查, 只将检测危险库函数和系统调用的源代码中进行对比而没有进一步的分析, 也就是RATS和ITS4 语义分析。这是最简单的方法, 但会产生大量的误报。例如, 一个局部变量的名称包含strcat都可以导致错误的报警。

(2) 其他一些基于模型检测的自动化代码审计工具, 把更多的注意力放在了精密性而不是可扩展性。它们的程序经常要进行大量繁重的计算和分析, 这就导致在处理大型应用程序时容易产生故障。

惰性抽象化技术展示了其不断建立和改善需求的单一的抽象模型, 它通过模型检查器驱动, 因此模型的不同部分可能会出现验证了终止性的不同精确度的检测方法。其他一些技术, 如MOPS也存在不同的模型检测的解决方案, 但模型检测的局限是, 在进行核查过程中有很多的注释和谓词会被插入到程序中, 整个过程都需要程序员的参与。同时, 由于程序分析要消耗大量资源, 处理大型应用程序的能力十分欠缺。

2 代码漏洞分类

2.1 通用弱点枚举CWE

通用弱点枚举 ( CWE , Common Weakness Enumeration) 是由美国国家安全局首先倡议的战略行动, 该行动的组织发布了《CWE/SANS最危险的程序设计错误》, 其中列举了最严重的25 种代码错误, 同时也是软件最容易受到攻击的点。这个列表是SANS学院、MITRE以及“美国和欧洲很多顶级软件安全专家”共同合作的成果。在CWE站点上列有800 多个编程、设计和架构上的错误, CWE文档首先列举的是针对程序员最重要的25 项, 从而帮助他们编写更安全的代码。同时文档还适用于软件设计师、架构师、甚至CIO, 他们应该了解这些可能出现的弱点, 并采取恰当的措施。CWE是继CVE (Common Vulnerabilities and Exposures) 之后的又一个安全漏洞词典。通过这一词典, Mitre希望提供识别、减轻、阻止软件缺陷的通用标准。CWE也可以作为人们购买软件的安全衡量标准, 尤其是在购买旨在阻止或发现具体安全问题的安全工具时。

● 跨站脚本攻击

跨站脚本攻击 (Cross Site Scripting) , 为不和层叠样式表 (Cascading Style Sheets, CSS) 的缩写混淆, 故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意html代码, 当用户浏览该页之时, 嵌入其中Web里面的html代码会被执行, 从而达到恶意攻击用户的特殊目的。

● SQL注入攻击

SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序, 而这些输入大都是SQL语法里的一些组合, 通过执行SQL语句进而执行攻击者所要的操作, 其主要原因是程序没有细致地过滤用户输入的数据, 致使非法数据侵入系统。

当应用程序使用输入内容来构造动态sql语句以访问数据库时, 会发生sql注入攻击。如果代码使用存储过程, 而这些存储过程作为包含未筛选的用户输入的字符串来传递, 也会发生sql注入。sql注入可能导致攻击者使用应用程序登陆在数据库中执行命令。相关的SQL注入可以通过测试工具pangolin进行。如果应用程序使用特权过高的帐户连接到数据库, 这种问题会变得很严重。在某些表单中, 用户输入的内容直接用来构造动态sql命令, 或者作为存储过程的输入参数, 这些表单特别容易受到sql注入的攻击。而许多网站程序在编写时, 没有对用户输入的合法性进行判断或者程序中本身的变量处理不当, 使应用程序存在安全隐患。这样, 用户就可以提交一段数据库查询的代码, 根据程序返回的结果, 获得一些敏感的信息或者控制整个服务器, 于是sql注入就发生了。

● 缓冲区溢出

缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量, 使得溢出的数据覆盖在合法数据上, 理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符, 但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配, 这就为缓冲区溢出埋下隐患。操作系统所使用的缓冲区又被称为“堆栈”。在各个操作进程之间, 指令会被临时储存在"堆栈"当中, "堆栈"也会出现缓冲区溢出。

通过向程序的缓冲区写超出其长度的内容, 造成缓冲区的溢出, 从而破坏程序的堆栈, 造成程序崩溃或使程序转而执行其它指令, 以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。

● 跨站点伪造请求

CSRF (Cross-site request forgery跨站请求伪造, 也被称为“one click attack”或者session riding, 通常缩写为CSRF或者XSRF, 是一种对网站的恶意利用。尽管听起来像跨站脚本 (XSS) , 但它与XSS非常不同, 并且攻击方式几乎相左。XSS利用站点内的信任用户, 而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比, CSRF攻击往往不大流行 (因此对其进行防范的资源也相当稀少) 和难以防范, 所以被认为比XSS更具危险性。

● 不当的访问控制授权

假设一个给定的身份的用户, 授权的过程是决定用户是否可以访问给定的资源, 根据用户的权利以及任意的许可或者可以应用在资源上的特殊访问控制权限。

当访问控制的检查不一致或完全不做检查时, 所有的用户都可以访问数据或执行数据, 这是他们不应该被允许执行的操作。这可能会导致广泛的问题, 包括信息的泄露, 拒绝服务攻击, 以及任意代码的执行。

● 在安全决策中信赖不被信任的输入

开发者可以假设诸如cookies, 环境变量, 表单隐藏域等这些输入不能被更改, 然而, 攻击者可以利用自定义的客户端或者其他的攻击来改变这些输入。这些改变可能不会被检测到。当诸如验证和授权等安全决策建立在这些输入的基础之上时, 攻击者可以绕过软件安全实施攻击。

● 不当地将路径名限制为受限的目录 (路径穿透)

许多文件的操作是试图是在一个受限制的目录中发生。通过使用特殊的元素, 如“..”和“/”分隔符, 攻击者可以跳出限制访问系统其他地方的文件或目录。最常见的一种特殊的符号是“../”, 这在大多数现代操作系统被解释为当前位置的父目录, 这属于相对路径遍历。遍历路径还包括使用绝对路径名如“/usr/local/bin”, 这也可能是有用的文件意外访问, 这属于绝对路径遍历。

在许多程序设计语言中, 一个空字节注射 (0 或NULL字符) 可以让攻击者截断生成的文件名来扩大攻击范围。例如, 该软件可以添加”.txt”到任何路径, 从而限制了攻击者的文本文件, 但空字符注射可有效去除这个限制。

● 对危险类型文件的上载不加限制

对文件的上传不做检查, 不加以限制, 攻击者可以利用这一漏洞上传含有恶意代码的文件, 从而执行恶意命令, 对服务器产生破坏, 甚至获取到操作权限, 重要的数据, 必须对上传的文件类型加以限制以防止此类攻击产生。

● OS命令注入

允许攻击者执行意外的, 直接作用在操作系统上的危险命令。这个缺点可以导致系统环境中, 这个漏洞会导致原本无法直接进入操作系统的攻击者找到一个易被破坏的环境, 比如web应用程序, 如果缺陷发生在一个有特权的程序, 它可以允许攻击者使用通常不能被访问的命令或者攻击者原本没有权利执行的命令。问题是如果过程不遵循最小特权原则, 攻击者控制命令可以运行特殊的系统特权, 增加系统的伤害量。

● 缺少对敏感数据的加密

对诸如登陆密码等敏感数据采用明文的方式存储, 攻击者可能会通过内部攻击获取到这些数据, 采用安全的加密算法加密敏感数据总是正确的, 以防止攻击者通过各种攻击方式获取到关键数据源。

● 使用硬编码的证书

硬编码证书通常会产生一个显著的漏洞, 该漏洞允许攻击者绕过软件管理员配置的认证。该漏洞对系统管理员来说难以检测。即使检测到了也难以修复, 这样一来, 系统管理员不得不被迫停止产品的使用。

● 使用不正确的长度值访问缓冲区

这类漏洞是相当不安全的, 因为使用错误的数据访问缓冲区容易造成严重的后果, 如缓冲区溢出攻击, 对缓冲区的使用一定要谨慎小心, 在编写程序时, 你需要考虑到内存管理以及堆栈的问题, 使用过长的值访问缓冲区, 造成越界的错误可能引发意想不到的后果。

● PHP文件包含漏洞

文件包含漏洞即当程序员在包含文件的过程中引入了外部提交的数据参与包含的过程所产生的漏洞, 这个漏洞是目前Web攻击中最利用率最高的一个漏洞, 攻击者可以轻松获取服务器的访问权限 (即拿到webshell) 。而文件包含通常又有本地文件包含 (Local File Inclusion) 和远程文件包含 (Remote File Inclusion) 之分。allow_url_fopen和allow_url_include是决定包含属于本地文件包含 (LFI) 还是远程文件包含 (RFI) 的条件, 在PHP4 中则只有一个allow_url_fopen选择。其中allow_url_fopen和allow_url_include为0n的情况为远程文件包含漏洞, 相反为本地文件包含漏洞。

● 对数组索引检查不当

对数组的索引检查不当, 访问了超出数组长度的索引, 引发未知的错误, 在编写程序时, 没有对索引变量进行检查, 误以为访问数组没有越界, 在程序运行时产生错误的结果, 抛出意外的异常, 甚至产生破坏。同样攻击者可以利用这点构造缓冲区溢出的攻击。

● 对非正常或异常的条件检测不当

程序员可能会认为某些事件或者条件永远不会出现, 所以不需要担心这类情况发生, 比如内存不足, 由于权限限制缺少对资源的访问, 或者行为不端的客户端或组建等情况。然而, 攻击者可能会试图触发这些不寻常的条件, 从而破坏程序程序员原有的设想并引起异常, 错误的行为或者对程序产生破坏。

● 通过错误消息透露信息

敏感信息可能是对自己有价值的信息 (如密码) , 或者可以利用它发起更致命的攻击。如果攻击失败, 攻击者可以使用服务器提供的的错误信息发起集中攻击。例如, 试图利用一个路径遍历的弱点 (cwe-22) 可能产生应用程序的安装全路径。反过来, 这可以用来选择“..”序列定位到目标文件的适当数量。使用SQL注入攻击 (cwe-89) 可能最初不能成功, 但显示畸形查询的一个错误消息, 并将在查询中使用的查询逻辑甚至密码或其他敏感信息暴露出来。

● 整型溢出和环绕

整型溢出顾名思义, 就是由用户提交的整型数据超出程序内部对整型数的安全要求, 造成违反原来的程序限制, 导致其他类型的溢出。一般来说, 整型溢出并不能直接导致改变程序流程, 它是由整型溢出造成字符串类型的溢出, 从而导致覆盖系统数据结构, 改变程序流程。值得注意的就是程序内部对整型数的安全数据范围要求, 而不是仅仅字符串数据范围的要求, 这是整型溢出的根本原因。

● 对缓冲区大小计算错误

对缓冲区的大小计算错误, 产生潜在的漏洞风险, 开发者在设计程序时没有考虑到要分配缓冲区的合理大小, 分配了一个不恰当或者较小的内存空间, 在面对精心构造的数据时, 可能会产生缓冲区溢出, 淹没原有的数据。攻击者可以利用该漏洞构造缓冲区溢出攻击。

● 缺少对重要功能的授权

对于一些重要的功能, 如管理用户日志, 管理备份数据等系统功能, 没有设置权限检测, 导致一些重要功能被除管理员以及更高级别的用户访问外, 能被攻击者以某些方式访问甚至恶意修改, 恶意删除。对于系统重要功能, 需要授权访问, 保证关键数据不会被泄露和恶意篡改。时刻保持对敏感数据访问源的可信度进行授权检查, 以确保系统重要功能的使用安全。

● 下载代码却不做完整性检查

攻击者可以通过影响主机服务器执行恶意代码, 如DNS欺骗, 或者在传输中修改代码。对于手机应用的代码最为普遍, 尽管在任何管理自己的更新的软件中都可能存在。攻击者可以通过修改下载源的代码, 使得用户下载并执行了被精心修改过的代码, 从而产生严重后果。

● 对重要的资源赋值不当

当资源被授权获得更大的被请求访问范围时, 可能会使得敏感数据暴露, 或者资源被意外的方式所修改, 当该资源和程序的配置以及用户的敏感数据相关联时, 这是非常危险的行为。

● 分配资源却不做限制和调节

在预定的安全策略中, 给相关请求分配资源不做限制和调节, 可能会导致资源抢占, 资源耗尽, 或者死锁的情况产生。攻击者可以通过对某一重要资源的请求使得该资源被过度使用, 从而使得系统瘫痪。而对于内建资源管理的程序, 此类问题可以有效避免。

● 重定向到不受信任站点的URL (开放重定向)

一个http参数可能含有URL值并且可能造成Web程序重定向到这个特殊的URL参数请求。通过修改URL的值到一个恶意站点, 攻击者可以成功的启用挂马窃取用户的机密信息。而因为修改后的服务器名和原战点链接相同, 使得这种钓鱼网站有更高的可信度, 从而产生更大的危害。

● 使用被破解或者有风险的加密算法

使用不标准的加密算法或者有风险的加密算法对数据加密, 攻击者可以通过字典构造或者其他相对的破解算法对加密数据进行破解, 诸如一些被技术所攻破的算法不要使用, 对敏感数据的加密要使用更为安全和复杂的加密算法。

● 竞争条件

在安全关键代码中进行预期同步, 诸如对记录用户是否被授权认证或者修改重要的敏感信息不应爱由外部人员所影响。竞争条件发生在并行环境, 并有效地作为适当的代码序列属性。竞争条件违反这些属性:独一无二的代码序列进行资源共享, 即独占访问, 没有其他的代码序列可以在原始序列完成执行修改的共享资源的特性。竞争条件存在时, 一个“干扰码”仍然可以访问共享资源, 违反垄断。程序员可能会假定某些被干扰码序列影响的代码序列执行太快;当竞争条件不在的时候, 这违反了原子行为。例如, 单一的“X++”的声明可能会出现在原子代码层, 但它实际上是在非原子的指令层, 因为它涉及到一个读取 (原始值X) , 随后计算 (x+1) , 其次是写入 (保存结果到X) 。干扰码序列可以是“可信的”或“不可信的”。一个可信的干扰码序列发生在程序中且它不能被攻击者修改, 它只能间接地被使用。一个不受信任的干扰码序列可以直接编写攻击命令, 产生的通常是脆弱的程序。

2.2开放式Web应用程序安全OWASP

开放式Web应用程序安全项目 (OWASP, Open Web Application Security Project) 是一个非盈利组织, 不附属于任何企业或财团, 因此由OWASP提供和开发的所有设施和文件都不受商业因素的影响。它提供有关计算机和互联网应用程序的公正、实际、有成本效益的信息。其目的是协助个人、企业和机构来发现和使用可信赖软件。OWASP支持商业安全技术的合理使用, 它有一个论坛, 在论坛里信息技术专业人员可以发表和传授专业知识和技能。

OWASP目前全球有130 个分会近万名会员, 其主要目标是研议协助解决Web软体安全之标准、工具与技术文件, 长期致力于协助政府或企业了解并改善网页应用程式与网页服务的安全性。由于应用范围日广, 网页应用安全已经逐渐的受到重视, 并渐渐成为在安全领域的一个热门话题, 在此同时, 黑客们也悄悄的将焦点转移到网页应用程式开发时所会产生的弱点来进行攻击与破坏。

2013 年版的OWASP Top 10 文档所基于的8 个数据组由7 家专业的应用安全公司提供, 其中包括:4家咨询公司, 3 家产品OR Saa S提供商 (其中, 1 家提供静态工具, 1 家提供动态工具, 1 家两者都提供) 。数据涵盖了来自上百家组织上千个应用, 超过500, 000 个漏洞。Top 10 根据所有这些相关数据挑选和排序, 并与可利用性、可检测性和影响程度的一致评估相结合。OWASP Top10 的首要目的是培训开发人员、设计人员、架构师、经理和企业组织, 让他们认识到最严重的web应用程序安全漏洞所产生的后果。Top 10 提供了防止这些高风险问题的基本方法, 并提供了获得这些方法的来源。

● 注入

注入攻击漏洞, 例如SQL, OS以及LDAP注入。这些攻击发生在当不可信的数据作为命令或者查询语句的一部分, 被发送给解释器的时候。攻击者发送的恶意数据可以欺骗解释器, 以执行计划外的命令或者在未被恰当授权时访问数据。

任何能够向系统发送不信任数据的人都是潜在的攻击者, 包括外部用户, 内部用户和管理员。攻击者利用有针对性的解释器语法发送简单的、基于文本的攻击。几乎任何数据源都能成为注入载体, 包括内部来源。注入漏洞发生在应用程序将不可信的数据发送到解释器时。注入漏洞十分普遍, 尤其是在遗留代码中。通常能在SQL查询语句、LDAP查询语句、Xpath查询语句、OS命令、XML解析器、SMTP头、程序参数等中找到。注入漏洞很容易通过审查代码发现, 但是却不容易在测试中发现。扫描器和模糊测试工具可以帮助攻击者找到这些漏洞。注入能导致数据丢失或数据破坏、缺乏可审计性或是拒绝服务。注入漏洞有时甚至能导致完全主机接管。所有的数据都有可能被偷窃, 篡改和删除。

● 失效的身份认证和会话管理

与身份认证和会话管理相关的应用程序功能往往得不到正确的实现, 这就导致了攻击者破坏密码、密匙、会话令牌或攻击其他的漏洞去冒充其他用户的身份。

任何匿名的外部攻击者和拥有账号的用户都可能试图盗取其他用户账号。同样也会有内部人员为了掩饰他们的行为而这么做。攻击者使用认证或会话管理功能中的泄露或漏洞 (比如暴露的帐户、密码、或会话ID) 来假冒用户。开发者通常会建立自定义的认证和会话管理方案。但要正确实现这些方案却很难, 结果这些自定义的方案往往在如下方面存在漏洞:退出、密码管理、超时、记住我、秘密问题、帐户更新等等。因为每一个实现都不同, 要找出这些漏洞有时会很困难。这些漏洞可能导致部分甚至全部帐户遭受攻击。一旦成功, 攻击者能执行受害用户的任何操作。因此特权帐户是常见的攻击对象。需要考虑受影响的数据及应用程序功能的商业价值。还应该考虑漏洞公开后对业务的不利影响。

● 跨站脚本

当应用程序收到含有不可信的数据, 在没有进行适当的验证和转义的情况下, 就将它发送给一个网页浏览器, 这就会产生跨站脚本攻击 (简称XSS) 。XSS允许攻击者在受害者的浏览器上执行脚本, 从而劫持用户会话、危害网站、或者将用户转向至恶意网站。

任何能够发送不可信数据到系统的人, 包括外部用户、内部用户和管理员。攻击者利用浏览器中的解释器发送基于文本的攻击脚本。几乎所有数据源都能成为攻击媒介, 包括内部数据源比如数据库中的数据。XSS是最普遍的web应用安全漏洞。当应用程序发送给浏览器的页面中包含用户提供的数据, 而这些数据没有经过适当的验证或转义 (escape) , 就会导致跨站脚本漏洞。有三种已知的跨站漏洞类型:1) 存储式;2) 反射式;3) 基于DOM的XSS。大部分跨站脚本漏洞通过测试或代码分析很容易找到。攻击者能在受害者的浏览器中执行脚本以劫持用户会话、破坏网站、插入恶意内容、重定向用户、使用恶意软件劫持用户浏览器等等。考虑受影响的系统及该系统处理的所有数据的商业价值。还应该考虑漏洞公开后对业务的不利影响。

● 不安全的直接对象引用

当开发人员暴露一个对内部实现对象的引用时, 例如, 一个文件、目录或者数据库密匙, 就会产生一个不安全的直接对象引用。在没有访问控制检测或其他保护时, 攻击者会操控这些引用去访问未授权数据。

考虑系统的用户类型。对于某些系统数据类型, 是否有的用户只具有部分访问权限。作为授权的系统用户, 攻击者只需要修改指向一个系统对象的直接引用参数值, 让其指向另一个无权访问的对象, 系统是否会允许这样的访问。当生成web页面时, 应用程序经常使用对象的实名或关键字。而应用程序并不会每次都验证用户是否有权访问该目标对象, 这就导致了不安全的直接对象引用漏洞。测试者能轻易操作参数值以检测该漏洞。代码分析能很快显示应用程序是否进行了适当的权限验证。这种漏洞能破坏通过该参数引用的所有数据。除非对象引用是不可预知的, 否则攻击者很容易访问该类型的所有数据。考虑暴露的数据的商业价值。还应该考虑漏洞公开后对业务的不利影响。

● 安全配置错误

好的安全需要对应用程序、框架、应用程序服务器、web服务器、数据库服务器和平台定义和执行安全配置。由于许多设置的默认值并不是安全的, 因此, 必须定义、实施和维护这些设置。这包含了对所有的软件保持及时地更新, 包括所有应用程序的库文件。

考虑外部的匿名攻击者和拥有自己帐户的内部用户都可能会试图破坏系统的。另外考虑想要掩饰他们的攻击行为的内部攻击者。攻击者访问默认帐户、未使用的网页、未安装补丁的漏洞、未被保护的文件和目录等, 以获得对系统未授权的访问或了解。安全配置错误可以发生在一个应用程序堆栈的任何层面, 包括平台、Web服务器、应用服务器、数据库、框架和自定义代码。开发人员和系统管理员需共同努力, 以确保整个堆栈的正确配置。自动扫描器可用于检测未安装的补丁、错误的配置、默认帐户的使用、不必要的服务等。这些漏洞使攻击者能经常访问一些未授权的系统数据或功能。有时, 这些漏洞导致系统的完全攻破。系统可能在你未知的情况下被完全攻破。你的数据可能会随着时间推移被全部盗走或者篡改。恢复的花费可能会很昂贵。

● 敏感信息泄露

许多Web应用程序没有正确保护敏感数据, 如信用卡, 税务ID和身份验证凭据。攻击者可能会窃取或篡改这些弱保护的数据以进行信用卡诈骗、身份窃取, 或其他犯罪。敏感数据值需额外的保护, 比如在存放或在传输过程中的加密, 以及在与浏览器交换时进行特殊的预防措施。

考虑谁可以访问您的敏感数据和这些数据的备份。这包括静态数据、传输中的数据甚至是客户浏览器中的数据。攻击者通常不直接攻击加密系统。他们往往通过诸如窃取密钥、发起中间人攻击或从服务器窃取明文数据等方式对传输中的或者客户浏览器中的数据进行破解。在这个领域最常见的漏洞是应该加密的数据不进行加密。在使用加密的情况下, 常见的问题是不安全的密钥生成和管理和使用弱算法是很普遍的, 特别是使用弱的哈希算法来保护密码。浏览器的漏洞也很普遍, 且可以很轻易的检测到, 但是很难大规模的利用。外部攻击者因访问的局限性很难探测这种漏洞, 并且难以利用。这个领域的错误频繁影响那些本应该加密的数据。这些信息通常包括很多敏感数据, 比如医疗记录, 认证凭证, 个人隐私数据, 信用卡信息, 等等。考虑丢失数据和声誉影响造成的商业损失。如果这些数据被泄露, 那你要承担的法律责任是什么, 另外考虑到对企业造成的声誉影响。

● 功能级访问控制缺失

大多数Web应用程序在功能在UI中可见以前, 验证功能级别的访问权限。但是, 应用程序需要在每个功能被访问时在服务器端执行相同的访问控制检查。如果请求没有被验证, 攻击者能够伪造请求以在未经适当授权时访问功能。

任何人具有网络访问权限的人都可以向你的应用程序发送一个请求。匿名用户可以访问私人网页吗, 又或者普通用户可以访问享有特权的网页吗。攻击者是被授权的系统用户, 很容易就把网址更改成享有特权的网页, 这样的访问会被允许吗。匿名用户可以访问未受保护的私人网页。应用程序并不总是能正确地保护页面请求。有时功能级的防护是通过配置来管理的, 而系统的配置是错误的。开发人员必须要做相应的代码检查, 然而, 有时他们忘记了。检测这些漏洞是很容易的。最难的是确定应用程序存在哪些可被攻击的网页或者链接 (URL) 。这种漏洞允许攻击者访问未经授权的功能。管理性的功能是这类攻击的主要目标。考虑被暴露的功能及其处理的数据的商业价值。另外考虑如果这样的弱点被公布于众而对你造成的名誉影响。

● 跨站请求伪造

一个跨站请求伪造攻击迫使登录用户的浏览器将伪造的HTTP请求, 包括该用户的会话cookie和其他认证信息, 发送到一个存在漏洞的web应用程序。这就允许了攻击者迫使用户浏览器向存在漏洞的应用程序发送请求, 而这些请求会被应用程序认为是用户的合法请求。

考虑可能将内容载入你用户的浏览器并迫使他们向你的网站提交请求的任何人。你的用户所访问的任何网站或者HTML源 (feed) 都可以这样做。攻击者创建伪造HTTP请求并通过图片标签、跨站脚本或许多其他技术诱使受害用户提交这些请求。如果该受害用户已经经过身份认证, 那么攻击就能成功。CSRF是利用某些web应用程序允许攻击者预测一个特定操作的所有细节这一特点。由于浏览器自动发送会话cookie等认证凭证, 攻击者能创建恶意web页面产生伪造请求。这些伪造请求很难与合法请求区分开。跨站请求伪造漏洞可以很容易通过渗透测试或代码分析检测到。攻击者能欺骗受害用户完成该受害者所允许的任意状态改变的操作, 比如:更新帐号细节, 完成购物, 注销甚至登录等操作。考虑受影响的数据和应用功能的商业价值。试想如果并不知道这些操作是否是用户的真正意愿会产生什么后果, 同时考虑带来的声誉影响。

● 使用含有已知漏洞的组件

组件, 比如:库文件、框架和其它软件模块, 几乎总是以全部的权限运行。如果一个带有漏洞的组件被利用, 这种攻击可以造成更为严重的数据丢失或服务器接管。应用程序使用带有已知漏洞的组件会破坏应用程序防御系统, 并使一系列可能的攻击和影响成为可能。

一些含有漏洞的组件 (如:框架库) 可以被自动化工具发现和利用。这使得威胁代理部分引入了“混乱”的角色, 而不仅仅是攻击者了。攻击者通过扫描或手动分析识别问题组件, 然后根据需要定制攻击代码并实施攻击。在应用中使用组件越深入, 实施攻击的难度越大。事实上, 大多数的应用都存在这些问题。因为大多数的开发团队并不会把及时更新组件/库作为他们的工作重心。在很多情况下, 开发者都不了解他们所使用的全部组件, 更不用说组件的版本了。组件的依赖性使情况更加糟糕。可能是由低到高全系列的漏洞, 包括注入, 破损的访问控制, XSS等。受影响范围也从最低的受损到主机被完全接管和数据的泄漏。考虑一下受影响的应用中, 每个脆弱点对业务控制来说意味着什么。可能是非常细微的影响, 也有可能意味着被完全攻破。

● 未验证的重定向和转发

Web应用程序经常将用户重定向和转发到其他网页和网站, 并且利用不可信的数据去判定目的页面。如果没有得到适当验证, 攻击者可以重定向受害用户到钓鱼软件或恶意网站, 或者使用转发去访问未授权的页面。

考虑所有能诱使用户向网站递交请求的人。用户使用的任何网站或其他HTML源 (feed) 都可以这样做。攻击者链接到未验证的重定向并诱使受害者去点击。由于是链接到有效的网站, 受害者很有可能去点击。攻击者利用不安全的转发绕过安全检测。应用程序经常将用户重定向到其他网页, 或以类似的方式进行内部转发。有时, 目标网页是通过一个未经验证的参数来指定的, 这就允许攻击者选择目标页面。检测未经验证的重定向很容易, 只需寻找那些允许你指定整个URL的重定向。但检测未经验证的转发困难些, 因为它们的目标是内部网页。这种重定向可能试图安装恶意软件或者诱使受害者泄露密码或其他敏感信息。不安全的转发可能允许绕过访问控制。

3 软件代码安全漏洞取证方法

近年来, 国外的研究热点集中在对漏洞取证的建模、针对已知漏洞的安全编程技术、针对安全漏洞的路径敏感分析、应用数据流分析到漏洞检测的研究中和漏洞特征的快速匹配等。除了科研机构, 国外的黑客在这方面也做了大量的工作。国外顶级的黑客会议, 如Black Hat大会、Defcon大会, 在会上有很多与安全相关的议题, 都是当前安全研究的热点。著名的Phrack黑客杂志也是专注于安全技术的有名刊物。Bugtraq邮件组和CVE都致力于收集软件的脆弱点。Security Focus的Bugtraq邮件组是很多安全研究人员首选的讨论区, CVE则是专家们所选择的分类方式讨论区。

相对来说国内起步较晚, 但同样取得不错的成绩。在国内, 网络安全焦点 (xfocus) 、绿盟科技、启明星辰和CCERT (中国教育和科研计算机网紧急响应组) 等是国内安全研究机构的代表, 并且维护了自己的漏洞数据库。xcon大会被誉为国内最顶级的探讨安全问题的大会。在2013 年的xcon大会上就有关于软件安全漏洞的议题, 比如夏超的二进制环境下的缓冲区溢出漏洞动态取证技术。2015 年的xcon会议上也出现了关于软件安全的探讨。

目前软件安全漏洞的检测技术包括静态分析检测技术和动态检测技术。静态检测技术是利用二进制比对技术、词法分析、形式化验证技术或者手工测试技术, 对被测程序的源程序或二进制代码进行扫描, 然后从语法、语义上理解程序的行为, 并分析程序的特征, 找出可能导致程序异常的漏洞。这类技术具有简单高效自动化的优势, 但只是对代码本身的特征进行检查, 不能很好检测出漏洞间复杂的逻辑关联, 并且存在大量的误报和漏报;动态检测技术是通过自动化生成测试数据, 以仿真攻击应用程序来判断是否存在漏洞, 主要手段是利用各种输入对程序进行探测, 并分析程序运行环境等。这类技术效率不如静态分析检测技术, 但它能准确的定位漏洞。本文详细综述了常见的源代码安全漏洞取证方法。

3.1 非执行栈技术

基于栈进行攻击的事件最近几年经常发生, 原因就是很多操作系统的栈是可以写与执行的, 而且内部变量尤其是数组变量都保存在栈中, 攻击者向栈中注入恶意代码, 然后想方设法来执行这段代码。栈攻击技术的文档也比较全面, 这从某种程度上加速了基于栈的攻击。一个最直接的防范栈攻击的方法就是使得栈不能执行代码。这样即使攻击者在栈中写入了恶意代码, 这个恶意代码也不会被执行, 在一定程度上防住了一些攻击者。只是这个方法需要在操作系统层进行修改, 同时, 不可执行栈的技术涉及到的一个大问题就是性能问题。此外, 在既有栈溢出漏洞又有堆溢出漏洞的程序中, 易出问题。可以利用栈溢出使程序跳转至攻击代码, 该代码是被放置在堆上。没有实际执行栈中的代码, 而是执行了堆中的代码。该技术所付出的代价就是对操作系统内核引入一个微小的改变:把栈页标记为不可执行。

该技术的检测不够全面, 它仅能检测并阻止摧毁栈攻击。一个攻击者可以通过把恶意代码注入到数据段来绕过该技术的检测, 他只需要把栈中返回地址覆盖掉, 使得这个返回地址指向数据段中的恶意代码就可以了。该技术可能会造成小量的兼容性问题, 因为有个别的应用程序就是依靠栈执行来正确运行的。该技术对性能的消耗可以被忽略, 有报告称这项技术仅仅在上下文切换时增加了2到3个CPU的指令周期。

3.2非执行堆与数据技术

由于堆是程序运行时动态分配内存的区域, 而数据段则是程序编译时就初始化好了的。很长时期以来, 由于担心非执行的堆与数据段会破坏软件的正常运行, 所以该方法进展缓慢, 最近几年才有些进展和文章。如果堆和数据段都不能执行代码, 攻击者注入其中的恶意代码将不能被执行。这项技术和前面的非执行栈技术结合能起到更全面的作用, 使得恶意代码彻底失去执行机会。使用该技术所付出的代价要比非执行栈技术大一些, 因为它对内核的修改要多一些。现在已经有了大量的实例可以使用, 这个技术还是可以接受的。

从全面性上来看, 该技术对于几乎所有的利用把恶意代码注入进程内存中的攻击都可以检测并阻止。但是, 对于恶意修改函数指针和函数参数的攻击没有办法检测和防范。该技术改变了传统程序在堆或数据段中动态生成代码的方式, 会造成很多应用程序的不兼容性。另外, 使用这个技术来检测并排除漏洞对很多的应用不会产生太大影响, 性能上的消耗也可以忽略。

3.3 内存映射技术

有些攻击者通过使用NULL结尾的字符串来覆盖内存, 以达到攻击的目的。通过使用映射代码页方法, 将使得攻击者很难通过NULL结尾的字符串来跳转到较低的内存区, 而且这些代码本身又可能含有NULL字符。再者, 把代码页随机地映射到不同的内存地址, 在某种程度上防止了那些靠猜地址来进行攻击的攻击方法。比如对于缓冲区溢出的漏洞, 攻击者就是要寻找目标进程在内存中的某些地址, 然后构造自己的数据来覆盖这些地址。这些地址在很多操作系统上都是有规律可以计算出的。如果使用内存映射技术, 把代码页映射到随机的地址, 将给攻击者增加很大的困难, 不做大量的尝试是不可能查出所需地址的。使用内存映射技术所付出的最大的代价就是要修改操作系统内核、使得操作系统可以把代码页映射到较低的内存空间。虽然这个技术不需要对代码进行修改, 但要重新链接, 因为二进制的地址在程序链接阶段就确定了。

内存映射技术可以检测并阻止基于内存中地址跳转的攻击。但它对于注入新代码并执行新代码的攻击不能检测和预防。除此之外, 因为低端内存是有大小限制的, 想把所有的代码页都映射到低端内存在有些应用中是不可行的。内存映射技术仅仅对那些依靠固定地址或使用高端地址的应用程序有影响。而这样的应用程序并不多。内存映射技术对性能的消耗也可以忽略, 它仅仅是在程序装载的过程中工作, 运行起来之后对程序没有任何影响。

3.4 安全共享库技术

很多软件的安全漏洞来源于使用了不安全的共享库, 尤其是C&C++, 当中有很多的函数都不够“安全”, 比如:strcpy、strcat、gets等等。这些函数使用不好就会带来灾难性的后果。用安全共享库技术, 能在一定程度上阻止攻击者的攻击。安全共享库技术就是依靠动态链接技术, 能在程序运行期间拦截对不安全的函数的调用, 并对函数参数等进行检测, 这在Windows和UNIX上都被广泛应用。特别的是, 这个技术能对当前内存大小的上限给出一个评估值, 这在一定程度上阻止了把数据写到评估边界的外面。安全共享库技术从技术的角度很容易开发和配置, 而且不需要对已有的应用程序作任何的修改和再编译。从理论上讲, 安全共享库技术可以检测并防止所有的基于标准库函数的攻击。但是它不能保护本地变量的安全, 而且它也不能防止数据段和代码段数据的溢出攻击。安全共享库技术对于非标准的库函数无能为力。安全共享库技术不会造成任何兼容性问题, 在标准库下运行正常的程序在安全共享库技术下面也同样运行良好。安全共享库技术对于那些和安全没有关系的标准库中函数不做任何处理。性能瓶颈主要在这些有安全弱点的函数上。这样可以大幅度提高程序的性能。如果所有的库中的函数都被拦截并检查, 性能上的消耗将提高15%。现在安全共享库的研究项目中的某些特性已经整合到某些标准库中了, 如glibc。使用glibc库的应用程序能提供隐式的安全性。

3.5 沙箱技术

通过限制一个进程所访问的资源来预防某些攻击行为[7]。例如:在C语言中有execv、system等系统调用函数, 一个软件可能根本不会存在这些系统调用, 如果发现某一大该运行软件有了这些系统调用, 可能就是被攻击了。在攻击之前如果能使用沙箱技术限制住对这些资源的访问, 则攻击就不会得逞。沙箱技术不需要对操作系统内核和应用程序作任何改变。然而, 要给每一个需要安全检测的应用程序定义一个资源访问策略。对于一个复杂的应用程序而言, 定义这样的一个策略将是很麻烦的工作。

沙箱技术检测的全面性主要看定义的策略的全面性。一个严格定义的策略可以更好的保护程序不受攻击。但该技术对于通过改写关键的木地变量 (例如用户的身份ID等) 而修改程序逻辑流程的攻击束手无策。沙箱技术依赖于安全策略。它不会带来兼容性方面的问题。但是一个过于严格的策略可能会限制应用程序的合法行为, 最终导致程序不能使用。而且对系统调用函数的审查可能会带来竞争条件问题的出现。

沙箱技术的主要性能消耗是在每个系统函数调用的检测开关上和查询策略表上。这个性能消耗在系统函数调用不频繁的应用程序中并不明显。沙箱技术目前主要集中于系统调用方面。在不知道一个应用程序逻辑的情况下限制它的行为是很困难的, 而且可以通过不在策略中的函数而绕过检测。

3.6 程序解释技术

在程序运行之后来监视其行为并且强制进行安全检查是最显而易见的好方法, 这就需要解释程序的执行。但程序解释技术方法, 通常会消耗大量性能。最近也有很多的动态优化技术来弥补这个缺陷。程序监视器是使用这种方法的一个较好的例子。它使得进行额外的安全检测却不牺牲太多的性能成为可能。

程序解释技术不需要对操作系统内核和应用程序代码作任何改变, 应用程序只要重新链接产生一个新的起动代码就可以了, 然后有这个起动代码来调用动态优化的程序解释框架。有了严谨的安全策略, 几乎所有已知的改变程序控制流程或修改危险函数的参数的攻击都可以被检测到并防范住。但是, 通过对关键变量 (如身份ID) 的修改、覆盖来改变程序逻辑流程的攻击没有好的办法防范, 除非对每一个读写指令都进行解释, 而这样又会带来不能接受的性能上的消耗。使用程序解释技术的又一个优点是它能对动态生成的代码执行安全检测, 例如JIT代码。

3.7 二进制文件分析技术

针对非开源的软件程序, 通过自动审核工具对程序的二进制文件进行自动分析。其中应用最广泛的工具便是IDA反汇编工具, 该工具是专用的二进制文件分析工具, 它可以通过目标程序反汇编得到汇编代码, 然后对汇编代码进行扫描, 从而去识别可能存在的安全漏洞缺陷[8]。IDA之所以被广泛应用, 其中一个很重要的因素就是该工具可以识别程序的关键结构, 它可以自动识别高级语言的关键结构, 如new和delete操作符、函数的返回值、局部堆栈变量、文本与字符串、IF-THEN-ELSE条件语句等, 从而进一步对目标程序进行分析。但是IDA反汇编工具采用的反汇编技术需要大量的人工分析, 且具有很强的复杂性, 因此其自动化程度也不会高。

二进制文件分析技术通过分析软件反汇编后的汇编代码, 来发现软件中存在的安全漏洞。汇编代码不利于人的理解, 这是不争的事实, 但是, 针对不公开源代码的软件进行漏洞的分析, 只能以汇编代码为源代码。对汇编代码的理解深度就决定了软件安全漏洞取证工作的深度。静态分析技术的优点是, 由于是从机器的角度去理解安全漏洞的机理, 理解更深刻、更到位, 对细节的把握也更加透彻。缺点在于软件反汇编后的汇编代码量巨大、结构复杂, 即使是一个小型的应用程序产生的汇编代码其复杂性也不可小觑, 对漏洞发生现场不易进行准确的定位。同时, 由于汇编代码与机器码基本一一对应, 晦涩难懂, 对研究人员的技术能力和技术积累要求较高。

4 软件漏洞取证技术对比分析

通过对现有常见的源代码漏洞取证方法的详细描述, 经过深入分析可得到这些方法各自存在的优点和缺点, 本文归纳结果如下表2 所示:

可以看到, 虽然现有的源代码漏洞取证方法有较多的优点, 但是也普遍存在着不能覆盖全部安全漏洞、扩展性较差、效率较低等多种缺点。为了克服这些已有漏洞取证方法存在的缺点, 能够使得源代码漏洞取证更加准确、全面、高效、灵活地进行, 研究基于大数据分析的软件代码漏洞取证技术是必要且迫切的工作。

5 结论

本文综述了软件漏洞的概念和特点, 同时归纳和分析了当前主流的代码漏洞分类标准, 在此基础上叙述了代码漏洞分析方法的技术原理和国内外的研究现状, 并分析了常见的漏洞取证方法的优缺点。

摘要:软件漏洞是当今信息系统最主要的安全漏洞来源。本文综述了软件漏洞的概念和特点, 同时归纳和分析了当前主流的代码漏洞分类标准, 在此基础上叙述了代码漏洞分析方法的技术原理和国内外的研究现状, 并分析了常见的漏洞取证方法的优缺点。

关键词:软件漏洞,电子取证,信息安全

参考文献

[1]夏杰.协同电子取证模型研究与设计[J].西北工业大学学报, 2013, 57 (5) :742-745.

[2]孙国梓, 耿伟明, 陈丹伟, 申涛.基于可信概率的电子数据取证有效性模型[J].计算机学报, 2011, 33 (7) :1262-1274.

[3]王加松.VMware虚拟机技术在电子数据取证中的应用[J].软件, 2013, 34 (12) :200.

[4]金元海, 王西雁.计算机网络信息安全防范方法研究[J].软件, 2014, 35 (1) :89-91.

[5]杨正校, 刘静.工业控制系统信息安全防范研究[J].软件, 2014, 35 (8) :55-58

软件代码 篇2

2. 只要有我,没有问题!

3. Visual Unit,让软件单元测试轻而易举。

4. 化难为易,一安永逸!

5. 可视化测试(Visual Unit),真正的人性(自动)化。

6. 智慧的你,需要智能的她(它)——Visual unit。

7. 一测通,必应器 。

8. 好工具,一测就灵。

9. 测试一下,做的更快做的更好。

10. 破题何须书万卷,工具好用事好办。

11. 真正解决问题,解决真正问题。

12. 十八般武艺,解决测试问题!

13. 真正解决问题——单元测试工具,

14. 软件专家,帮您轻松解决测试问题!

软件代码 篇3

关键词:ASP SQL Server数据库 执行效率 软件因素 对策

ASP是一种动态网页开发技术,网页中ASP代码在服务器端执行后的结果会以HTML格式输出到客户端的浏览器上显示,虽然其执行效率比不上ASP.NET,但因为ASP具有简单、灵活、易学、易用等特点,因此被广泛应用于企业网站、个人网站、电子商务网站、Web应用系统等网站系统开发中。

制约ASP页面代码执行效率的因素有很多,如网络、Web服务器以及数据库服务器等的设置和配置,但这些大都与硬件相关,而一些软件因素,如页面设计、程序设计方法、SQL Server数据访问方法也能影响程序的性能:好的设计、访问方法可以大大提高系统的性能,有时在同等条件下只要稍微改变一下,代码执行效率就能得到显著的提升。

1 影响执行效率的软件因素及对策

ASP页面代码通常由HTML代码和ASP代码组成,影响ASP页面代码执行效率的软件因素主要包括3个方面,即HTML代码的执行效率、ASP代码的执行效率、SQL Server数据库的访问效率。

1.1 HTML代码

HTML代码的优劣也会影响整个ASP页面代码的执行效率。影响HTML代码执行效率的因素不仅包括客户端计算机和它的网络带宽,而且HTML页面上的一些常见因素也会影响其执行效率。

1.1.1 图像、动画和框架因素。在HTML页面中使用图像和动画的原则是:按需使用,能不用的尽量不用。因为,如果页面包含多个图像和动画,那么当浏览器请求页面后,将要多次向Web服务器请求调用图像、动画,这显然会降低页面的加载进程,影响执行效率。使用框架的情况也和图像类似。

1.1.2 表格因素。应尽量避免使用表格布局,而用符合Web标准的主流的DIV+CSS方式布局[1],可极大地提高HTML执行效率。即使要使用表格来呈现数据,也要尽量避免使用多个表格和嵌套表格,过多过复杂的表格会大大降低HTML的执行效率。

1.1.3 多余的标识符。多余的标签会使页面解释时花费较多时间。例如:

项目名称
负责人

很显然,可以对

进行优化,优化后的代码如下:

项目名称负责人

1.1.4 过多的注释。应减少不必要的注释,这将会减少文件的大小,也就相应地提高了页面的加载速度。

1.1.5 尽量避免使用一些不必要的插件(如Java Applets),而用相关技术来代替,因为插件的执行时间较长。比如当我们用Java Applets处理动画时就可用Gif动画或者Flash来代替。

1.2 ASP代码

提高ASP代码的执行效率可从以下几个方面进行:

1.2.1 避免在同一页面中使用多种脚本语言,如vbscript、javascript。因为混用多种脚本语言后会使得Web服务器不得不加载多个脚本引擎逐个解释,这势必会影响脚本执行的效率。

1.2.2 避免包含ADOVBS.inc文件。因为Microsoft提供的ADOVBS.inc包含了270行代码,这些代码定义了大多数的ADO属性常量。应通过其它方法访问和使用ADO常量,比如适度地注释或直接将需要用到的常量从ADOVBS.inc文件中直接拷贝到页面内。

1.2.3 尽量把对象变量转换成本地变量,因为读本地变量比读对象变量要快很多。比如,如果要多次访问myobj.value及rs("author"),不妨先将其赋给一个变量:myvar=myobj.value及吗author=rs("author"),再在程序中使用myvar、author。

1.2.4 当使用VBScript 5.0及以上版本时,尽量使用With... End With语句来简化对同一对象不同属性或方法的多次访问,这也可以提高程序的运行速度。

1.2.5 尽量多使用存储过程,少使用include文件。因为一旦建立了一个存储过程,就可以很方便地在不同的应用中进行调用,甚至是在不同服务器上的应用中进行调用,如果把所有的代码都放在Include文件中,那么要做到这一点是很困难的。

比如,在大多数情况下,我们通常使用ASP来生成选择省份等的列表,即创建生成这个列表的函数并把它们保存在一个Include文件中。然而,ASP需要额外的时间在服务器上加载并处理这些Include文件,此外,每次生成一个选择列表时,服务器都必须加载整个Include文件。但是。如果把函数中的代码放在存储过程中,让存储过程返回一个包含全部选择列表元素的单一变量,然后把这一变量返回给HTML的Select语句,那么这将会提高效率。

1.2.6 多使用已编译的组件。相对解释执行的ASP代码,编译过的组件肯定会更快一些[2]。

1.2.7 减少脚本中服务器端与前端的切换。比如:<%=var1%><%=var2%>,应改为<%=””& var1 & “”&var2 & “”%>,因为ASP遇到一个脚本时必须在服务器端解释再发送到前端,频繁的切换也会使速度大减,特别是在循环语句中尤为明显。

1.3 数据库访问

在ASP中,相当多的应用与SQL Server数据库的访问有关,因此提高访问SQL Server数据库的效率必然会大大提高ASP的执行效率。这可从以下几个方面进行:

1.3.1 在条件允许的情况下,应将数据库服务器和Web服务器分开,这肯定能够提高速度。

1.3.2 设计一个好的数据库结构可以大大提高程序的运行速度,比如在经常用于查询的列上建立(组合)索引等。

1.3.3 访问数据库是最消耗时间的,因此应灵活地运用存储过程,尽量少用多条动态的SQL语句,因为存储过程是预编译的,首次运行时查询优化器会进行分析、优化并会存储在系统表中,而SQL语句每次运行时都要编译和优化。实践证明,数据量越大,两者之间的执行效率差别越大,况且使用存储过程还能减少网络流量[3]。

1.3.4 如果ASP页面中只使用一个记录集,那么可直接把数据库连接串赋给记录集的ActiveConnection属性,而不必先创建一个单独的Connection对象再将它赋给Recordset的ActiveConnection属性。此时,虽然Recordset对象仍旧要创建一个连接,但这时的创建是在高度优化的条件下进行的。

如果同一页面内要用到多个记录集时,可创建单一的连接对象并通过记录集的ActiveConnection属性共享它。

1.3.5 相比从Connection和Command对象创建记录集的方法而言,通过ADODB.Recordset类实例化记录集将会使页面开销有所下降,并且可以获得最好的性能和灵活性。

1.3.6 要更新数据记录,应盡量使用Connection或Command对象执行Update、Insert Into等指令,少用Recordset对象的Update、Addnew等方法。对于单条记录的更新,两者差别不大,但在批量更新数据时将使执行效率提高数倍。

1.3.7 使用适合于处理任务的最简单的游标类型和记录锁定方式。与“只能向前”类型的游标相比,所有其它的游标类型都需要额外的开销,况且,这些游标在循环内一般也要慢一些。因此,永远不要认为“有时候我会用到动态游标,那么我就一直使用这种游标吧”。同样的看法也适用于记录锁定方式的选择。

1.3.8 分页显示时应针对不同的数据量分别采用不同的分页技术。

2 结语

本文讨论了影响ASP页面代码执行效率的软件因素及提高效率的一些对策,需要说明的是,这些对策不一定适合于所有的ASP动态网站或应用系统,对不同的ASP应用要采用不同的对策,以期达到应有的效果。

参考文献:

[1]蔡伯峰.网页设计与制作[M].北京:清华大学出版社,2010.

[2]吴贵山.基于改进ASP设计的提高执行效率探究[J].漳州职业技术学院学报,2010,12(3):8-10.

[3]王启才.使用存储过程提高ASP的数据处理速度[J].电子商务,2010,(2):61-62.

作者简介:

蔡伯峰(1967-),男,江苏泰州人,大学本科学历、硕士学位,现为副教授兼工程师。有企业一线的工作经历,多年来一直在泰州职业技术学院从事计算机专业教学、教学管理及Web应用软件开发工作。研究方向:软件开发。

基于代码混淆的软件保护技术 篇4

随着信息技术的发展, 计算机已成为人们工作、学习和生活中不可缺少的部分, 而计算机软件正是推动这一发展的主要动力。然而, 盗版现象日益严重, 引起了许多企业和学者的关注。要解决盗版问题, 一方面应该依靠法律手段, 另一方面应该研究和讨论如何借助各种技术手段来有效保护软件产品, 这对于防止盗版有着重要的现实意义。代码混淆是重要的软件保护技术之一, 它的出现使得攻击者很难通过软件反汇编得到源码或得到的源码不可理解, 从而, 极大地保护了Java、C#等语言开发的软件。

1、代码混淆的定义与目标

代码混淆是为了转换一个程序P到另一个程序P', 使得P'对逆向工程师来说更为困难, 同时P'与P有相同的可观测行为。如果P不能结束或错误结束, 则P'也不能结束或错误结束, 否则P'必须结束并产生和P相同的输出。代码混淆的目标是改变代码使得它很难被反编译, 但事实证明, 只要有足够的时间和资源, 反编译一个程序总是可能的, 因此, 更多的代码混淆理论关注的是通过代码混淆使得反编译的代价超出攻击者通过反编译所获得的收益。

根据代码混淆的定义, 可以得出混淆的目标:

(1) P'和P在输入和执行环境相同时, 输出也必须相同, 一般来说, 只要语义保持不变, 这个条件自然满足;

(2) P'的可理解性要远低于P, 比如说, 逆向工程P的时间要远大于逆向工程P的时间;

(3) 不存在由P'向P的逆变换, 或者很难构造一个工具自动完成这种逆变换, 或者这种逆变换的代价非常高。

2、代码混淆分类

代码混淆可以划分成版面布局混淆、数据混淆、控制混淆等类型[1][2]。

2.1 版面布局混淆

版面布局混淆, 也称符号混淆, 即改变或者去除代码里的信息, 但不改变代码的可执行部分。包括弄乱代码里的标识符和去除代码里的调试信息和注释。在Class中存在许多与程序执行本身无关的信息, 例如方法名称、变量名称, 这些符号的名称往往带有一定的含义。

例如, 某个方法名为setPassword () , 那么这个方法很可能就是用来设置密钥的。符号混淆就是将这些信息打乱, 把这些信息变成无任何意义的表示, 比如替换该方法名为a () , 如图所示, 增加了攻击者破解的难度。对于私有函数、局部变量, 通常可以改变它们的符号, 而不影响程序的运行。但是对于一些接口名称、公有函数、成员变量, 如果有其它外部模块需要引用这些符号, 则往往需要保留这些名称, 否则外部模块找不到这些名称的方法和变量。因此, 对于符号混淆, 最好提供选项, 让用户选择是否、如何进行符号混淆。

2.2 数据混淆

这类混淆不修改代码, 而是混淆数据和程序里的数据结构。良好的编程风格对变量的命名方式都有一些约定, 因此, 把数据编码为有一定意义的变量, 通过消除变量的含义来达到混淆的目的。常用的混淆算法如下:

(1) 拆分变量

例如, 把二进制变量S拆分为两个二进制变量P和Q, 当P=Q=0时S=0, 当P=Q=1时S=1。

(2) 转换静态数据为过程

例如, 字符串是由多个字符构成, 可以设计一个连接字符串的函数, 通过调用函数生成静态字符串。

(3) 改变编码

例如, 整数j可以替换为j', 如图所示, 这里c和d为常数。

(4) 改变变量生命期

例如, 局部变量可以转换为全局变量。

(5) 提升标量为向量

例如, 把所有的循环计数变量放在一个数组里。

(6) 合并标量变量

例如, 合并两个16位的变量为一个32位的变量。

(7) 修改继承关系

例如, 取两个没有关系的不同的类, 以两个类都有的某些特征创建一个新的父类。

(8) 拆分、折叠、合并数组

例如, 改变数组的维数。

2.3 控制混淆

控制混淆的目标是改变代码的控制流但不改变代码的计算部分。通常代码是以逻辑的方式划分成方法, 并把相关代码放在一起。通过组合拆分不相关方法可以打破这种逻辑, 使得攻击者无法理解代码之间的相互关系, 从而达到保护软件源码的目的。

常见的控制混淆方法有:重新排序语句;重新排序循环;重新排序表达式。

目前, 最主要的控制混淆算法是通过增加更多的计算来修改真实的控制流。经常使用的一种基本构造是opaque谓词[3]。这种谓词的值对混淆者是已知的, 而反混淆者却很难推知。通常的方法有:插入无意义的或不相关的代码;由opaque谓词构造这些代码的分支语句;扩展循环条件;用opaque谓词来扩展循环条件;表解释;构造一个简单的虚拟机, 真实的代码由虚拟机解释;可约流图转换成不可约流图。

3、代码混淆的性能指标

通常从强度 (potency) 、抗攻击能力 (resilience) 、代价 (cost) 等方面来评估某个混淆的效果。

(1) 强度--度量混淆后程序增加的复杂度, 在大多数情况下该测度刻画了一个程序被人理解的困难程度。一般来说, 一个应用程序所包含的谓词越多, 条件和循环结构嵌套的次数越多, 该程序的复杂度就越高。因此, 常见的提高强度的方法有:引入新的类和方法增加程序的长度;引入新的谓词以增加条件语句和循环结构的嵌套层数;增加方法的参数的个数;增加继承树的高度等方法都可以提高混淆变换的强度。

(2) 抗攻击能力--度量混淆后程序抵抗自动攻击的能力。强度高的混淆变换并不代表抵抗攻击的能力就强。通常如果某个变换是单向 (one-way) 的, 即变换是不可恢复的, 如从程序中移除有助于人阅读和理解的格式、变量名、注释等不影响程序执行的有关信息, 这种变换的抗攻击能力就是最强的。对于其它例如在程序中加入不改变程序行为的假的谓词等变换, 能够加大攻击者人工阅读时的工作量, 但却是可恢复的变换。

(3) 代价--度量混淆后程序执行时资源耗费的增加, 而资源指的是经过混淆变换后的程序在执行时由变换所带来的额外的执行时间和所需存储空间的开销。某些变换 (如改名, 格式移除是零开销的, 但多数变换都会带来或多或少的时空开销。变换的开销主要来自于代码增加、数据膨胀和循环增多。更为严重的情况是, 原本能正常运行的程序在经过混淆变换后, 可能因为耗尽内存空间而无法运行。例如, 在多层循环内的一条简单赋值语句所带来的开销要远大于在循环体之外的同样的语句所带来的开销。

4、总结与展望

代码混淆是近年来出现的一种新型的软件保护方法。它通过改变原有代码, 加大攻击者识别的难度来提高对软件的保护。目前, 针对代码混淆技术的研究在国内外已取得一定的成果。但是, 现实世界的攻击是多角度与多层次的, 为了给软件提供更强的保护, 使软件更能抵御静态分析、逆向工程和篡改等恶意攻击, 将多种软件保护技术结合起来是一种有效的选择。

参考文献

[1].Christian Collberg, Clark Thomborson, and Douglas Low.A taxonomy of obfuscating transformation[C].Technical Report148, Department of Com-puter Science, University of Auckland, July1997.

[2].Christian Collberg, Clark Thomborson, and Douglas Low.Breaking ab-stractions and Unstructuring Data Structures[C].IEEE International Confer-ence on Computer Languages, ICCL'98.

软件代码 篇5

你是怎么教人们快速深入挖掘不熟悉的代码(不是自己所写的)?我学习如何编程的方法很传统 —— 自己动手编码。但我现在很纠结:到底是集中精神阅读源码,还是自己编写。对我而言,似乎唯一有效的方法就是自己写过。

不是和Jeremy开玩笑,写代码的确没有读代码难。

首先,我同意你的看法,几乎很少有人能读代码但不会写代码。这不像自然书面语或口语,理解他人的意思并不需要去理解他们为什么要那样说。比如,如果我说:

“写代码有两种方式:一种严格且详细,另一种模糊且草率。前者生成简洁分层的婚礼蛋糕,后者却是意大利面条。”

上面这句话产生一个平衡且幽默的效果,但即使听众和读者不理解我使用“零照应”和“并列句”这样的文字技巧,也会理解我要说的意思。但是说到代码,既要从代码本身中理解代码作者的意图,又要理解代码产生的预计效果,这两者都极为重要。

Eric Lippert

因此,我又回到那个问题了,有些人需要快速切入代码,但不需要动手写代码,那我们如何编写适合这些人的代码?

下面是我在编写代码时,尽力去做的事,目的就是使其他人能轻松阅读:

1. 使代码遵从工具。Object Browsers和Intellisense虽然很好,但我告诉你,我是守旧派。如果找不到我想要的,我会不高兴。什么使得代码成为可查询的呢?

像”i”这样的变量名不好。如果没有明确的错误提示,你就无法轻易查找代码。

避免使用是其他名字前缀的名字。比如,在代码中有个“perfExecuteManifest”,如果再有一个“perfExecuteManifestInitialize”,这就会让我抓狂,因为每次在源码中查询前者时,我不得不费力地过滤掉后者所有的实例。

“临时传递数据”(tramp data)应使用相同的名字。所谓“临时传递数据”(tramp data),就是指那些传递给方法A的变量,还要传给方法B的变量。这两类变量实际上是相同的,所以如果它们有着相同的名字,则更好。

别用宏来重命名东西。如果有个方法叫get_MousePosition,那别这样GETTER(MousePosition)来声明该方法。因为我会找不到实际的方法名。

Shadowing会引起很多问题,请不要用它。

2. 坚持使用一种命名模式。如果你打算用匈牙利命名法,那就坚持并广泛使用,否则将适得其反。使用匈牙利命名法来记录数据,而不是存储类型;记录普遍事实,而不是临时条件。

3. 使用断言来记录先决条件(preconditions)和后置条件(postconditions)。

4. 别缩写英文单词。确切来说,别缩写成稀奇古怪的形式。在脚本引擎中,有个变量名叫“NME”,这让我非常抓狂!它应当叫“VariableName”。

5. C语言标准运行时库的设计不是很优秀。别去效仿它。

6. 别写“聪明”的代码;当代码出现问题,维护代码的程序员没时间去理解你的聪慧。(编注:这条建议即为:编写可维护的代码,详情可参见《明星软件工程师的10种特质》中的第8点。)

7. 理解编程语言特性的设计初衷,使用这些特性去做它们适合完成的工作,而不是它们能做到的工作。例如:别把异常当做一般的流控制机制来使用(即便你能做到),而应该用它们来报告错误。别强制把接口指针转换成类指针,即便你知道这样没问题。

8. 按功能单元划分源码树,而不是按组织结构。比如:我目前所在团队中,有2个根子目录的名字是“Frameworks”和“Integration”,这是两个团队的名字,

不巧的是,Frameworks团队名下有一个叫“Adaptor”的子目录,而“Adaptor”却是Integration的子目录,这就非常令人迷惑。同理,(如果)有着相同子目录的不同的子树,有些是客户端的组件,有些是服务端的组件;有些是管理组件,有些是非管理组件;有些是处理型组件,有些是非处理型组件;有些是零售组件,有些内部测试工具。这就会乱七八糟的。

当然,我实际上根本没有回答Jeremy的问题——如何调试不是我写的代码?

这取决于我的目的。如果我只是因为一个bug,而深挖一段具体的代码,我会在调试器中逐步跟踪所有代码,写下我“走过”的调用分支,记录下哪些方法是特定数据结构的“生产者”,哪些方法是“消费者”;我也会仔细盯着输出窗口,查看出现的有用信息;还要打开异常捕捉器,因为异常通常是问题所在。设置断点;我会记录所有和我上面建议相反的地方,因为这些东西很可能误导了我。

如果我想在理解一段代码后修改它,我通常是从代码头部开始,或者先查找公共方法。我要知道类是如何实现的,它是如何扩展的,它的作用,它是如何嵌入整个代码中的?我会尽力理解这些东西后,才去了解这些特定部分(代码)是如何实现的。这耗时虽更长些,但如果你准备改动复杂代码,你应当那样做。

昨天,我对于这个问题思考了好一会,还跟Larry Osterman进行了讨论,终于想出了一些也许会在阅读和调试别人的代码时有用的建议。

首先,你正在调试的机器代码,很有可能会与源代码不匹配,或者只是因为你得到的源代码不是最新的,或者是因为代码被过度优化以至于源代码和二进制文件之间的关系变得不够明显——像瑞士乳酪那样松散,又或者是因为你遇到符号表错误等等。我当然不是个汇编程序员,但我了解必要的汇编知识和调用规则,这样我可以试着调试那些源代码和二进制之间不是那么同步的代码。即使知道“‘this”指针很有可能在ECX寄存器中”可以对正在进行的调试会话大有帮助。

第二,你还记得那部卡通片Calvin and Hobbes中Calvin偷偷溜到Hobbes的身后吓他,然后学到了吓一只正在睡觉的老虎并不明智吗?Calvin喃喃自语道:“我得开始聆听那没有声音却不停冒出的疑问才行。”

那部卡通片改变了我的生活。我意识到自己常常会犯一个错误,在回顾之前我应该能够提前意识到,但不知因为什么,我却不顾没有声音却不停冒出的疑问而执意地冒失地继续下去。我决定绝不让自己的墓碑上写着“此人死于愚蠢的但本可以完全避免的事情上。”

相信你的头脑。是的,预感有可能是错的,但当它真的是错误的时候,发现它是错的并不需要很大的代价。而如果它是对的,你可以省很多时间。当我在调试我不知道的代码时,我试着去聆听那些没有声音却不停冒出的疑问。在内存显示窗口有一个字节瞬间变成了红色,表明它已经改变了。嗯。在这次函数调用中我是否期望内存发生改变?其自身拥有的内存是改变了,还是只是堆栈错误?嗯,这个局部变量突然变值—这是不是个符号错误?这个变量是否是shadow变量而我则刚刚离开了内部作用域?顺着这类的线索追踪下去。

译者注:shadow变量:当一个变量所在的作用域之外还有一个同名的变量,称为shadow变量;shadow变量只在自己的作用域有效,详细解释和示例参见variable shadowing.

最近我凭直觉在Excel中找到了一个极不起眼的漏洞—我有发现有一个数位的堆分配的缓冲器通过了一个函数但其长度没有通过。嗯。可疑!果真,只要你追踪所有的逻辑,你就会发现更深十级的函数对于缓冲范围作了错误的假设并且造成了一个错误。幸好这个假设十分保守,受到了许多限制,所以没有造成缓冲溢出的后果。还有,幸好这个漏洞极不起眼—一般用户都不会马上就陷入其中。

那么我的第三个建议又会是什么呢?昨天我说过,你需要知道代码是干什么的和开发者为什么要让它干这些。但你还需要知道更多信息—你还要知道代码是怎样随着时间的流逝而在发生改变的。显然在这个漏洞中,程序一开始占用一小块固定大小的缓冲。有人修改了缓冲区分配代码以分配可变范围的缓冲区,但却忘记了这代码所表示的程序是写来假定一个固定的小范围缓冲的。漏洞的发生通常由于在其它合理的代码重整中发生的极小的错误。明显地,没有人会把这样的漏洞写进从一开始就已经有了可变范围的缓冲区代码的代码。当你在阅读一片段的代码时,试着了解不变量将会是什么,然后想想那些情况会违反常量的假定。

软件代码 篇6

动态分析擅长于发现运行时的错误, 如资源泄漏和动态存储错误。开发人员可信赖动态分析工具所报告的任何错误都是真实的, 因为这些错误是在实际代码执行期间被发现的。但为了高效地使用动态分析, 代码必须被全面执行, 因此需要使用测试案例。这样, 动态分析工具在寻找错误方面的效率就取决于测试案例的质量。另外, 由于动态分析工具是与运行软件一起工作的, 因此只能在开发过程的晚期阶段起作用, 此时代码已经完全编好并首次被整合。

对于静态代码分析, 在引入工具之前, 是通过代码同行评审来完成的。这种方式, 在很大程度上依赖于评审人员的经验。有些公司采用了详细的代码同行评审检查表, 但是一个冗长的检查表在检查代码缺陷时实际效果是非常有限的。因此, 出现了越来越多的静态代码分析工具。笔者所在的企业, 通过对多种代码分析工具的试用与比较, 最终选取了Parasoft的Jtest、C++test工具。整个试用过程, 参照CMMI引入新技术的要求进行, 本文总结了整个试用过程, 并对比分析工具的优缺点及带来的效益。

1 静态代码规范检查

1.1 静态规范检查介绍

静态代码分析是指通过分析代码来监视这些代码是否满足安全性、可靠性、性能以及可维护性方面的指标, 以及是否满足企业定义的编码规则。正确地实施代码分析能帮助开发者查找出结构性错误并预防整体类错误, 从而开发出可靠的代码。如果能及时发现并修复可能存在问题的危险代码, 并将其消灭在萌芽状态, 就能为后续工作节省大量的测试与调试时间, 而在后续工作中处理这些缺陷的成本较之前往往会提高几个数量级。

考虑到静态测试的这些特点, Parasoft建议可以让开发人员在代码开发的过程中实时测试, 在这段时间也可以空出测试人员的时间做其他的事情, 节省开发和测试人员的时间成本。针对不同的开发语言, Parasoft提供了不同的代码检查工具, 本次试用包括C++test, Jtest。

1.2 C++test测试过程

C++test能自动对代码进行编程规范检查, 内置1 450多条业界有名的C/C++规则。试用中选取了推荐的33条规则, 整个过程如下:

(1) 选择需要测试的文件, 或者整个工程。

(2) 点击“C++Test”菜单, 选择Test Using>Builtin>Static Analysis>Parasoft Recommended Rules (33 rules) , 即可简单的完成测试。测试过程完全自动。

(3) 测试运行结束后, 在C++test运行界面里可以看到检查出的错误, 如图1所示。

测试过程中选用了1 673个文件, 总共307 532行代码, 耗时130.5 min找到了1 632个问题, 其中严重问题7个, 如图2所示。

C++test静态代码分析检测出了许多在平时编写程序时容易忽略的问题。C++test将静态代码分析的问题分为几个级别, 开发人员很方便从所有的代码问题中找出最重要的部分进行修正。对于每类问题, C++test都有很详细的解释, 帮助开发人员找出代码问题的同时让开发人员的知识得到提高。此外C++test还提供了快速修复问题功能, 让开发人员迅速地解决检测出的代码问题。

1.3 Jtest测试过程

试用过程如下:

(1) 选择需要测试的文件, 或者整个工程。

(2) 菜单栏中选择Test Using>Builtin>Static Analysis>Parasoft Recommended Rules, 即可简单的完成测试。测试过程完全自动。

(3) 测试运行结束后, 在运行界面里可以看到检查出的错误。

2 Bug Detective

2.1 Bug Detective功能介绍

Parasoft的静态代码分析技术支持基于数据流和基于模式的两种静态代码分析方法。Parasoft的这种基于数据流的静态代码分析技术被称为Bug Detective, 它能方便地为用户检测出跨越多个方法、类或者包的运行时出现的问题及程序不稳定性因素 (诸如空指针异常、资源泄漏等) 。目前, Parasoft的Jtest (用于Java代码) 、C++test (用于C以及C++代码) 及.TEST (用于.NET代码) 等工具都提供Bug Detective功能。本文着重以C++test为例, 但是其概念和原则适用于所有使用Bug Detective的工具。

通过在应用程序 (包含跨越多个方法、类和/或包并且含有多个顺序调用路径的复杂应用程序) 中自动追踪和模拟其路径, Bug Detective能及时发现很多程序中的缺陷, 若通过人工测试的方法来查找这些缺陷是相当困难且耗时的, 并且若将问题留到程序发布时来修改, 往往会耗费巨大的资源。使用Parasoft的Bug Detective, 开发者能在早期发现、诊断并且修复基于模式的静态代码分析和单元测试所不能检测到的软件错误。

2.2 测试过程

(1) 选择需要测试的文件, 或者整个工程。

(2) 以C++test为例:点击“C++Test”菜单, 选择Test Using>Builtin>Bug Detective, 即可简单的完成测试。测试过程完全自动。

2.3 测试报告生成

测试结束后, 在C++test运行界面里有个report…按扭, 选择此按扭, 生成测试结果报告, 如图3所示。

3 测试数据统计

3.1 静态代码检查

3.1.1 C++test

本次检查采用的是Parasoft Recommended Rules (共33条规则) , 检查了1 673个文件共307 532行代码, 共耗时130.5 min, 发现1 632个问题, 其中严重问题有7个。从执行效率来看, 每分钟检查文件12.82个, 每分钟检查2 357行代码。

3.1.2 Jtest

Jtest的检查采用了两种不同的运行方式, 其数据对比如表1。

通过对比可见, 选择命令行测试, 在同样的环境下能发现更多的问题。

3.2 运行

Bug Detective运行效率如表2。

3.3 测试数据分析

从试用的数据来看, 速度稍微有点慢, 开发人员只能在本地进行小规模检查。项目级的全面检查需要在服务器每日构建中进行。测试的C++代码相对简单, 内聚强, 耦合小, 也有比较严格的规范, 故发现的严重问题不多。Jtest查出的严重问题占到总问题数的17%, 确实能查出一些代码的问题, 将潜在问题在编码阶段就暴露出来并予以解决。

4 与其他开源工具对比

将项目中曾经使用的开源工具Findbugs与Jtest做一个简单使用对比。主要对比功能性、易用性、性能等方面, 如表3所示。

在没有专业人员指导情况下, 从开始安装Parasoft软件, 到进行完第一次测试, 总共耗时半天时间。说明该软件易用性较好, 学习成本相对较低。经过上述测试, 以及与开源同类软件Findbugs进行功能对比, 可以看出, 相比开源工具Parasoft软件在功能及检查效果方面具有一定优势。特别Parasoft支持团队及组织级集成管理, 可以统一管理和定义检查测试规则、发布测试结果, 方便团队或组织建立统一的检查规范, 并实时对代码质量进行分析。

5 效益分析

在采用静态代码工具之前, 代码同行评审率仅有20%左右, 在项目工期比较紧张时覆盖率甚至只有10%。大量地代码缺陷只有在集成测试环节才能被发现, 极大地增加了修复缺陷的时间和成本。

采用工具之后, 代码检查覆盖率可以达到100%, 且配合持续集成的要求在非工作时间进行, 开发人员每天生产的代码缺陷都及时被检出, 大幅度地提高了工作效率及产品质量。

6 综合评价及建议

(1) 产品使用入门简单, 确实能查出潜在的Bug。长期规范使用, 整个团队可以形成良好的代码风格, 减少常见Bug的出现, 提高团队工作效率

(2) 运行速度稍微有点慢, 开发人员只能在本地进行小规模检查。项目级的全面检查需要在服务器每日构建中进行。

(3) Parasoft的测试工具部署比较复杂, 涉及源代码服务器、测试服务器、测试客户端、报告分发等。规则自定义工具使用要求高, 需要专门培训。

(4) VS2008的C++项目只能在插件版测试工具中进行, 不能在独立运行版测试工具中进行。即需要先安装VS2008, 再安装插件版测试工具。

(5) Jtest测试对机器性能要求高, 应以服务器夜间构建为主, 经过一定的开发后, 开发人员个人使用的频率会大大减少。

(6) 静态代码检查能否获得收益, 取决于检查项的定义。检查项过多过细会导致检查出的Bug过多, 引起开发人员的抵触, 检查项过少则无法起到提高质量的作用。因此, 选择适当的数量并且适合于组织或者项目的检查项将有利于代码检查的推行。

摘要:介绍了所在组织引入静态代码检查工具的试用过程, 包括静态代码规范检查、BugDetective以及从功能性、易用性、性能等方面进行与其他开源工具的分析对比, 其作用及性能皆优于开源工具。并对试行前后的的效益进行了分析, 该工具的引入极大化提高了代码评审覆盖率和代码质量。最后, 给出了具有实践意义的经验总结。

软件代码 篇7

国内外针对软件质量评估提出了很多质量度量模型。 1968年由Rubey和Hurtwick就软件的一些特性提出了度量方法, 但尚未建立质量度量模型, 所提出的度量方法也不完整。1976年, Boehm等人提出了定量的评价软件质量的概念, 给出了60个质量度量公式, 首次提出了软件质量的3层模型。1978年, Waters和McCall提出了从软件质量要素、准则到度量的3层次式的软件质量度量模型。McCall认为, 软件的质量有11个要素构成, 即正确性、可靠性、效率、完整性、可使用性、可维护性、可测试性、灵活性、可移植性、重复使用性和连接性。 ISO 于1985年提出建议, 软件质量度量模型由3层组成:高层软件质量需求评价准则、中层软件质量评价设计评价准则和底层软件质量度量评价准则。ISO3层次模型来自McCall等人的模型, 高层、中层、底层分别对应与McCall模型中的特性、质量准则和度量。

上海软件中心根据ISO/TC97/SC7的建议, 同时参照McCall模型和Boeing模型, 并结合我国实际情况综合构成了SSC (Shanghai Software Center) 软件质量度量模型及度量方法, 从而形成了SSC软件质量评价体系。

2代码审查与评价

2.1检查表设计

缺陷检查表是根据软件质量度量特征归类编写的一些通用的、良好编程规范或者编程注意事项, 本文称之为评价原则, 严格遵循这些原则进行编程能够保证代码质量的各种特性的提高。缺陷检查表设计结构如图1所示。

其中a1, a2, a3, …, an为各项质量特性的权重。

每类质量特征包括多条评价原则, 每条评价原则从程序代码的角度来阐述了程序应该遵循的编写规范, 检查表设计时候应该注意尽量全面概括某一个质量特性的各项评价原则, 保证同一质量特性中各条评价原则彼此独立、互不干扰或者重叠。

2.2度量权重设计

对于不同的软件产品根据其性质的不同, 质量衡量的标准也不同。例如国防武器系统和商用电子制表软件对其质量的要求是不同的, 国防武器系统可能对安全性、易维护性要求更高;而商用电子指标软件可能对其可靠行、易用性、易移植性要求更高。因此, 在评价一种软件产品之前首先要对每种度量特征规定相应的权值。

这里的权值只是一个相对的数字, 例如:如果对可移植性要求只是一般, 则可将可维护性权值设定为3, 如果对可靠性要求较高, 可将其设定为5, 依次类推为每项质量特性根据具体情况设定相应的权值, 最后得到权重矩阵A=[a1, a2, a3, a4, a5, a6]。因此对于国防武器系统, 电子商务系统可能的度量权重设计模式分别如表1、表2所示。

3缺陷统计分析

3.1抽样审查

对待评估系统的全部代码进行抽样, 例如从系统全部代码中随机抽取n份代码, 每份代码包含m行代码 (多余m行的可以从中随机截取m行代码) , 这里n代码相当于n次抽样, 显然, 每组抽样缺陷数据都来自于同一样本空间。

对抽取的每份代码参照代码检查表进行逐行评审, 找出每份代码中的缺陷, 并将其按照软件度量特征进行归类记录, 这样就可以得到n份抽样数据, 每份抽样数据表明在固定的行代码中发现的各类缺陷数总数, 对于第i份代码而言, 假设对每类缺陷的累计计数分别为ωi= (ωi1, ωi2, ωi3, …, ωi6) , 其中ωik, 1≤k≤6是第i份代码第k类质量特性的最终缺陷总数, 从而这份代码的综合缺陷贡献分值为undefined, 全部这些通过评审得到的数据组成了一个样本集, 记作R= (r1, r2, r3…rn) 。

通过将归类于某项度量特征的缺陷数与该度量特征类型的权重进行加权, αjωij从而达到区分软件关键质量特征的目的。

3.2求解缺陷分部函数

将每份代码的最终评价得分R作为随机变量, 假设此随机变量R满足正态分布N (μ, σ) , 利用中心距最大熵法可以求解该分布的参数σμ, 分布函数为undefined。在这里t为每份抽样代码中发现的缺陷数所贡献的分值, F (x) 的实际意义代表全部抽样中每份样本代码中包含的缺陷所贡献的分值小于x的概率。

4质量等级度量

引入评价集Vk= (vk1, vk2, vk3, …vki) , 其中, vki由具体的软件质量测评部门根据软件的特性和实际经验给出, k为每行代码规定的缺陷贡献分值的上限, vki (i=1, 2, 3, …, n) 对应着一个综合质量等级标准, vk1

若F (k) >vki, 则说明该抽样代码的质量标准达到了第i个级别, 从而可以评定被检测系统代码质量等级最低为i级。

至此对软件系统的综合质量水平已给出了一个量化水平标准, 通过建立的缺陷分部函数可以很容易地得出被评测软件综合质量水平。

5结束语

本文论述方法的优点在于从软件系统内部进行抽样分析判别, 从而从实质上把握了软件的缺陷, 具体有以下几个方面:①能够从除测试之外的另一个角度评估系统的质量, 弥补了仅仅通过系统测试来评估软件系统质量的不足之处;②可操作性强, 评估结果在一定程度上量化了软件的综合质量, 弥补了仅仅通过千行代码缺陷数的不足之处, 为开发高质量的软件产品提供了必要的保证。

该方法的不足之处在于:①基于代码缺陷分析的软件质量评估方法对工作的人员要求较高, 要对程序设计和业务领域有比较深入的了解;② 本文对代码缺陷分布遵循的模型假定为正态分布, 这满足一般的经验, 一定程度上能够满足应用, 但是还缺乏理论验证;③ 通过本文提出的方法最终得到的是可靠性特征、效率特征、可维护性特征和可移植性特征等几个软件质量方面的综合评价, 而没有对某一个方面给出具体的量化参数。

摘要:评价一套软件系统的质量, 一方面要对其所表现出来的外部特征进行研究, 另一方面还应对其内部结构进行分析。因为构成软件系统的程序代码质量如何直接决定了整个软件系统的质量水平, 所以程序代码中的缺陷分布特征也直接反映了软件系统的质量特征。介绍了如何通过抽样审查程序代码的方法建立软件缺陷分布函数, 从而达到由软件缺陷分布来对软件质量进行综合、量化评估的目的。

关键词:软件质量评估,代码审查,缺陷分布

参考文献

[1]朱三元.软件质量及其评价技术[M].北京:清华大学出版社, 1990.

[2]ISO/IEC9126.-1:Information Technology-Software Product Quality-Part1:Quality Mode1.ISO/IEOJTC1/SC7/WG6, Junio, 1998.

[3]陈军, 马溪骏.软件质量审查技术及其进展[J].电子质量, 2004 (1) .

[4]孙梦, 宋晓秋, 巢翌.软件程序代码质量度量技术研究[J].计算机工程与设计, 2006 (2) .

[5]袁玉宇.一个实用的软件质量评估模型[J].计算机工程, 2003 (5) .

[6]Deutsch M, Willis R.Software Quality Engineering.Englewood Cliffs, NJ:Prentice-HaH, 1988.

[7]Boehm B W, Brown J R.Quantitative evaluation of softwarequality[C].2ndInternational Conference on software Engineering, IEEE Computer Society, 1979.

[8]刘, 原林.软件质量度量研究及其分析[J].开发研究与设计技术, 2007 (18) .

软件代码 篇8

关键词:android,信息安全,恶意代码,代码分析

Android是一种基于Linux的自由及开放源代码的操作系统, 主要使用于移动设备, 如智能手机和平板电脑, 由Google公司和开放手机联盟领导及开发。2012年11月数据显示, Android占据全球智能手机操作系统市场76%的份额, 中国市场占有率为90%。

Android会同一系列核心应用程序包一起发布, 该应用程序包包括客户端, SMS短消息程序, 日历, 地图, 浏览器, 联系人管理程序等。所有的应用程序都是使用JAVA语言编写的。手机中存储了个人的日常生活隐私和通信隐私等等, 因此android下的恶意软件危害及其严重。黑客可以通过android恶意软件、木马程序等攻击用户, 用户一旦遭受攻击, 将会暴露大量的隐私信息, 会带来诈骗、钓鱼、重要文件失窃等事件, 更有可能带来不可估量的经济损失。

1 Android软件APK结构和功能分析

Android应用程序包文件 (APK) 是一种Android操作系统上的应用程序安装文件格式, 其英文全称为“applicationpackagefile”。任意一个Android应用程序的代码想要在Android设备上运行, 必须先进行编译, 然后被打包成为一个被Android系统所能识别的文件才可以被运行, 这种能被Android系统识别并运行的文件格式称之为“APK”。

APK文件是基于ZIP文件格式, 它与JAR文件的构造方式相似。它的互联网媒体类型是application/vnd.android.package-archive.通过观察Android工程在Eclipse的目录结构分布。

2 基于代码特征的恶意代码特征库构建原理和设计

首先采集样本, 样本来源于contagiominidump.blogspot.com。人工构建敏感API名单, 通过对SDKAPI的分析, 将获取联系人、短信、通话、网络、录音、GPS、摄像等相关的API作为初始化敏感API。

Zip APk批量解压模块, 利用zlib库实现, 通过代码实现全自动解压缩, 将获取的样本逐一解压。APK缓存文件生成之后交由Dex2Jar处理。

Dex2Jar依赖于JDK环境, 将.dex/.odex的二进制字节码反编译, 转换为java的Jar包。

JAR (Java Archive, Java归档文件) 是与平台无关的文件格式, 它允许将许多文件组合成一个压缩文件。通过zlib库将得到的Jar文件进行解压缩处理, 放入缓存, 已备后续流程处理。

Jar预处理完成交由Smali->java模块处理, 该模块由Jad实现, Jad将生成smali文件反编译为能够有文本编辑器识别的Java代码, 将所有当前生成的Java文件夹放入缓存, 交由文本匹配模块进行特征提取。

根据手工设定的敏感API进行特征提取, 将每个样本的敏感API组合特征和出现频率等进行统计和入库。

3 基于代码特征的恶意APK静态分析系统原理与设计

恶意代码样本库特征初始化完成, 有本部分完成对待分析APK的恶意代码的静态分析。

首先将要分析的APK输入到该系统, 通过Dex2Jar, Jar转换Java代码文件, 待分析代码放入缓存区域, 将待分析代码输入到特征匹配模块, 利用之前生成的恶意代码特征库进行特征匹配, 将匹配的结果生成到分析报告中。

4 结语

首先对Android系统进行了简单的介绍, 并简略的叙述了当前Android恶意软件带来危害, 然后通过对Eclipse工程项目的结构对APK结构进行了简要的分析, 并分别介绍了各自的功能, 恶意代码通常包含在dex文件之中, 不排除有部分恶意软件动态加载加密的资源执行隐藏的代码。

在最后提出了Android下APK中的恶意代码特征库组建模型, 叙述了它的实现流程和原理, 再次基础上设计基于代码特征的APK恶意代码分析系统, 通过对特征的提取和分析得出分析报告。

该设计是在特征库足够完备和权重指标足够完美的前提下运作的, 能够更加快速的分析软件恶意特征。

参考文献

[1]戴明星, 陈正奎.Web网站的安全代码设计[J].信息安全与通信保密, 2010.

[2]wxSQLite3.wxSQLite3 Source Code[EB/OL]. (2011-02-12) [2012-09-15].

[3]刘嘉勇, 方勇, 胡勇.应用密码学[M].北京:清华大学出版社, 2008.

[4]李鑫, 周安民.对多种Web语言嵌套的跨站过滤分析[J].信息安全与通信保密, 2012.

[5]徐少培, 姚崎.基于操作劫持模式的Web攻击与防御技术研究[J].信息安全与通信保密, 2011.

代码干扰变换在软件保护中的使用 篇9

关键词:代码干扰,代码变换,反向工程,静态分析,控制流,数据流

0 引 言

近年来随着程序分析和软件工程技术的发展,程序分析和软件开发工具得到了极大的改进;但是这些技术同时也被反向工程系统用于发现软件的弱点和漏洞,从而实现软件的非法修改或盗用知识产权。为识别软件系统的薄弱点,黑客对软件分析后能够知道软件是如何工作的,并从哪里容易实现攻击。例如,为盗用加有水印的软件,他们很可能重构软件的内部结构,来隔离水印 [1]。针对这些软件保护问题,学者们提出了对软件的执行代码进行加密(在运行时适当地解密)或者结合硬件来实现保护。然而这在许多高性能需求的环境很不利,也因依赖硬件而缺乏灵活性。代码干扰变换是加大程序复杂度并降低程序可读性的途径。加大程序的复杂度可以使得攻击者很难通过反编译工具破解并分析软件;降低程序的可读性则可以使得攻击者即便获得了软件源代码或中间代码也不能轻易读懂程序[2]。

文章阐述了两种代码干扰变换:基于不透明谓词的变换与降级高级控制结构的变换,对软件能产生很好的保护效果。

1 基于不透明谓词的变换

不透明谓词的结果在设计时是可知的并是常量(真或假), 却难以被反干扰技术推断出来。基于不透明谓词构造的代码变换能够分解顺序控制流来迷惑或误导攻击者。

1.1 不透明谓词分解顺序控制流

PF(PT))来表示不透明谓词的结果为永假或永真;P?表示结果有时为真,有时为假。如图1所示。

图1(a)在块A、B间插入结果为真值的不透明谓词,使得B好像有时才执行;图1(b),B被分成两个不同的版本,B 和B’ ,它们是等价的,这也使得B好像有时才执行;图1(c) 总是执行 B 而不是 Bbug 。

这些干扰变换的可靠性依赖于不透明谓词,引入的谓词既不能与一般程序代码的谓词相差太大(很容易被反向工程探测到),也不能太复杂。

1.2 不透明谓词的构造

许多反代码干扰者掌握了多种静态分析技术,我们很自然会想到,根据这些分析技术的薄弱处来构造不透明谓词,但这过于复杂。目前的基于指针结构和并行区域静态分析技术功能非常强,然而从已有的理论研究和多年的编译优化实践经验表明,要建立快速准确的别名分析非常困难[3];而且这类分析对深层嵌套结构和对结构的分离、合并、删除操作无效。因此我们采用指针别名与结构变化的方法,来建立可靠而低代价的谓词,如图2所示。

图2 (a),(b),(c)中有不透明谓词 if (f==g)? ,因为指针f、g在同一结构中移动,它们可能互为别名,也可能分别指不同的对象。从 (c)到 (d),结构分离后,便有不透明谓词 if (f==g)F,此时f,g在不同的结构中移动。最后在(f)中两个块又被合并,便有不透明谓词 if (f==g)? 。

此例是针对别名分析这一棘手问题构造的不透明谓词,将这种思想用于程序中需要使用代码干扰的模块上,能形成一套复杂的动态结构。使用较多的全局指针来引用该结构上的一些节点,并引入一些代码来对结构进行修改(修改指针、增加节点、分离与合并结构等)。但这些修改要保持某些不变性,如:指针p和q不能指向同一个堆或不存在从p访问q的途径等。这些不变的特性对于手工构造不透明谓词是很有必要的,以免给静态分析者留有机会。

2 降级高级控制结构的变换

静态分析可分为对控制流敏感和不敏感两类。对于控制流敏感的分析,它先要建立程序控制流图,然后在此基础上进行数据流分析。没有控制分析中的程序调用和分支跳转信息,数据分析只能限制在基本块内,这对静态分析没什么作用。目前绝大多数程序的控制流很容易被分析工具探测到,主要是因为高级程序设计语言的使用,使得程序结构清晰,模块独立性强;这方便了写程序,但同时也给软件的安全留下了隐患。因此相应的技术路线是使控制流的静态分析与数据分析相关,然而超出基本块内的数据分析又依赖于控制流信息,这样就使控制和数据的分析相互依赖。这极大地增加了两者静态分析的复杂性又降低了静态分析精度。

降级高级控制结构能增加控制与数据流的依赖性,实现干扰分支跳转和转子调用的静态探测。

2.1 降级高级控制结构

我们分两步来执行这种转换。第一步,将高级控制结构降级成 “if-then-goto”结构。如图3所示。

第二步,修改 goto 语句,使其目标地址由动态决定。通过用数据变量的值来替代跳转地址,如图4所示,用 switch 来替代 goto 语句后, switch 变量的计算决定了下一步执行哪个代码块。

根据上面的变换,直接跳转被数据相关的指令替代,静态分析的控制流图降级成了上面的“扁平”图 。这个过程体现了把一个对控制流敏感的分析产生的流图变换成低级扁平图的过程。从扁平图中,分析者不知道跳转目标和块的执行顺序,每个块都可能是其它块的前驱块。

没有分支目标信息,建立静态流图的复杂性由分支点决定,为此要探测最近的分支变量。这是典型的数据流分析,而数据流分析的复杂性又受程序特征的影响。

2.2 干扰分支目标

上述变换使控制流的探测归结为分支目标的数据流探测,很多数据流问题已被证明是NP完全问题[4]。而别名是数据流分析的一个不可跳跃的难点。

为此,引入函数和全局数组来计算扁平图中的 swVar变量。在不同的块中使 blocki: 用swVar=global_array[fi ()] 替代 swVar=constanti ,这样静态分析者在获取 swVar 前必须间接获取 fi ()和 global_array[j] 的值。

再引入指针别名:在数据块中设置一些指针变量,并插入一些相关代码,使指针指向包含全局数组在内的数据变量;然后通过指针间接访问变量和数组;在不同的块,指针和变量的其它定义方式交替使用,特别是指针和数组的等价间杂交替使用。

在程序中,一些基本块是必执行的,而一些块是死代码,这是静态分析者难以区分的。因指针在不同的块都有使用,这就使得分析者难以判定哪个指针在当前块是活动有效的,原因是所有被赋值的指针能同时出现。静态分析程序块A:“ *p=a; a=a+b; *p=b; b=3; ” ,很容易识别只有第二指针 p 的定义<*p,b > 才能代表 p对A块的引用点。如果把A块分解成A1: “ *p=a; a=a+b;swVar=f1(); ” 和A2: “*p=b; b=3;swVar=f2(); ”子块,两块间的过度采用前一小节“扁平”图控制处理,分析后会产生关系<*p,a >,<*p,b >,因为分析不能确定A1 ,A2哪块先执行。

现在对上节图3(a)中的代码,分别使用降级高级控制结构和干扰分支目标后,代码结构如图5所示。

变换的结果使静态分析产生不精确的别名关系,这些别名暗中改变过全局数组,而且其内容也是在动态变化。引入足够的别名后,分析工作必须处理在大范围内变化结果的数组元素,也说明在实际的每次运行时,switch 变量呈现一个很大的结果集合。这增加了数据分析的难度,而程序控制流图的分析又依赖它,使得静态控制流的分析工作相当困难。

3 结束语

目前,大多数的软件都是以可执行代码的形式发布的,易遭受反向工程的攻击。如果程序本身具有反静态反编译的性能,就可以增加攻击者分析可执行代码的难度,从而起到软件保护的作用。本文所讨论的代码变换就是要从源代码级增强软件的反编译性能,是一种有效的软件保护方法。在软件代码的敏感处,特别是在“许可注册/验证”部分使用多种方式代码变换技术来实现干扰,在实际应用中是很奏效的。但是人工进行代码干扰变换增加了程序员的难度,代码也不易维护,因为本是一些很容易用高级语言书写的代码,却有意将其控制复杂化难理解。然而要实现代码的等价变换,在理论上已有可行性。如何有效地把代码变换理论用于实际编译器上,使得代码干扰变换实现对软件的保护由人工走向自动化,这将是很有价值的研究课题。

参考文献

[1]吴金波.反静态反汇编技术研究[J].计算机应用,2005,25(3):626-625.

[2]李长青,李晓勇.基于控制转换的软件保护[J].信息安全与通信保密,2006,10:146-149.

[3]SCHWARZ B,DEBRAY S,ANDREWS G.Disassembly of executable code revisited[A].Working conference on reverse engineering,2002.

软件代码 篇10

软件错误是软件在运行时引起软件失效的一个缺陷。软件工程中,BUG是只不符合软件需求的错误。软件错误、软件失效及软件的BUG在软件工程中是有区分的。软件失效是指软件不按用户的期望来运行,而软件错误则是隐藏在程序中的错误,有可能会被发现也有可能不被发现。

有很多不同的度量方法可以预测软件错误。如在代码开发过程中的代码静态度量方法有Halstead复杂性度量方法、McCabe复杂性度量方法等可用来检测模块的错误趋势。Fenton对用不同的语言实现同样功能的程序模块用不同静态度量方法进行了代码静态度量,结果Fenton对这种代码属性的静态度量提出了质疑。所以单纯用代码的静态属性度量是不准确的。

一个正在开发模块具有的错误趋势与在相同开发环境下和相同度量体系下的其他模块具有相似的错误趋势。因此,开发项目的早期信息或早前的工程项目的信息可以用来预测后面的软件错误趋势。虽然单独的需求度量并不是最好的错误预测方法,但它却可以增强错误预测的实施。

错误趋势预测模型应该具有有效性和准确性,因此,结合从需求文档和代码中抽取出的静态属性是比较好的度量数据来源。目前提出的预测软件错误的方法有统计方法、机器学习方法、神经网络技术和聚类技术等。在软件质量度量方面,目前利用统计和机器学习的方法对软件的需求或者是软件的代码进行度量的工作做了很多,而用聚类的方法来度量需求或软件代码静态属性的不多见。用聚类的方法结合需求和代码静态属性度量软件质量的工作目前还没人提出。软件错误趋势预测为通过软件工程进度计划和工程控制来提高软件质量提供了一条道路。

最后,本文绘制了ROC (Receiver Operator Characteristic)曲线,使用获得的数据值来比较三个模型的优劣,即静态代码度量模型,需求度量模型和需求与代码度量的组合度量模型。

1 软件错误早期预测方法

我们在需求阶段的度量数据和软件系统的代码结构是从美国航天局(NASA)的MDP (Metrics Data Program)数据仓库中收集而来的。MDP数据仓库包含了13个项目的数据,其中仅有3个项目的数据包含需求度量。这三个项目分别是CM1(用C语言编写),包含有大约505个模块,JM1(用C++编写),包含10878模块,PC1(用C语言编写)中包含有1107模块。CM1是美国航空航天局的航空器的仪器系统,JM1是一个实时地面系统而PC1是地球轨道卫星系统。在对从美国航空航天局项目中的数据进行收集和提炼后,上面提到的项目的需求度量和模块结构度量通过内部连接方法进行了连接。

1.1 聚类算法

聚类是一种根据某些标准来将数据划分为两个或多个群组的技术。因为在本研究中我们将数据分为两个聚类,分类的依据是看这些数据是否是无错误或有错误倾向的。所以,需要选择一个合适的将软件模块划分成缺陷模块和无缺陷模块的算法。

我们用到的聚类是利用软件度量数据中具有有限的或无错误倾向的数据去分析软件质量的一种方法。本文在预测模型中使用聚类算法中的K-Means聚类算法来预测模块中是否有错误存在。K-Means将数据分类为k组,k是一个根据数据的属性或一些性质来选定的正整数。

本文提出的软件质量预测模型试图预测软件模块具有错误倾向是否为影响软件质量的因素。识别有错误倾向的软件模块的方法有助于改进开发资源计划和进度安排,同时通过有效的错误检查能够降低开发和维护成本。这种模型可以用于不同的情形,可以预测一个模块的类(如有缺陷倾向性或无缺陷倾向性)或预测一个模块作为软件质量因素的影响(例如缺陷的数量)。然而不同的软件工程实践限制了缺陷倾向性的数据的获得。由于这种影响,监督聚类是不可能用来实现软件质量分析的。这种受限的缺陷倾向性数据可以用半监督聚类来进行分组。利用软件工程领域专家知识反复创建无缺陷聚类或错误倾向性聚类是基于聚类方案的一个约束条件。

为了预测结果,我们使用了混淆矩阵。这种混淆矩阵有四大类:真阳性(TP:True Positives)是指有缺陷的模块被正确的分类为缺陷模块。假阳性(FP:False Positives)是指无缺陷模块被错误的标记为缺陷模块。真阴性(TN:True Negatives)是指无缺陷模块被正确的标记为无缺陷,假阴性(FN:False Negatives)指那些有缺陷的模块被错误的标记为无缺陷。图1为预测结果的混淆矩阵。

利用图1,我们用下面的评估方法来获得一些有用的结果:

(1)检出率(PD),定义为将有至少一个缺陷的模块正确的分类为缺陷模块的概率。

(2)误警率(PF),定义为假阳性与所有没被正确检测出其性质的模块的比值,包括有缺陷的和无缺陷的模块。

根据上面定义,在软件工程实践中,我们希望PD最大的而PF最小。

1.2 ROC曲线

ROC是Receiver Operator Characteristic的缩写,中文称为接收器运作指针曲线。这项技术起初是为了增进军事雷达的敌我侦测能力而发展的。在1954年的情报理论研讨会上,哈佛大学的Meter及Middleton和密西根大学的Peterson、Birdsall及Fox同时提出了应用概算比(likelihood ratio)作为决策法则的报告。随后,这项决策法则被整合为ROC曲线。本文中的ROC曲线是在所有的实验组中PD对比PF的一个曲线图。通过对软件项目中检测出来的缺陷模块和非缺陷模块的比较来分析软件项目的成本/效益值,在这种分析中采用ROC曲线的方法是一个比较好的方法。对于不同的参数之间的比较,ROC曲线提供了更直观的显示。对于我们描述的方法的ROC曲线的示意图如图2, PD和PF值的范围从0到1。图中绘制的X轴和Y轴的取值范围都是从0到1的。在图2中绘制的点代表了预测模型中的将缺陷模块和非缺陷模块分类的可视化对比。

典型的ROC曲线是从(0, 0)开始和(1, 1)结束的凹形曲线。本文的ROC曲线分为四个不同的区域,即成本下降区域,风险下降区域,负曲线区域和无信息区域。在图2中,一条直线连接(0, 0)和(1, 1),意味着一个分类器的性能并不比随机猜测更好。图2中的点E和F落入风险下降区域,从图可以看出,E、F点的PD与PF值都很高。这种情况对于高安全需求的系统较合适,因为这类系统更要求识别系统故障,相对来说对成本的考虑就要低一些,只要能有利于找出故障,高误报率是可以接受的。在图2中,ROC曲线上标记为A, B, C和D的点,因为低的缺陷检出率,所以几乎没有提供有关模块错误倾向性的信息。

ROC中的负曲线由低PD和高PF数据点组成。在软件工程实践中,高PD和低PF说明了模块被正确归类的比例是很高的。当PD值降低,而PF值增加时,表明模块被错误归类的概率增加。但是,这不一定是件坏事,因为在分类器否决它们的一些测试时,这可以作为它们的首选曲线。

2 结果分析

本文所提出的方法采用美国航天局的公开数据集MDP来评估软件产品的质量。我们用到了这些数据集中的CM1, JM1和PC1,因为这3个是MDP数据仓库中仅有的包含软件需求度量的项目。我们利用文献[2]中提出的模型度量需求、代码及需求和代码混合的度量。这些预测模型使用了k-means聚类方法,在软件产品中找出那些具有缺陷的软件,和那些没有缺陷的软件产品,然后在这些预测模型中找出最佳的预测模型。

在MATLAB7.4中,聚类是其统计工具包中的一个内置功能。我们在MATLAB7.4系统上利用其聚类功能对我们的方法进行了运行,其功能的参数是其默认参数。

在我们的研究中,JM1数据集作为我们的数据训练集,通过计算其特征值训练,并用训练出来的数据对评估软件的质量。PC1和CM1数据集作为测试数据,以检查其中的三个预测模型,得到一个最好的模型,用不同的聚类算法评估软件质量度量的方法,从而证实软件测试和质量保障的需求。对于比较的结果,PD值应该是最大的而PF值应该是最低的。这些值的范围从0到1。

表1显示了在JM1数据集上采用K-Means算法聚类来训练数据,并且对CM1和PC1使用了需求度量来计算它们的真阳性、真阴性、假阳性、假阴性和检出率及误警率的结果。CM1需求度量的TP值计算出来为0, TN是21, FP是0而FN是67, PD值和PF值分别都是0。类似的,对PC1采用需求度量后计算出来的TP值是0, TN是213, FP是0而FN是107, PD和PF值分别都是0。这些值显示了单个需求度量的效果并不好。表2给出的是CM1和PC1的静态代码度量的结果。CM1的代码度量的TP值是0, TN是457, FP是0, FN是48, PD和PF值分别都是0。这里PD和PF值都是0意味着这样的度量效果也不好,其值几乎和需求度量模型一样。从两个表的结果看,我们认为联合上诉两种度量方法可能效果就会比较好。

表3显示的是需求和静态代码联合度量模型的结果。其对CM1项目数据集的TP, TN, FP, FN, PD和PF值分别是66, 107, 76, 17, 0.99729和0.79518。对PC1项目数据集的TP值是115, TN值是1, FP值是361, FN值是0, PD是1和PF是0.99724。

因此,根据上面所反映的情况可以看出,通过对训练后的数据集进行静态代码度量和需求度量操作更能代表软件工程的真实情况。

源于需求度量和静态代码度量模型的PD和PF在软件容错度量方面要比先前文献中提到的方法更准确的对系统进行度量,该模型可用于对软件系统进行“故障系统”和“非故障系统”进行分类。

3 结束语

在这项研究中,我们在生命周期的早期阶段,知道错误倾向的数据情况下,结合代码中的可用数据来预测项目的错误倾向。这种预测结果能够帮助项目管理者更准确地构建项目系统,并且在预测了错误区域后能够减少测试的投入,这样这些模块可以得到妥善控制。使用这种混合度量模型的主要优点在于比较于单个的度量模型,它能够更给出更准确的度量结果,并且有助于提高软件产品的生产效率。当然,这还需要做进一步的研究,在后继的研究过程中,对于错误预测的相关影响也会逐步被发现。

参考文献

[1]FENTON N.E.and Pfleeger S.L.Software Metrics:A Rigorous and Practical Approach[M].PWS publishing Company:ITP, Boston, MA, 2nd edition, 1997.

[2]JIANG Y.CUKIC B.and Menzies T.Fault prediction using early life-cycle data[A].ISSRE2007, the18th IEEE Symposium on Software Engineering[C].IEEE Computer Society, Sweden, 2007.

[3]NASA IV&V Facility.Metric Data Program[EB/OL].Available from http://MDP.ivv.nasa.gov/.

[4]SELIYA N.KHOSHOFRAAR T.M.AND ZHONG S.Analyzing soft-ware quality with limited fault-proneness defect data[A].in pro-ceedings of the Ninth IEEE International Symposium on High As-surance System Engineering[C].Germany, 2005.

上一篇:根管螺纹钉下一篇:企业收益分配