软件安全性的10原则和相互作用Word文档格式.docx
《软件安全性的10原则和相互作用Word文档格式.docx》由会员分享,可在线阅读,更多相关《软件安全性的10原则和相互作用Word文档格式.docx(9页珍藏版)》请在冰豆网上搜索。
一旦一些其它组件很明显是更大的风险时,您就应该将精力集中到别的地方。
当然,可以永远使用这一策略,因为安全性从来就不是一个保证。
您需要某些停止点。
根据您在软件工程过程中定义的任何量度,在所有组件都似乎在可接受的风险阈值以内时,您应该停下来。
原则2:
纵深防御
纵深防御背后的思想是:
使用多重防御策略来管理风险,以便在一层防御不够时,在理想情况下,另一层防御将会阻止完全的破坏。
即便是在安全性社区以外,这一原则也是众所周知的;
例如,这是编程语言设计的着名原则:
纵深防御:
采取一系列防御,以便在一层防御不能抓住错误时,另一层防御将可能抓住它。
让我们回到为银行提供安全性的示例。
为什么典型的银行比典型的便利店更安全?
因为有许多冗余的安全性措施保护银行―措施越多,它就越安全。
单单安全摄像机通常就足以成为一种威慑。
但如果攻击者并不在乎这些摄像机,那么安全保卫就将在那儿实际保护银行。
两名安全保卫甚至将提供更多的保护。
但如果两名保卫都被蒙面匪徒枪杀,那么至少还有一层防弹玻璃以及电子门锁来保护银行出纳员。
如果强盗碰巧砸开了这些门或者猜出了PIN,起码强盗将只能容易抢劫现金出纳机,因为我们有保险库来保护余下部分。
理想情况下,保险库由几个锁保护,没有两个很少同时在银行的人在场是不能被打开的。
至于现金出纳机,可以为其装备使钞票留下印记的喷色装置。
当然,配备所有这些安全性措施并不能确保银行永远不会遭到成功的抢劫。
即便在具备这么多安全性的银行,也确实会发生银行抢劫。
然而,很清楚,所有这些防御措施加起来会形成一个比任何单一防御措施有效得多的安全性系统。
这好象同先前的原则有些矛盾,因为我们实质上是在说:
多重防御比最坚固的环节还要坚固。
然而,这并不矛盾;
“保护最薄弱环节”的原则适用于组件具有不重叠的安全性功能的时候。
但当涉及到冗余的安全性措施时,所提供的整体保护比任意单个组件提供的保护要强得多,确实是可能的。
一个好的现实示例是保护在企业系统不同服务器组件间传递的数据,其中纵深防御会非常有用,但却很少应用。
大部分公司建立企业级的防火墙来阻止入侵者侵入。
然后这些公司假定防火墙已经足够,并且让其应用程序服务器不受阻碍地同数据库“交谈”。
如果数据非常重要,那么如果攻击者设法穿透了防火墙会发生什么呢?
如果对数据也进行了加密,那么攻击者在不破解加密,或者(更可能是)侵入存储未加密形式的数据的服务器之一的情况下,将不能获取数据。
如果我们正好在应用程序周围建立另一道防火墙,我们就能够保护我们免遭穿透了企业防火墙的人攻击。
那么他们就不得不在应用程序网络显式输出的一些服务中寻找缺陷;
我们要紧紧掌握那些信息。
原则3:
保护故障
任何十分复杂的系统都会有故障方式。
这是很难避免的。
可以避免的是同故障有关的安全性问题。
问题是:
许多系统以各种形式出现故障时,它们都归结为不安全行为。
在这样的系统中,攻击者只需造成恰当类型的故障,或者等待恰当类型的故障发生。
我们听说过的最好的现实示例是将现实世界同电子世界连接起来的示例―信用卡认证。
诸如Visa和MasterCard这样的大型信用卡公司在认证技术上花费巨资以防止信用卡欺诈。
最明显地,无论您什么时候去商店购物,供应商都会在连接到信用卡公司的设备上刷您的卡。
信用卡公司检查以确定该卡是否属被盗。
更令人惊讶的是,信用卡公司在您最近购物的环境下分析您的购物请求,并将该模式同您消费习惯的总体趋势进行比较。
如果其引擎察觉到任何十分值得怀疑的情况,它就会拒绝这笔交易。
从安全性观点来看,这一方案给人的印象十分深刻―直到您注意到某些事情出错时所发生的情况。
如果信用卡的磁条被去磁会怎样呢?
供应商会不得不说:
“抱歉,因为磁条破了,您的卡无效。
”吗?
不。
信用卡公司还向供应商提供了创建您卡的标记的手工机器,供应商可以将其送给信用卡公司以便结帐。
如果您有一张偷来的卡,那么可能根本不会进行认证。
店主甚至可能不会向您要您的ID。
在手工系统中一直有某些安全性所示,但现在没了。
在计算机网络出现以前,可能会要您的ID以确保该卡同您的驾驶证相匹配。
另外需要注意的是,如果您的号码出现在当地定期更新的坏卡列表之内,那么该卡将被没收。
而且供应商还将可能核查您的签名。
电子系统一投入使用,这些技术实际上就再也不是必需的了。
如果电子系统出现故障,那么在极少见的情况下,会重新使用这些技术。
然而,实际不会使用这些技术。
信用卡公司觉得:
故障是信用卡系统中十分少见的情形,以致于不要求供应商在发生故障时记住复杂的过程。
系统出现故障时,系统的行为没有通常的行为安全。
遗憾的是,系统故障很容易引起。
例如,很容易通过将偷来的信用卡在一块大的磁铁上扫一下来毁坏其磁条。
这么做,只要小偷将卡用于小额购买(大额购买经常要求更好的验证),他们就或多或少地生出了任意数目的金钱。
从小偷的角度看,这一方案的优点是:
故障很少会导致他们被抓获。
有人可以长期用这种方法使用同一张卡,几乎没有什么风险。
为什么信用卡公司使用这种愚蠢落后的方案呢?
答案是:
这些公司善于风险管理。
只要他们能够不停地大把赚钱,他们就可以承受相当大数量的欺诈。
他们也知道阻止这种欺诈的成本是不值得的,因为实际发生的欺诈的数目相对较低。
(包括成本和公关问题在内的许多因素影响这一决定。
)
大量的其它例子出现在数字世界。
经常因为需要支持不安全的旧版软件而出现问题。
例如,比方说,您软件的原始版本十分“天真”,完全没有使用加密。
现在您想修正这一问题,但您已建立了广大的用户基础。
此外,您已部署了许多或许在长时间内都不会升级的服务器。
更新更聪明的客户机和服务器需要同未使用新协议更新的较旧的客户机进行互操作。
您希望强迫老用户升级,但您尚未为此做准备。
没有指望老用户会占用户基础中如此大的一部分,以致于无论如何这将真的很麻烦。
怎么办呢?
让客户机和服务器检查它从对方收到的第一条消息,然后从中确定发生了什么事情。
如果我们在同一段旧的软件“交谈”,那么我们就不执行加密。
遗憾的是,老谋深算的黑客可以在数据经过网络时,通过篡改数据来迫使两台新客户机都认为对方是旧客户机。
更糟的是,在有了支持完全(双向)向后兼容性的同时仍无法消除该问题。
对这一问题的一种较好解决方案是从开始就采用强制升级方案进行设计;
使客户机检测到服务器不再支持它。
如果客户机可以安全地检索到补丁,它就升级。
否则,它告诉用户他们必须手工获得一个新的副本。
很遗憾,重要的是从一开始就应准备使用这一解决方案,除非您不在乎得罪您的早期用户。
远程方法调用(RemoteMethodinvocation(RMI))的大多数实现都有类似的问题。
当客户机和服务器想通过RMI通信,但服务器想使用SSL或一些其它加密协议时,客户机可能不支持服务器想用的协议。
若是这样,客户机通常会在运行时从服务器下载适当的套接字实现。
这形成了一个大的安全漏洞,因为下载加密接口时,还没有对服务器进行认证。
攻击者可以假装成服务器,在每台客户机上安装他自己的套接字实现,即使是在客户机已经安装了正确的SSL类的情况下。
如果客户机未能建立与缺省库的安全连接(故障),它将使用一个不可信实体给它的任何协议建立连接,因此也就扩展了信任范围。
原则4:
最小特权
最小特权原则规定:
只授予执行操作所必需的最少访问权,并且对于该访问权只准许使用所需的最少时间。
当您给出了对系统某些部分的访问权时,一般会出现滥用与那个访问权相关的特权的风险。
例如,我们假设您出去度假并把您家的钥匙给了您的朋友,好让他来喂养您的宠物、收集邮件等等。
尽管您可能信任那位朋友,但总是存在这样的可能:
您的朋友未经您同意就在您的房子里开派对或发生其它您不喜欢的事情。
不管您是否信任您的朋友,一般不必冒险给予其必要的访问权以外的权利。
例如,如果您没养宠物,只需要一位朋友偶尔收取您的邮件,那么您应当只给他邮箱钥匙。
即使您的朋友可能找到滥用那个特权的好方法,但至少您不必担心出现其它滥用的可能性。
如果您不必要地给出了房门钥匙,那么所有一切都可能发生。
同样,如果您在度假时确实雇佣了一位房子看管人,那么您不可能在没有度假时还让他保留您的钥匙。
如果您这样做了,那么您使自己陷入额外的风险之中。
只要当您的房门钥匙不受您的控制,就存在钥匙被复制的风险。
如果有一把钥匙不受您的控制,而且您不在家,那么就存在有人使用钥匙进入您房子的风险。
当有人拿了您的钥匙,而您又没有留意他们,那么任何这样的一段时间都会构成一个时间漏洞,在此段时间内您就很容易受到攻击。
为了将您的风险降到最低,您要使这段易受攻击的时间漏洞尽可能的短。
现实生活中的另一个好的示例是美国政府的忠诚调查系统―“需要知道”政策。
即使您有权查看任何机密文档,您仍不能看到您知道其存在的任何机密文档。
如果可以的话,就很容易滥用该忠诚调查级别。
实际上,人们只被允许访问与那些交给他们的任务相关的文档。
UNIX系统中出现过一些违反最小特权原则的最著名情况。
例如,在UNIX系统上,您一般需要root特权才能在小于1024的端口号上运行服务。
所以,要在端口25(传统的SMTP端口)上运行邮件服务器,程序需要root用户的特权。
不过,一旦程序在端口25上运行了,就没有强制性要求再对它使用root特权了。
具有安全性意识的程序会放弃root特权并让操作系统知道它不应再需要那些特权(至少在程序下一次运行之前)。
某些电子邮件服务器中存在的一个大问题是它们在获取邮件端口之后没有放弃它们的root权限(Sendmail是个经典示例)。
因此,如果有人找到某种方法来欺骗这样一个邮件服务器去完成某些恶意任务时,它会成功。
例如,如果一位怀有恶意的攻击者要在Sendmail中找到合适的栈溢出,则那个溢出可以用来欺骗程序去运行任意代码。
因为Sendmail在root权限之下运行,所以攻击者进行的任何有效尝试都会成功。
另一种常见情况是:
一位程序员可能希望访问某种数据对象,但只需要从该对象上进行读。
不过,不管出于什么原因,通常该程序员实际需要的不仅是必需的特权。
通常,该程序员是在试图使编程更容易一些。
例如,他可能在想,“有一天,我可能需要写这个对象,而我又讨厌回过头来更改这个请求。
”
不安全的缺省值在这里可能还会导致破坏。
例如,在WindowsAPI中有几个用于访问对象的调用,如果您将“0”作为参数传递,那么这些调用授予所有的访问。
为了更有限制地进行访问,您需要传递一串标志(进行“OR”操作)。
只要缺省值有效,许多程序员就会坚持只使用它,因为那样做最简单。
对于受限环境中运行的产品的安全性政策,这个问题开始成为其中的常见问题。
例如,有些供应商提供作为Javaapplet运行的应用程序。
applet构成移动代码,Web浏览器会对此代码存有戒心。
这样的代码运行在沙箱中,applet的行为根据用户同意的安全性政策受到限制。
在这里供应商几乎不会实践最小特权原则,因为他们那方面要花太多的精力。
要实现大体意思为“让供应商的代码完成所有的任务”的策略相对要容易得多。
人们通常采用供应商提供的安全性策略,可能是因为他们信任供应商,或者可能因为要确定什么样的安全性策略能最佳地使必须给予供应商应用程序的特权最小化,实在是一场大争论。
原则5:
分隔
如果您的访问权结构不是“完全访问或根本不准访问”,那么最小特权原则会非常有效。
让我们假设您在度假,而你需要一位宠物看管人。
您希望看管人只能进出您的车库(您不在时将宠物留在那里)但是如果您的车库没有一把单独的锁,那么您别无选择而只能让看管人进出整幢房子。
分隔背后的基本思想是如果我们将系统分成尽可能多的独立单元,那么我们可以将对系统可能造成损害的量降到最低。
当将潜水艇构造成拥有许多不同的船舱,每个船舱都是独立密封,就应用了同样原则;
如果船体裂开了一个口子而导致一个船舱中充满了水,其它船舱不受影响。
船只的其余部分可以保持其完整性,人们就可以逃往潜水艇未进水的部分而幸免于难。
分隔原则的另一个常见示例是监狱,那里大批罪犯集中在一起的能力降到了最低。
囚犯们不是居住在营房中,而是在单人或双人牢房里。
即使他们聚集在一起―假定,在食堂里,也可以加强其它安全性措施来协助控制人员大量增加带来的风险。
在计算机世界里,要举出糟糕分隔的示例比找出合理分隔容易得多。
怎样才能不分隔的经典示例是标准UNIX特权模型,其中安全性是关键的操作是以“完全访问或根本不准访问”为基础的。
如果您拥有root特权,那么您基本上可以执行您想要的任何操作。
如果您没有root访问权,那么就会受到限制。
例如,您在没有root访问权时不能绑定到1024以下的端口。
同样,您不能直接访问许多操作系统资源―例如,您必须通过一个设备驱动程序写磁盘;
您不能直接处理它。
通常,如果攻击者利用了您代码中的缓冲区溢出,那人就可以对磁盘进行原始写并胡乱修改内核所在内存中的任何数据。
没有保护机制能阻止他这样做。
因此,您不能直接支持您本地磁盘上永远不能被擦去的日志文件,这意味着直到攻击者闯入时,您才不能保持精确的审计信息。
不管驱动程序对底层设备的访问协调得多么好,攻击者总能够避开您安装的任何驱动程序。
在大多数平台上,您不能只保护操作系统的一部分而不管其它部分。
如果一部分不安全,那么整个系统都不安全。
有几个操作系统(诸如TrustedSolaris)确实做了分隔。
在这样的情况中,操作系统功能被分解成一组角色。
角色映射到系统中需要提供特殊功能的实体上。
一个角色可能是LogWriter角色,它会映射到需要保存安全日志的任何客户机上。
这个角色与一组特权相关联。
例如,LogWriter拥有附加到它自己的日志文件的权限,但决不可以从任何日志文件上进行擦除。
可能只有一个特殊的实用程序获得对LogManager角色的访问,它就拥有对所有日志的完全访问权。
标准程序没有对这个角色的访问权。
即使您破解了一个程序并在操作系统终止这个程序,您也不能胡乱修改日志文件,除非您碰巧还破解了日志管理程序。
这种“可信的”操作系统并不是非常普遍,很大一部分是因为这种功能实现起来很困难。
象在操作系统内部处理内存保护这样的问题给我们提出了挑战,这些挑战是有解决方案的,但得出解决的结果并不容易。
分隔的使用必须适度,许多其它原则也是如此。
如果您对每一个功能都进行分隔,那么您的系统将很难管理。
原则6:
简单性
在许多领域,您可能听到KISS咒语——“简单些,蠢货!
”与其它场合一样,这同样适用于安全性。
复杂性增加了问题的风险;
这似乎在任何系统中都不可避免。
很明显,您的设计和实现应该尽可能地简单。
复杂的设计不容易理解,因此更有可能产生将被忽略的拖延问题。
复杂的代码往往是难以分析和维护的。
它还往往有更多错误。
我们认为任何人都不会对此大惊小怪。
类似地,只要您所考虑的组件是质量良好的,就应该考虑尽可能重用组件。
特定组件被成功使用的次数越多,您就更应该避免重写它。
对于密码库,这种考虑尤其适用。
当存在几个广泛使用的库时,您为什么想重新实现AES或SHA-1呢?
那些库可能比您在房间里装配起来的东西更为健壮。
经验构筑了保证,特别当那些经验是成功的经验时。
当然,即使在广泛使用的组件中,也总是有出现问题的可能性。
然而,假设在已知数量中涉及的风险较少是合理的。
原则7:
提升隐私
用户通常认为隐私是安全性问题。
您不应该做任何可能泄露用户隐私的事情。
并且在保护用户给您的任何个人信息方面,您应该尽可能地认真。
您可能听说过恶意的黑客能够从Web访问整个客户数据库。
还经常听说攻击者能够截获其它用户的购物会话,并因此获得对私有信息的访问。
您应该竭尽所能避免陷入这种窘境;
如果客户认为您不善处理隐私问题,则您可能很快失去他们的尊重。
原则8:
难以隐藏秘密
安全性通常是有关保守秘密的。
用户不想让其个人数据泄漏出去,所以您必需加密密钥以避免窃听或篡改。
您还要保护您的绝秘算法免遭竞争者破坏。
这些类型的需求很重要,但是与一般用户猜疑相比较,很难满足这些需求。
很多人以为用二进制表示的秘密也许能保守秘密,因为要抽取它们太困难了。
的确,二进制是复杂的,但要对“秘密”保密实在是太困难了。
一个问题就是某些人实际上相当擅长对二进制进行逆向工程―即,将它们拆开,并断定它们是做什么的。
这就是软件复制保护方案越来越不适用的原因。
熟练的黑客通常可以避开公司尝试硬编码到其软件中的任何保护,然后发行“破译的”副本。
很长时间以来,使用的技术越来越多;
供应商为阻止人们发现“解锁”软件的秘密所投入的精力越多,软件破解者在破解软件上花的力气也越多。
在极大程度上,都是破解者达到目的。
人们已经知道有趣的软件会在正式发布之日被破解―有时候会更早。
如果软件都在您自己网络的服务器端运行,您可能会判定您的秘密是安全的。
实际上,它比隐藏秘密难得多。
如果您可以避免它,就不应该信任您自己的网络。
如果一些不曾预料到的缺点允许入侵者窃取您的软件将会怎么样呢?
这是就在他们发行第一版Quake之前发生在Id软件上的事情。
即使您的网络很安全,但您的问题可能是在内部。
一些研究表明对公司最常见的威胁就是“内部人员”攻击,其中,心怀不满的雇员滥用访问权。
有时候雇员并不是不满;
或许他只是把工作带到家里做,朋友在那里窃听到他不应该知道的东西。
除此之外,许多公司无法防止心怀恶意的看门人窃取其仔细看守的软件。
如果有人想要通过非法手段获取您的软件,他们或许会成功。
当我们向人们指出内部攻击的可能性时,他们常常回答:
“这不会发生在我们身上;
我们相信我们的员工。
”如果您的想法也是这样,那么您应该谨慎一点。
与我们对话的90%的人说的都一样,然而大多数攻击都是内部人员干的。
这里有一个极大的差距;
大多数认为可以相信其员工的那些人肯定是错的。
请记住,员工可能喜欢您的环境,但归根结底,大多数员工与您的公司都有一种业务关系,而不是个人关系。
这里的寓意就是多想想也是值得的。
有时,人们甚至不需要对软件进行逆向工程,就可以破译它的秘密。
只要观察正在运行的软件,就常常可以发现这些秘密。
例如,我们(JohnViega和TimHollebeek)曾经仅仅通过用一系列选择的输入来观察其行为,就破解了Netscape电子邮件客户机中的一个简单密码算法。
(这太容易做到了,所以我们说:
“我们不用铅笔和纸来做这件事。
我们的许多笔记都用钢笔写。
我们不需要擦除更多东西。
”)最近,ETrade遭受了类似下场,当您在Web上登录时,任何人都可以看到您的用户名和密码。
相信二进制(就此而言,或者是任何其它形式的模糊)为您保守秘密的实践被亲切地称作“含糊的安全性(securitybyobscurity)”。
只要有可能,您都应该避免将它用作您唯一的防御线。
这并不意味着含糊的安全性没有用武之地。
明确地拒绝对源代码的访问会稍微对攻击者产生一些障碍。
模糊代码以产生一个模糊的二进制甚至会有更大帮助。
这些技术要求潜在的攻击者拥有比在他们需要实际破坏您系统时更多的技巧,这通常是一件好事。
相反,大多数以这种方法保护的系统无法执行一次足够的安全性审查;
有一些事情是公开的,它允许您从用户那里获得免费的安全性忠告。
原则9:
不要轻易扩展信任
如果人们知道不能相信最终用户所控制的客户机,那么他们可能常常会意识到他们的秘密正处于危险中,因为不能相信最终用户会按照他们期望的那样使用客户机。
我们还强烈要求您勉强相信您自己的服务器,以防止数据窃取,这种犹豫应该渗透到安全性过程的各个方面。
例如,虽然现成的软件的确可以帮助您简化您的设计和实现,但您怎么知道相信现成组件是安全的呢?
您真的认为开发人员就是安全性方面的专家吗?
即使他们是,您期望他们确实可靠吗?
许多有安全性漏洞的产品都来自安全性供应商。
许多从事安全性业务的人实际上并不太了解有关编写安全代码方面的知识。
通常很容易扩展信任的另一个地方是客户支持。
毫无戒心的客户支持代理(他们有相信的倾向)非常容易遭到社会工程攻击,因为它会使他们的工作变得更加容易。
您还应该注意一下“随大流”。
仅仅因为一个特殊的安全性功能是标准的并不意味着您应该提供同样低级的保护。
例如,我们曾经常听到人们选择不加密敏感数据,仅仅是因为他们的竞争对手没有对数据进行加密。
当客户遭到攻击,于是责备某人疏忽安全性时,这就不是充足的理由。
您也不应该相信安全性供应商。
为了出售他们的产品,他们常常散布可疑的或完全错误的信息。
通常,这种“蛇油”传播者通过散布FUD——害怕、不确定和怀疑进行工作。
许多常见的警告标记可以帮助您发觉骗子。
其中我们最喜欢的一个就是用于秘钥加密算法的“百万位密钥”广告。
数学告诉我们,对于整个宇宙生命周期,256位很可能足以保护消息―假设该算法是高质量的。
做了较多广告的人对密码术知道得太少而无法出售安全性产品。
在完成购物之前,请一定要进行研究。
最好从“SnakeOil”FAQ开始。
您还应该勉强相信您自己和您的组织。
当涉及您自己的主意和您自己的代码时很容易目光短浅。
尽管您可能喜欢完美,但您应该容许不完美,并且对正在做的事情定期获取高质量的、客观的外部观点。
要记住的最后一点是信任是可转移的。
一旦您信任某个实体,就会暗中将它扩展给该实体可能信任的任何人。
出于这个原因,可信的程序决不应该调用不可信的程序。
当确定要信任哪些程