软件安全评估之设计评审入门(上)

这篇文章详细阐述了软件开发生命周期中的设计评审,强调了算法和业务逻辑在设计中的作用,以及信任关系、抽象分解和纵深防御在确保系统安全中的关键。它讨论了如何通过设计审查来避免潜在漏洞,并介绍了如何通过有限信任和多层次防护来提升网络安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基础概念

在软件开发生命周期(Software Development Life Cycle,简称SDLC)中,设计评审(Design Review)是一个关键的阶段,旨在确保软件设计满足项目需求和目标,并且能够高效、可靠地实现预期功能。

设计评审通常在需求分析和系统设计阶段之后进行,是软件开发过程中的一个重要质量保证活动。在设计评审阶段,项目团队会审查和评估软件设计文档,以确保设计满足所有业务和技术要求。

设计评审主要包含以下三个方面:

图片

软件设计基础原理

2.1    算法

软件工程是关于设计、开发算法和数据结构的实践,它强调逻辑性地解决问题。要确保系统安全,我们需要先理解系统的核心算法,并识别可能的安全风险。

2.1.1    业务逻辑

业务逻辑决定了程序处理数据时的规则。软件系统设计需整合执行关键任务的规则与流程。设计中需考虑对用户和资源的安全需求。

例如,具有以下业务逻辑规则的银行软件:

用户可将资金从主账户转账至任何有效账户。

用户可将资金从货币市场账户转账至任何有效账户。

用户每月仅限从货币市场账户转账一次。

若用户主账户余额为负,系统将自动从用户的货币市场账户中转出所需资金以补足余额,前提是该账户有足够资金。

上述例子虽然简单,但暴露了系统设计中的潜在漏洞:客户可能通过使主账户余额降至零以下,来规避货币市场账户每月转账的限制,从而获取额外资金。

2.1.2    关键算法

程序的性能需求对其算法和数据结构的选择具有决定性影响,这些选择直接关联到关键数据片段的管理效率。通过深入分析这些算法,我们可以预见潜在的安全风险,并提前采取措施加以防范。

以一个具体案例为例,假设一个程序使用有序链表来存储一系列记录,该链表支持基本的顺序搜索功能,单向链表的时间复杂度是O(n)。了解到这一点后,我们可以预测,如果面对一个经过特别设计的大量记录列表,程序在执行链表搜索时可能会消耗过多时间。针对这种关键算法的连续攻击,可能会对服务器的稳定性造成影响,进行拒绝服务攻击。合理的搜索算法应该是二分查找算法,其时间复杂度是O(logn)。

2.2    抽象分解

图片

抽象 是指从具体实例中提取共同特征,忽略不相关的细节,从而形成一个更高层次的概念或模型。在计算机科学中,抽象是一种常见的设计原则,它允许开发者专注于系统的核心功能,而不必关注底层的实现细节。例如,编程语言提供了高级抽象,使得程序员可以用更接近自然语言的代码来表达复杂的逻辑,而不必担心硬件层面的操作。

分解 是指将一个复杂的问题或系统分解成更小、更易于管理的部分。通过分解,可以逐个解决这些小问题,然后将解决方案组合起来,形成对原始大问题的解答。分解有助于提高问题解决的效率和质量,因为它使得问题更加具体,也更容易测试和验证。例如,在软件工程中,一个大型项目可能会被分解成多个子系统或模块,每个部分由不同的团队负责开发。这样,每个团队可以专注于自己的任务,同时保持整个项目的协调一致。

2.3    信任关系

在第 1 篇文章《软件漏洞基础》中,介绍了信任概念及其如何影响系统安全。本文进一步扩展这一概念,指出多方之间的每一次通信都必须有一定程度的信任与之相关,这被称为信任关系。对于简单的通信,双方可以假定完全信任,即每一方都拥有完全的信任。

在通信过程中,虽然各方可能提供了对其公开功能的全面访问权限,但为了确保安全性,应当更加关注如何适度地限制各方之间的信任程度。仅允许对对方功能的有限访问,确保每个功能点都受到适当的保护。这种对访问权限的限制,实际上构成了各方之间的信任边界,明确划分了信任域的范围。

信任域是一个共享的信任区域,它通过明确的信任边界来区分。

在软件设计的实践中,我们必须要对系统的信任域、边界和相互之间的关系进行深思熟虑。信任模型,作为一种抽象的代表,成为了应用程序安全策略的关键组成部分。这个模型不仅影响着系统的架构设计,而且通常建议信任应当是有限度的,而非绝对的。这种有限的信任体现在不同层级的权限设置上。

图片

例如,UNIX/Linux 文件系统提供了一套标准的权限管理机制,允许用户针对系统中的其他用户或组设置不同的文件访问权限(自主访问控制模型的一种)。通过这样的机制,文件所有者可以精确控制其他用户对特定文件的读取、写入或执行权限,从而在系统中建立起有限的信任关系。这种基于权限的控制方式,不仅增强了系统的安全性,也为用户提供了灵活的访问控制选项。

2.3.1    简单的信任边界

让我们以 Windows 98 这个经典的单用户操作系统为例,来探讨信任关系的概念。在这个系统里,一旦用户登录,他们就拥有了对整个系统的几乎完全控制权。这意味着,用户可以自由地修改任何文件和系统设置,没有内置的机制来限制他们的行为。因此,在这种环境下,我们不能期望普通用户之间会存在安全保障,因为他们本身就拥有系统的完全访问权限。

在这个例子中,信任边界实际上是关于谁可以物理接触到计算机硬件的问题。只有被授权的人才能使用系统,这就形成了一个由可信用户组成的内部圈子,而那些无法接触系统的人则构成了外部的不可信圈子。

现在,如果我们将场景转移到更先进的多用户操作系统,比如 Windows XP 专业版,情况就会变得更加复杂。在这个系统中,我们期望即使是拥有特权的用户也不能随意干扰其他用户的数据和进程。这种期望是建立在普通用户身份的基础上的,而不是管理员身份。因此,我们在不同用户之间建立了一种信任关系,他们之间存在一个界限,确保各自的数据和进程安全不受侵犯。同时,管理员账户则需要有额外的权限和责任。

这种多用户环境要求我们在用户之间设定明确的界限。如果没有这些界限,系统就会退化成单一用户操作系统的状态,任何用户都可以随意改变系统的状态。在多用户操作系统中,信任关系的图形表示可以帮助我们更清晰地理解这些界限。

图片

最终,我们需要认识到,每个系统都需要一个最终权威的、可以信赖的责任主体。无论是 UNIX/Linux 的 root 账户还是 Windows 的管理员账户,它们的存在是必要的,因为总得有人对系统的状态负责。虽然我们可以对这个最高级别的权限施加各种控制,但不可否认的是,在每个信任边界内,至少有一个拥有绝对权威的实体。这是确保系统有序运行和保障系统安全的基础。

2.3.2    复杂的信任关系

在网络环境中,系统不再是孤立的实体,而是成为了一个互联网络的一部分。这时,我们需要对不同类型的用户和访问者进行区分。例如,本地用户和远程用户可能需要不同的访问权限和安全级别。本地用户,即直接在系统上操作的用户,可能需要更多的权限来执行日常任务,而远程用户则可能受限于特定的服务和数据访问。

此外,网络中的其他实体,如服务和设备,也可能需要被纳入信任模型的考虑范围。防火墙和网关等安全设备在这里扮演着至关重要的角色,它们不仅保护系统免受外部威胁,还帮助定义和实施信任边界,确保只有经过验证和授权的流量才能进入系统。

在软件设计过程中,定义和应用一个有效的信任模型是至关重要的。这项工作应该在设计阶段之前就开始进行。在可行性研究和需求收集阶段,我们必须识别和定义用户对安全性的期望,以及目标环境中可能影响系统的各种因素。得出的模型需要足够强大,能够满足这些需求,同时又不能过于复杂,以免难以实施和维护。安全性的设计需要在保证清晰性和准确性的同时,找到适当的平衡点。

2.3.3    信任链

在第 1 篇文章中,我们讨论了传递信任的概念,这是一种重要的安全机制,它描述了组件之间的信任如何通过整个系统传递。具体来说,如果组件 A 信任组件 B,那么 A 也会间接地信任 B 所信任的所有其他组件。这种关系构成了一个信任链,它是许多系统安全性的基础。

图片

以安全套接字层(SSL)连接为例,我们可以看到一个实际的信任链是如何工作的。当你通过 SSL 连接访问一个网页服务器时,你的浏览器会使用一个本地的证书数据库来验证服务器证书的有效性。这个数据库包含了你信任的证书颁发机构(CA)。这些 CA 可能会颁发证书给其他的 CA,形成一个证书链,直到最终网站的证书具有证书链上的其中一个 CA 签名。为了验证这个连接的安全性,你的浏览器需要沿着这条从服务器证书到你信任的 CA 的信任链进行检查,只有当链条完整无缺,连接才被认为是安全的。

然而,这种信任链也存在潜在的弱点。如果攻击者能够操纵任何环节的证书数据库,无论是访问者的客户端证书数据库,还是目标网站,或者是信任链中的任何一个 CA 的数据库,包括根 CA,他们就能够伪装成任何网站。这是因为,信任链的传递性质意味着只要攻击者破坏了链条上的任何一个环节,他们就能够成功地模仿任何网站。即使那些颁发真实证书的 CA 没有受到损害,攻击者仍然可以利用由有效 CA 颁发的任何证书来进行攻击。这表明,SSL 交易的安全性实际上是由链条中最薄弱的环节决定的。

尽管传递信任链是一种广泛使用的机制,但它的复杂性和潜在的脆弱性需要我们进行仔细的审视。作为安全分析人员,需要深入分析这种信任模型的影响,确保信任链的设置是恰当的,并且要跟踪系统中所有组件之间的信任关系。这样,才能准确评估每个组件的暴露程度,并识别出可能被攻击者利用的复杂和微妙的信任关系。通过这种细致的分析,我们可以更好地保护系统,防止潜在的安全威胁。


 

2.3.4    纵深防御

纵深防御策略是一种综合性的安全方法,它通过在不同层次上部署保护措施来增强系统的安全性。这样,即使攻击者突破了一层防御,仍然有其他层次的安全措施来减轻可能的损害。这种策略的核心在于构建多重防线,确保安全性的全面覆盖。

在实施纵深防御时,一些基本的做法包括使用具有有限权限的账户来运行关键服务和后台进程,这样可以减少攻击者通过这些服务获得更高权限的机会。此外,将系统的不同功能分散到不同的硬件平台上,可以有效地隔离风险,防止单一故障导致整个系统的崩溃。

更高级的纵深防御措施可能涉及建立网络非军事区(DMZ),将对外提供服务的设备放置在一个受限制的子网中,从而保护内部网络不受直接的外部威胁。同时,在 UNIX/Linux 系统中使用 chroot 技术可以限制程序的运行环境,使其只能访问特定的文件和目录,从而降低潜在的安全风险。另外,通过实施栈和堆保护机制,如栈保护和地址随机化,可以有效地防止缓冲区溢出等常见的攻击手段。

在对系统组件进行安全审查时,考虑纵深防御的概念可以帮助我们合理地分配审查资源和确定优先级。例如,一个在内网中运行、使用低权限账户、处于 chroot 环境中、并且在编译时加入了缓冲区保护的组件,可能被认为是相对低风险的,因此可能被赋予较低的评审优先级。相反,一个需要以 root 权限运行、面向互联网的组件,因其潜在风险较高,可能需要更高的评审优先级。

需要注意的是,这并不意味着低风险组件就完全不需要关注,或者高风险组件一定存在问题。关键在于根据证据和风险评估来优先安排安全工作,确保我们的努力能够产生最大的正面影响。

作者:MMM

 2024年4月8日  

 洞源实验室

{************************************************************** 浅谈软件安全设计(一) code by 黑夜彩虹 & vxin with almost pure delphi 网站:http://soft.eastrise.net 2007-03-07 --- 转载时请保留作者信息。 **************************************************************} 此CM的设计模式: 1、插入一些花指令 2、写了一些代码迷惑Cracker 3、有简单的Anti_DEDE 和检测调试器 话不多说,请看以下代码: unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,strutils; Const C1= 17856; C2= 23589; type TForm1 = class(TForm) Image1: TImage; Edit1: TEdit; Label1: TLabel; Label2: TLabel; Edit2: TEdit; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} Procedure Anti_DeDe();//检测DEDE反编译器 var DeDeHandle:THandle; i:integer; begin DeDeHandle:=FindWindow(nil,chr($64)+chr($65)+chr($64)+chr($65)); if DeDeHandle0 then begin For i:=1 to 4500 do SendMessage(DeDeHandle,WM_CLOSE,0,0); end; end; Function ABC42():Boolean; //检测调试器; var YInt,NInt:Integer; begin asm mov eax,fs:[30h] movzx eax,byte ptr[eax+2h] or al,al jz @No jnz @Yes @No: mov NInt,1 @Yes: Mov YInt,1 end; if YInt=1 then Result:=True; if NInt=1 then Result:=False; end; function EncryptModule(SourceStr:String;Key:Word;N:Integer):String; var //加密函数 I:Integer; begin SetLength(Result,Length(SourceStr));//利用SetLength函数指定密文长度 //对每一个索引元素进行变换 for I:=1 to Length(SourceStr) do begin Result[I]:=Char(byte(SourceStr[I]) xor (Key Shr N)); Key:= (byte(Result[I]) + Key)*C1+C2; end; end; //==========以下是549的函数,据说没有暴破点,顺便试一试 //========函数作用:动态改变程序运行罗辑 function GetEIP: Integer;//自动生成address的方法 asm mov eax, [esp]; sub eax, 5; //call GetEIP占用5字节 end; function PatchOneItem(PatchItem: String): Boolean; var PatchAddress: Integer; PatchLength: DWord; PatchData: Pointer; PatchDataStr: String; i: Integer; PatchByte: Byte; PID, PHandle: THandle; WriteCount: DWord; begin Result := False; if Length(PatchItem) < 11 then Exit; PatchAddress := StrToInt(\'0x\' + LeftStr(PatchItem, 8)); for i := 1 to Length(PatchItem) do begin if PatchItem[i] \' \' then PatchDataStr := PatchDataStr + PatchItem[i]; end; PatchLength := (Length(PatchDataStr) - 9) div 2; GetMem(PatchData, PatchLength); try for i := 0 to PatchLength - 1 do begin PatchByte := StrToInt(\'0x\'+PatchDataStr[10 + i * 2] + PatchDataStr[10 + i * 2 + 1]); Byte(Pointer(Integer(PatchData) + i)^) := PatchByte; end; GetWindowThreadProcessId(Application.Handle, PID); PHandle := OpenProcess(PROCESS_ALL_ACCESS, False, PID); WriteProcessMemory(PHandle, Pointer(PatchAddress), PatchData, PatchLength, WriteCount); CloseHandle(PHandle); finally FreeMem(PatchData, PatchLength); end; Result := PatchLength = WriteCount; end; procedure Patch(PatchFile: String); var PatchItems: TStrings; PatchIndex: Integer; begin if not FileExists(PatchFile) then Exit; PatchItems := TStringList.Create; try PatchItems.LoadFromFile(PatchFile); for PatchIndex := 0 to PatchItems.Count - 1 do begin PatchOneItem(PatchItems[PatchIndex]); end; finally PatchItems.Free; end; end; procedure TForm1.FormCreate(Sender: TObject); begin Anti_DeDe; //检测DEDE,检测到关闭它。 if ABC42 then ExitProcess(0); //检测调试器,终止。 end; procedure TForm1.Button1Click(Sender: TObject); //注册按纽,开始检测 begin //========在这里插入一些花指令 asm jz @Start jnz @Start db 0E8h, 24h, 0, 0 ; db 0, 8Bh, 44h, 24h db 4, 8Bh, 0, 3Dh db 4, 0, 0, 80h db 75h, 8, 8Bh, 64h db 24h, 8, 0EBh, 4 db 58h, 0EBh, 0Ch, 0E9h db 64h, 8Fh, 5, 0 db 0, 0, 0, 74h db 0F3h, 75h, 0F1h, 0EBh db 24h, 64h, 0FFh, 35h db 0, 0, 0, 0 db 0EBh, 12h, 0FFh, 9Ch db 74h, 3, 75h, 1 db 0E9h, 81h, 0Ch, 24h db 0, 1, 0, 0 db 9Dh, 90h, 0EBh, 0F4h db 64h, 89h, 25h, 0 db 0, 0, 0, 0EBh db 0E6h db 0EBh, 1, 0Fh, 31h ; db 0F0h, 0EBh, 0Ch, 33h db 0C8h, 0EBh, 3, 0EBh db 9, 0Fh, 59h, 74h db 5, 75h, 0F8h, 51h db 0EBh, 0F1h db 0B9h, 4, 0, 0 ; @Start: end; if length(edit2.Text)>3 then //比较大于3位 begin //============再写一些骗Cracker if edit2.Text=EncryptModule(Edit1.Text,12345,10) then begin showmessage(\'请重启本软件。\'); //=======还可以再写一些记号,这里我就不写了 end; PatchOneItem(edit2.Text); //真正的比较 showmessage(\'ok\'); //弹出OK对话框 end; end; end.  //====附件为CM,会破解的兄弟可以试试其强度....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值