您有多脆弱? 软件安全速成

 软件安全性依然是热点话题。每个人,从老祖母到全球 500 强公司都听说过由互联网上的病毒和攻击者所引起的盗窃身份、丢失数据,及一般性的伤害的事。在 2008 年第一季度,所有报告的 1,474 个不同的软件脆弱点只有 64 个被解决。1分辨率大约为 4%。伴随所有关于软件和系统安全的议论,计算机世界似乎处于一片混乱中,这会让许多人不禁问道:“我有多脆弱?”

在本文中,我将介绍一些伍斯特工业学院(Worcester Polytechnic Institute,WPI)近期的安全项目的成果,以及额外的研究。我的目的是通过阐明公共术语并且提供一些典型的安全性使用的现实实例来说明什么是软件安全性。

本文不打算提供全面的计算机安全教育,而是介绍一些辽阔且扩展的信息安全领域中的关键主题。如果您想要进一步讨论,那么请通过 [email protected] 联系我。

背景

我早期对计算机安全的兴趣实际上激发了我对计算机科学的最初兴趣,并且从那时起就一直是我关注的焦点。所以不用说,我有一点失望的是 WPI 没有提供大学软件或系统安全课程。在没有任何正式的安全课程的情况下,我和其他两个计算机科学的学生决定进行独立研究,了解更多关于软件安全的知识。今年的早些日子,我们和 WPI 计算机科学的教授 Kathryn Fisler 谈论关于开始一个涉及软件安全的独立研究项目的事。我们计划开设一门首先在 08-09 学年度进行的安全软件工程的课程。众所周知,CS4400x 将成为 WPI 提供的第一门大学计算机科学安全课程。

在开设该课程的过程中,我们发现许多关于没有在标准课程中提到的软件脆弱性和预防的事实。我们发现大部分脆弱点通常由小的逻辑错误或软件开发人员没发现或解决的情况所引起。一些脆弱点不太复杂,因而很容易被黑客利用。可以通过一些简单的资源就能找到它们,像 Web 浏览器和文本编辑器。在软件开发团队出错的其他情况下,安全性的破坏可能由最终用户不恰当地配置或使用软件所致。

我们的结论是,最大的安全缺陷源于开发人员错误地假设安全问题将在系统的其他地方处理 —— 举例来说,他们假设可以相信输入的数据。经验教训:我们不得不认识到安全是每个人的职责,不是其他人的。





脆弱性 101

脆弱性是什么?“利用”、“攻击”、“脆弱点”,和其它术语一般用于描述什么适当的软件安全目的在于纠正:系统中允许黑客特权访问信息或破坏系统的缺陷。Mitre Corporation 将脆弱性定义为“系统或网络中允许黑客以另一个用户的身份执行命令,访问他们不应该访问的数据,冒充某人,及/或执行拒绝服务的状态”。2根据此定义,脆弱就意味着处于一种状态,在这种状态下,黑客(人或恶意程序,像病毒或间谍软件)可以访问到比他们应该可以访问的要多的系统的部分。

脆弱点出现的范围很广,从明显的 —— 像使用不健壮的密码或存储无保护的私有数据 —— 到更有细微差异的 —— 像未检查的输入。

溢出攻击

最早遭受破坏的,且仍旧普遍的攻击来源于开发人员对最终用户输入的数据可以信任的假设。大部分程序设计人员未预料在用户名框中得到 40,000 行文本,或者从密码框中获得甚至非键盘输入的模糊字符,因此,所输入的数据从不会被验证无误。这种假设增加了溢出攻击。举例来说,使用本文编辑器并了解一些 Microsoft PowerPoint 文件格式的知识,3人们就可以手工编写 PowerPoint 文件。编辑 PowerPoint 文件4,让内部字段中拥有比格式允许的更多的数据会导致 Microsoft PowerPoint XP 崩溃,然后执行任何黑客想要执行的程序。在一个这种脆弱性的熟悉的实例中,内嵌的 Windows 计算器程序被执行,然而,被执行的程序很容易是更恶意的。这只是无数的这类利用中的一个实例。

实质上,溢出类攻击是由于将太多的数据放入原始程序设计人员认为足够的空间中导致的。额外的数据溢出到预期存储区附近的内存中,并且覆盖与该区域的原始用途无关的数据。当执行余下的程序时,它使用新被覆盖的数据。如果黑客能够用伪数据(也就是,NOP)填充足够的空间,然后添加一点恶意代码或值,那么程序将执行恶意代码或使用新值。这可能导致许多不同的后果。黑客可能能够越过登录5,获得程序的管理员特权。如果受攻击的程序是由系统管理员启动的,那么恶意代码将作为原始程序的一部分进行执行,给黑客系统中的管理员特权。溢出脆弱点,尽管不总是出现,但在一些情况下,可能很容易被补救,当开发应用程序时利用“安全”库6,使用堆栈保护7(也就是,StackGuard8)或对输入数据进行检查,从而确保其是适当的大小或类型。这一类的利用总是以类似的方式进行,但会根据受影响的内存类型和预期效果而不同。

缓冲区溢出攻击

在缓冲区溢出攻击的实例中,程序的内部值溢出,从而改变程序的运行方式。9在程序的正常操作过程中,当调用一个函数时,被调用函数的所有参数以及返回位置的指针都放在栈中。当完成该函数之后,使用返回指针回到原来的位置并继续程序。利用缓冲区溢出进行攻击可以改变这个过程,并且允许黑客执行任何他们期望的函数。 这是通过输入足够的数据来用伪数据覆盖参数,及输入到不同函数的新返回指针来实现的,现在就执行新的函数了。10

SQL 注入

除了溢出的利用以外,SQL 注入是另一类依赖于开发人员没测试输入数据的疏漏的攻击。大多数人拥有字母数字式密码,或者有安全意识的人,拥有附带其他键盘符号的字母数字式密码。由于这种想法,开发人员可能允许输入任何字符作为密码。这通常是没问题的,除非他们忘记清洁或检查输入数据。这种情况比应该的要发生的频繁得多。使用 SQL 数据库的密码系统(在许多网站上非常普遍的场景)可能运行这样的查询:

SELECT * FROM users WHERE 'username' = '$USER' AND 'password'='$PASS';

$USER 和 $PASS 会用用户提供的用户名和密码来代替。那么如果用户输入‘bob’和‘1234’,那么结果的查询是:

SELECT * FROM users WHERE 'username' = 'bob' AND 'password' = '1234';

,而来自数据库的返回值会是所有用 bob 作为用户名且用 1234 作为密码的数据元组。如果黑客输入 admin 和 <<'hi' 或 1=1>>--,那么查询是:

SELECT * FROM users WHERE 'username' = 'admin' and `password` = 'hi' OR 1=1--'

注意用户输入的引号如何与原始查询中的第三个引号匹配。数据库现在会返回用户名为 admin 的所有元组,并且会取消对密码的检查,因为 'password' = 'hi' OR 1=1 命令数据库寻找密码是 hi 的元组或 1=1 的元组,而由于 1 总是 1,所以每行都是候选。-- 是 SQL 注释标志,取消查询中原始的其他引号,并且还将取消任何额外的检查,因此如果有额外的凭证(也就是,keyfob11或 captcha12)也会被忽略。现在黑客可以以管理员的身份进入系统并且不用不得不给出合法的密码。通过利用越来越复杂的查询,黑客可以变更、添加,或查询数据。13对于数据库,这令黑客具有同应用程序相同的特权。

这种类型的脆弱点被证实是对 Web 应用程序最有效的攻击类型之一,并且随着对 Web 应用程序的信任的增加,这种利用的力量甚至将更令人畏缩。幸运的消息是,像溢出类型的攻击一样,可以通过清洁输入数据,并且从不立即相信用户输入(至少对于输入的数据)来防止大部分这种脆弱点。





散列攻击

任何处理在数据库中存储用户凭证的人都会告诉您,首要的规则之一是从不直接存储没有首先加密的密码或其它私有数据。如果数据库暴露了,那么使用加密方案将防止暴露用户的密码。为了更多的利益,利用单向加密算法或散列,像 MD514或 Blowfish,15将使密码的解密成为不可能。这是因为散列可以将输入值转化为新的值,而这些新值不能从数学上逆向生成原始值。传统上,攻击以这种方式存储的密码的方式涉及用尽可能多的不同的密码进行尝试直到最终有效,这被称之为“蛮干”技术。虽然这种类型的攻击十分简单,但通常是无效的,因为需要绝对的时间来尝试足够的组合,有时候要上千年,统计上是成功的,一般是理论的。

每天您可能都在使用散列攻击工具,而甚至不知道它。Google 真的非常擅长它所做的:在信息之间找到链接。举例来说,Googling “Bob Breznak”将取出所有关于我的信息:我为The Rational Edge 写的最近的书评,我的个人站点(及废弃的)等等。现在,如果您从这里借鉴一下,那么您将得到快速返回结果的许多想法。应用该想法来寻找散列。举例来说,利用“foobar”的 MD5 散列:3858f62230ac3c915f300c664312c63f。现在将其输入 Google,瞧!0.21 秒内,第一个结果是“Google Hash: md5(foobar) = 3858f62230ac3c915f300c664312c63f”。您将找到的大部分结果都是哈希索引站点 —— 有意地连接散列值和其相应关键字的站点。尝试更复杂的字符串(举例来说,“bobby”、“crayon”、“rational”)将生成混合的结果。如果您尝试复杂的密码(或者最好是传递阶段),您可能没有收获。

这可能不是您需要担心的最大安全漏洞,但令其危险的是,这种利用不太知名,并且没有简单的补救办法。随着越来越复杂的关键字被匹配到散列上,匹配到已知密码上的可能性增加了。变更为更复杂的算法,比方说从 MD5 变更为 SHA-2,16对恢复秘密的完整性没什么作用。这是因为尽管从不同的散列中获得同一个字符串的返回值,但是将关键字链接到散列上也只是时间的问题。虽然加密法总是将利用时间来蛮干作为安全网,搜索减少所需的时间,从而成功地从几千年到几年,甚至几个月。

现在,存在着两种主要的争论,它们将散列查找从年度最大的安全缺陷的竞争列表中去掉了。这种类型的攻击只可能在数据库或密码存储已经暴露的情况下进行。需要读取数据库、影子文件(UNIX 或 LINUX 系统保存用户密码的地方),或 I/O 流。在某些情况下,这可能和达到正确的 URL 或执行 SQL 注入一样简单,而在其他情况下,它可能需要比黑客多得多的工作。减小这种攻击的潜在严重性的另一个争论实际上源于散列的使用。由于许多字符串可以生成相同的散列,所以不能必然地确定原始的字符串(用户的真实密码)。然而,找到任何散列到相同值得字符串能够再次生成相同的散列值。这意味着尽管黑客可能没有获得实际的密码,但是由于系统使用存储的散列,而黑客拥有能生成同等散列的字符串,所以系统会像黑客拥有原始密码那样响应。





最终用户问题

即使有了最彻底地测试过的且安全的软件,一旦打包并交给最终用户,全部的赌都输了。软件如何配置和实现,像其他步骤那样扮演者关键的安全性角色。

默认值的谬论

用户犯的最大错误之一是当所使用的软件没有默认值时。许多软件为各种选项定义默认值,以便用户可以尽可能快地运行。虽然有时候这可能非常有益,像 Web 服务器默认为标准的 Web 服务器通信端口,这也会导致许多安全问题。举例来说,许多路由器和其它网络设备都有默认的登录用户名和密码。当用户不将这些默认值改为独特的值时就会出现问题。搜索“默认的路由器密码”将得到许多列出市场上大部分路由器的默认用户名和密码的站点。如果黑客打算进入网络,那么还未接触的用户名、密码、IP 地址,和其它默认值都是现成的钥匙。

不可靠的系统

当最终用户不确定他们添加的软件如何符合系统的其他部分,并且需要采取什么额外的安全量度时,会产生另一个问题。再次拿 Web 搜索举例。搜索“view/index.shtml axis”将返回未保护的网络摄像机的列表。在一些情况下,最终用户成功地设置了他们想让全世界都可见的网络摄像机。在其他情况下,网络摄像机被添加到某个网络,并且没有配置为不公开。这种未保护的摄像机可以被互联网上的每个人见到,并且可能快速地成为侵犯隐私罪。一些书籍和网站致力于提供返回所有者没犹豫过安全性并且现在公开了的数据搜索查询。17

我们从这些新的搜索中得到一些经验。第一,默认值到处都是,因此当不修改默认值时,考虑如果黑客知道此信息会有多有害。第二,您应该了解如何访问系统的各个部分并且考虑这种访问级别是否合适。第三,记住通过模糊的安全没有用。不论多么不重要或未公开的信息公开了,如果有人感兴趣,不管通过自动的搜索或一些人力,都可以找到该数据。18





结束语

随着越来越多的脆弱点日益被发现,这些威胁只是沧海一粟 。如同这些实例一样,大部分脆弱点源于疏忽:忽略了实现安全实践的开发人员,或者忽略改变配置的最终用户。即使我提供的实例可能肤浅,并且似乎十分容易避免,但随着项目的增长,对于简单的未检查的情况就有机会了。黑客可能只需要小小的机会就对系统进行攻击并且引起永久性的损害。开发人员应该充分了解他们假设的影响,并且越过正常使用之外进行测试。通过充分地了解系统的工作方式,并且假定为对于产品的黑客角色,开发人员应该定期审查他们的工作,并且在必要时发布补丁。

个人可能说不出软件有多大缺陷,并且虽然没有那么完全的安全系统,但是人们可以通过利用多层次的安全性将脆弱性最小化。健壮的密码,让软件保持更新及适当地修补,并且当添加了每个软件困扰时了解它的影响,是最终用户添加保护层的小方法。最后,与软件相关的每个人都有责任关注安全性,并试图减少脆弱点。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章