| 软件安全速成课 你的系统有多脆弱? |
|
软件安全仍然是一个热门话题。无论是普通百姓,还是《财富》500强公司,谁都听说过由互联网上的病毒和攻击者引起的身份窃取、数据丢失以及一般性的混乱。单单2008年第一季度,就有1474个不同的软件脆弱点报告上来,只有64个发布了相应的解决方案。也就是说解决率大约只有4%。由于软件和系统安全方面议论纷纷,计算机业界似乎完全处于一片混乱之中,这让许多人问道:“我的系统有多脆弱?” 本文介绍了伍斯特理工学院近期开展的一个安全项目取得的部分成果,还介绍了其他研究。目的在于,通过阐明常见的安全术语,并且提供典型安全漏洞的一些实际例子,表明什么是软件安全。 本文并不想提供全面的计算机安全教育,而是旨在介绍信息安全这个广阔、并且在不断扩展的领域当中的一些关键话题。 标准课程不会提到软件脆弱点 我们在开设这门课程的过程中,发现了有关软件脆弱点和预防的几个事实,而标准的课程根本不会提到这些事实。我们发现,大部分脆弱点通常是由很小的逻辑错误或者软件开发人员没有发现或没有解决的某种情况引起的。有些脆弱点不是太复杂,因而很容易被黑客利用。只要使用一些简单的资源,比如Web浏览器和文本编辑器,就能找出这些脆弱点。在软件开发团队没有犯错的其他情况下,安全漏洞可能由最终用户对软件配置或者使用不当引起。 我们得出了这个结论:最大的安全缺陷来自于开发人员错误地以为安全问题会在系统其他地方得到处理――比方说,他们想当然地以为输入数据值得信任。经验教训是,我们一定要认识到确保安全是每个人的职责,而不是别人的职责。 什么是脆弱点?“可被人利用的漏洞”、“攻击”和“脆弱点”及其他术语通常用于描述合适的软件安全旨在纠正的对象:系统当中让黑客得以获取权限、从而访问信息或者破坏系统的缺陷。Mitre公司对脆弱点的定义是“系统或者网络中的一种状态,这种状态让黑客得以以另一个用户的身份执行命令、访问不该访问的数据、冒充别人,以及/或者发动拒绝服务攻击。”根据这个定义,脆弱性就意味着处于这种状态:攻击者(无论是人,还是像病毒或者间谍软件这些恶意程序)可以访问某个系统中超出其访问权限范围的部分。 导致出现脆弱点的途径很广,有的很明显,比如使用脆弱的密码或者存储未加保护的私人数据;有的则比较隐密,比如未加检查的输入。 溢出攻击 实质上,溢出类攻击中出现的是,放入了太多的数据,结果原始程序设计员以为绰绰有余的空间装不下这么多数据。多出来的数据就溢出到了预期存储区附近的内存中,并且覆盖了与该存储区的原始用途没有关系的数据。程序的其余部分执行时,它就使用刚被覆盖的数据。如果攻击者能够用伪数据(dummy data)填充足够大的空间(即空操作),然后添加一段恶意代码或者一个值,程序就会执行恶意代码或者使用这个新值。这可能会导致许多不同的后果。攻击者也许能够越过登录这一道机制,获得程序的管理员权限。如果受攻击的程序由系统管理员来启动,那么恶意代码随后将作为原始程序的一部分来运行,为攻击者提供了这个系统的管理员权限。溢出漏洞尽管并非总是很明显,但在一些情况下,很容易得到补救:只要在开发应用程序时,使用“安全”库、使用堆栈保护(即StackGuard),或者对输入数据进行检查,确保数据大小和类型正确。这个漏洞系列的工作方式都很相似,不过受影响内存的类型和预期效果会有所不同。 缓冲区溢出攻击 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--’ 事实证明,这种脆弱点是针对Web 应用程序最有效的攻击类型之一;随着人们日益依赖 Web 应用程序,这种漏洞的功效只会更加让人望而生畏。好消息是,与溢出类攻击一样,只要清洁输入数据,并且从不立即信任用户输入内容(至少对输入数据),就能在很大程度上预防这种脆弱点。 即使有了经过最全面测试的、最安全的软件,一旦软件交到了最终用户手里,结果就很难说了。如何配置及部署软件对安全起到的作用如同其他任何安全步骤一样来得重要。 靠不住的默认值 不安全的系统 我们可以从这些新颖的搜索当中汲取几个教训。第一,默认值天下人都知道,因而如果让默认值原封不动,就要考虑清楚:如果让攻击者知道了默认值,后果会多严重。第二,你应该知道系统的各部分是如何可以访问的,并且考虑这种访问功能是不是合适。第三,记住通过隐藏获得安全(security through obscurity)行不通。不管公众可以获得的信息多么不重要或者多保密,只要通过自动搜索或者通过某种人力,致力于找到这种数据的人总会搞到手。 总之,随着越来越多的脆弱点每天被发现,这些威胁只是沧海一粟。与这些例子一样,即便不是全部脆弱点,至少大部分脆弱点源于疏忽:无论是开发人员疏忽了采取安全做法,还是最终用户忽视了更改配置。诚然,我给出的例子可能很肤浅,似乎很容易就能避免;但随着一个项目越来越大,出现简单情况未加检查的可能性随之加大。攻击者只要抓住小小的机会,就能对系统构成严重威胁,并且带来永久性破坏。开发人员应当充分了解想当然的假设会带来什么影响,并且测试时要考虑到非正常使用。如果充分了解系统的工作方式,并且假定攻击者可能瞄上自己的产品,开发人员就会定期审查自己的工作,并且必要时发布补丁。 个人可能说不出软件存在多大的缺陷;尽管世界上没有什么完全安全的系统,但人们可以采用多层安全机制,以便尽量减少脆弱点。强密码、让软件保持更新版本、合理打上补丁,并知道软件每个部分带来的影响,这些都是最终用户增强保护层的小办法。最后,与软件相关的每个人都有责任关注安全,并且设法减少脆弱点。 |