网络安全漏洞是网络安全专家处理的最棘手的问题之一。开放网络应用安全项目(Open Web Application Security Project),即OWASP。一个网络安全专家应该了解和防御的十大网络安全漏洞的列表,以维护安全的网络服务。2017年的OWAST Top 10为:
注入(Injections): 当攻击者能够将代码插入发送到网站的请求中,然后欺骗该网站将代码传递给后端服务器并执行时,就会出现注入缺陷。这方面最常见的例子是针对数据库的SQL注入攻击。
失效的身份认证(Broken authentication): 当网站要求用户进行身份验证,但提供身份验证的机制存在缺陷时,就会出现的破碎的认证。后续会谈到攻击者如何利用这种叫做会话劫持的攻击。
敏感信息泄露(Sensitive data exposure): 当一个不安全的网络应用程序意外地将敏感信息暴露给窃听者时,就会发生敏感数据暴露。这可能很简单,因为意外地将客户文件放在网站的公开访问部分,或者当网络服务器管理员没有实施HTTPS协议来加密在互联网上发送的信息时,就可能发生这种情况。
XML外部实体注入攻击(XML External Entities)(XXE): XML外部实体可以被攻击者用来从配置不良的XML处理器中获得敏感的内部信息。在最坏的情况下,这些漏洞甚至可能允许远程代码执行或拒绝服务攻击。
失效的访问控制(Broken Access Controls): 当开发人员未能在后端检查用户是否被授权访问应用程序的特定功能时,就会发生访问控制被破坏的情况。对应用程序有了解的用户可以直接向服务器发送请求,绕过用户界面中内置的安全控制。这一类别还包括不安全的直接对象引用。当开发者暴露了底层应用程序功能的一些细节,然后没有执行适当的安全检查以防止未经授权使用该应用程序时,就会发生这种情况。例如,想象一个像这样的URL,在请求中嵌入了一个用户的账号。攻击者可能会简单地尝试改变账号,以访问一个不同的账户。如果网络应用程序没有检查以确保用户被授权访问该账户,攻击者就可能获得未经授权的访问。
安全错误配置(Security Misconfiguration): 安全错误配置的发生是因为网络应用程序依赖于大量的复杂系统,包括网络服务器、应用服务器、数据库服务器、防火墙、路由器和其他组件。这些组件中的每一个都有自己的安全设置,这些设置中的任何一个错误都可能危及整个系统的安全。
跨站脚本攻击(Cross Site Scripting)(XSS): 跨站脚本是一种攻击,攻击者在第三方网站中嵌入脚本,然后可能在受害者的浏览器中执行。
不安全的反序列化(Insecure Deserialization): 不安全的反序列化是一个复杂的安全问题,涉及应用程序或API处理网络用户提供的对象的方式。如果这个过程设计得不安全,攻击者就有可能进行远程代码执行攻击。
使用具有已知漏洞的组件(Using components with known vulnerabilities):网络开发人员必须非常谨慎地对待他们用来构建应用程序的组件,因为许多这些组件都有已知的漏洞。如果一个网络应用程序是使用一个有漏洞的组件建立的,攻击者可能会利用该组件来攻击应用程序本身。管理员必须确保定期监控他们的环境,一旦有安全补丁,就立即应用到组件上。
不足的日志记录和监控(Insufficient logging and monitoring): 当应用程序没有创建详细的日志记录时,就会出现日志和监控不足的情况,这些记录包含了对安全调查和故障排除工作至关重要的信息。
世界在软件上运行。应用程序几乎控制着我们生活的每一个方面,从驾驶飞机的软件到通过自动取款机发放货币的应用程序。软件开发人员每天都在努力工作,为我们生活的许多方面带来自动化和一体化。我们对软件的依赖性越来越强,因此,我们使用已知安全可靠的软件变得越来越重要。
软件安全的细节有很大的不同,这取决于组织如何获得他们的软件。在许多情况下,我们从微软、Adobe和甲骨文等知名供应商那里购买软件。在其他情况下,我们会开发自己的软件,对其进行定制以满足我们专门的业务需求。
在这两种情况下,我们都有安全责任。应用加固(Application Hardening) 是软件安全的核心原则之一。网络安全专家必须仔细测试软件,以确保它尽可能地被锁定(locded down),安全地防止攻击。应用程序加固的一些关键原则是:
组织修补软件漏洞的方法之一是在供应商发布安全补丁后,及时应用这些补丁。主要应用程序的开发者经常收到他们软件中安全问题的报告,他们会发布修补补丁,以防止未来的攻击者利用该漏洞。一旦一个漏洞的知识被公开,那些仍在运行未打补丁的代码的组织就特别容易受到攻击。
应用程序补丁管理是一个关键的安全控制。组织对应用程序的安全设置的配置也有相当大的控制权。例如,当一个组织运行一个复杂的企业资源计划(Complex enterprise resource planning或ERP) 系统时,他们通常会做出配置选择,如在包含ERP数据的光盘上使用的加密类型和范围,可以访问ERP的用户和他们的认证技术,授权给每个可以访问的用户的访问范围,以及支持应用程序的数据库、服务器、网络和其他基础设施的安全性。配置所有这些设置是一项复杂的工作,它涉及许多不同的配置参数和团队。企业管理这个难题的最好方法之一是使用配置基线(Configuration baselines),允许快速比较当前设置和所需的安全配置文件。如果当前设置偏离了安全标准基线,管理员就可以采取行动修复漏洞,并将应用程序恢复到其安全基线。
许多现代动态Web应用程序依赖底层数据库来生成动态内容,SQL注入攻击正是利用了这一点。例如,一个依靠简单的数据库驱动的认证机制的网络应用程序可能在数据库中存储未加密的用户密码,然后当用户试图登录时,应用程序从数据库中检索出正确的密码并与用户的输入进行比较。如果密码匹配,用户就能成功登录到系统中。目前,这不是一个实现密码验证的好方法,但这是许多网站工作的现实。
在这种情况下,网络服务器使用结构化查询语言或SQL编写的查询,从数据库中请求密码。SQL只是关系型数据库使用的语言,它允许用户和应用程序创建、更新、删除和检索数据。
Web应用程序想从数据库中检索一个用户的密码时,它写了一个查询,例如如下的查询:
查询的第一部分,即选择语句,告诉数据库我们要检索的信息和我们想要的特定字段的名称。我们的应用程序要求的是用户名和密码字段。查询的第二部分,即From,给出了包含所需信息的数据库表的名称。然后,我们查询的最后一部分,即Where条款,告诉数据库我们感兴趣的具体记录。
在这个例子中,当我使用用户名mchapple和密码apple登录网络应用程序时,Web应用程序会向数据库发送一个SQL查询,要求为名为mchapple的用户提供正确的密码。如果我输入的密码与存储在数据库中的密码相匹配,就可以登录成功。
现在我们可以看到数据库查询在SQL中是什么样子。如果我是一个黑客,则会试图通过在用户名字段中输入一些奇怪的信息来改变这个查询呢。假设我没有在该字段中输入mchapple,而是输入一些奇怪的文字。我的用户名,后面是一个单引号,一个分号,一个SQL命令,然后是分号和两个破折号。下面是在这种情况下被发送到数据库的内容:
现在,重要的是要知道,分号在SQL中分隔了命令,两个破折号指定了应该被忽略的后续信息。上面的语句,实际上向数据库发送了两条独立的SQL命令和一个注释。第一条命令按要求检索mchapple账号的密码,但第二条命令实际上改变了存储在数据库中的该账户的密码。我们第一次输入的密码是否正确并不重要,因为已经成功地将密码改为设置选择的值。现在我们就可以用这个新的密码来访问应用程序。
这个攻击的精髓是,攻击者需要输入一个单引号,以使自己跳出原来SQL语句中模板的引号。如果我们想防御这种攻击,可以尝试两种技术,输入验证(input validation)和参数化查询(parameterised queries):
跨站脚本攻击是相当危险的,因为它们可以在受害者不知情的情况下发生。这些攻击通常被缩写为XSS攻击,当攻击者在第三方网站中嵌入恶意代码,并在该网站其他访问者的网络浏览器中运行时,就会发生这种攻击。
网页是用HTML代码制作的。HTML是一种标记语言,允许网页拥有各种高级格式,而不仅仅是显示纯文本。HTML作者可以添加不同的字体,包括图像,链接到其他网站,甚至包括称为脚本的小程序,在网站访问者的浏览器中运行。HTML使用标签的概念来执行所有这些动作。
如果我们还想在网页中加入一些脚本,在用户的浏览器中运行程序。可以使用HTML的脚本标签做到这一点。例如,我们可以在一个网页中加入这段代码,在读者的浏览器中弹出一个窗口,说该网站正在建设中:
脚本是一个强大的工具,当脚本是由合法网站的创建者编写时,它是完全合法的。然而,在跨网站脚本攻击中,攻击者设法欺骗一个合法网站,向其用户发送恶意脚本的副本。这通常发生在网站允许用户输入显示给其他用户的信息。例如,一个在线拍卖网站可能接受世界上任何一个人发布的信息。在该网站上发帖的用户可能想用粗体字、图片和其他增强功能来装扮他们的拍卖清单,因此拍卖网站的所有者允许他们在清单中写上HTML代码。但是,如果用户在他们的帖子中包含了意想不到的HTML,比如一个在浏览者的电脑上进行一些恶意操作的脚本,会发生什么?如果网站只是简单地接受这个输入并将其传递给其他用户,用户将看到相同的拍卖清单,但恶意脚本将在用户不知情的情况下在后台运行。
幸运的是,抵御跨站脚本攻击很容易。与SQL注入攻击一样,关键是对任何包含HTML的用户输入使用输入验证,特别是输入验证应注意任何试图在用户提供的输入中使用脚本标签的行为,并从输入中删除任何脚本代码。
Web应用程序面临的另一个危险是跨网站请求伪造的威胁。这些攻击类似于跨站脚本攻击,但它们甚至更危险。跨站请求伪造(Cross-site request forgery),也有两个不同的缩写词。有些人称之为CSRF,而其他人则使用XSRF的缩写。还有人甚至把这个缩写读成海浪(sea surf)。所有这些术语都是指同一种攻击。
跨站脚本攻击是指攻击者利用第三方网站,在显示给其他用户的输入中包含攻击者编写的脚本。用户的网络浏览器在访问该网站时执行这些代码。跨网站请求伪造攻击则更进一步,利用用户经常在同一时间打开多个网站的事实。而且他们可能登录了许多不同的网站和不同的浏览器标签(tag)。正如你可能已经注意到的,认证会话在不同的浏览器标签之间交叉进行。跨站请求伪造攻击就是利用这一点,利用一个网站欺骗用户的浏览器,在用户不知情的情况下向另一个网站发送非法请求。工作原理如下:
跨网站请求伪造攻击以类似于跨网站脚本攻击的方式掠夺这些持久的认证会话。让我们假设我们有一个在线支付服务,接受账户转账,使用网页请求,如下所示:
用户已经在之前登陆过这个网站,有对应的会话。转账页面需要几个参数。这些参数包括要转移的金额、源账户号码和目标账户号码。现在,知道这一点的攻击者可以尝试利用跨网站请求伪造攻击,试图诱使用户在不知情的情况下发送这个命令。做到这一点的最简单的方法之一是在一个网页中包含一个假的图像标签,该标签实际上执行了所需的命令。如下是一个在线拍卖网站,我们尝试使用它进行跨站请求伪造:
我们将在页面底部添加另一个图像标签。这个图像根本不是图像,而是一个从用户的支票账户向攻击者的支票账户转移资金的请求。当用户加载页面时,该船的销售清单看起来完全正常:
但添加到页面上的隐形图像却执行了未经授权的银行转账(由于用户的游览器保持了登陆银行网站的令牌(token)等信息,可以直接登陆),这就是跨网站请求伪造。
防范跨站请求伪造是很困难的,最佳的防御方式为:
对于 Web 应用程序,存在多种解决方案来阻止恶意流量和防止攻击。最常见的缓解方法之一是为每个会话请求或 ID生成唯一的随机令牌。这些随后由服务器检查和验证。具有重复令牌或缺失值的会话请求将被阻止。或者,与其会话 ID 令牌不匹配的请求会被阻止到达应用程序。
我们刚刚讨论的攻击,即跨网站请求伪造,是一种客户端的攻击。也就是说,它是针对用户的攻击。服务器端请求伪造,或称SSRF,是这种攻击的一个变种,目标是服务器而不是用户。SSRF攻击篡改服务器端应用程序使用的元数据,并试图欺骗服务器,使其从服务器认为是可信的来源中检索恶意的命令或目的地。
目录遍历攻击是另一个常见的web应用程序安全缺陷。这些攻击允许攻击者操纵网络服务器上的文件系统结构。当使用Linux文件系统时,一个句号(.)引用当前目录,而使用两个句号(. .)引用层次结构中的上一级目录。目录遍历攻击使用这些导航引用,试图在目录结构中上下移动,寻找不安全的文件。当应用程序允许用户请求存储在文件系统中其他地方的文件时,这些攻击就会起作用。
ThreadSafetyProblem.html文件是我们实际应该得到的网络应用程序的文件。tomcat-users.xml文件是我们想得到的文件。现在我们在en目录下,所以需要上升四层到.extract目录,然后从那里向下进入conf目录。例如我们通过ZAP软件拦截对于ThreadSafetyProblem.html文件的请求后,看到了如下的文件:
现在,我们需要获取tomcat-users.xml,修改文件名称:
这样,得到回复的就是tomcat-users.xml文件的信息。
当软件工程师开发应用程序时,他们经常预留出特定的内存部分以包含可变内容。用户经常提供对应用程序运作至关重要的问题的答案,并填充这些内存缓冲区。如果开发人员没有检查用户提供的输入内容是否足够短,没有超出缓冲区,就会发生缓冲区溢出。用户的内容可能会从为输入预留的区域溢出到用于其他目的的区域,并可能发生意外的结果,例如泄露一些敏感信息。
Cookies可以在网站访问之间和不同的网站之间跟踪用户。了解Cookie的用途以及如何从系统中删除它们,对于注重隐私的安全管理员来说是一项关键任务。Cookies被网站存储在用户浏览器中,它们通常被用来跟踪单个用户或保留会话之间所需的信息。有一些与cookies相关的隐私风险。当一个cookie被用来跟踪多个网站的活动时,情况尤其如此。这种跟踪理论上可能是匿名的,但只要你向使用同一跟踪cookie的网站之一提供你的名字,你在所有这些网站上的活动就会被取消匿名。
以Chrome为例子,可以在设置中的隐私与安全中对cookies的控制进行修改:
其中,“关闭Chrome时清除cookies和网站数据”,使Chrome在我们每次关闭浏览器时丢弃所有cookies。这确实提供了强大的安全性,因为其他人以后使用同一台电脑将无法访问我们的cookies,但这有点不方便,因为网站每次使用后都会忘记,要求你每次使用时都要登录;“阻止第三方cookies”,防止网站访问其他网站创建的cookies。这个功能最常用于广告,没有多少合适的理由让它保持开的状态。
同时,也可以设置查看Chrome上的所有cookies信息和对不同的网站定义不同的cookie规则。
Cookies经常被用于Web应用程序的认证。在用户登录到一个系统后,网络服务器提供一个cookie,这样用户就不需要在每次请求一个新的网页时持续登录到系统。在每次请求时出示cookie会使网络服务器参考先前的成功登录。一些网络应用程序的一个主要缺陷是,它们没有使用随机的cookie,而是使用一个可猜测的值。
例如,我们先继续启动ZAP应用程序代理,并告诉它拦截登录请求。然后我们向同一个网站发起两次登陆。两次登陆的cookie值如下:
现在,我们有两个用户和他们的cookie值,而我们想做的是能够弄清楚Alice的cookie值。当看这些值时,可能注意到的第一件事是,它们都以相同的五位数开始,所以我们将假定爱丽丝的cookie也以65432开始。然后,它们以一个文本值结束。乍一看,这个文本值看起来有些随机,但通过观察,我们意识到的第一件事是,这些文本值的每一个长度都与用户名相同,cookie末尾的文本值实际上是通过采取用户名,颠倒字母,然后给每个字母加上一个值来计算的。所以A会变成B,B会变成C,以此类推就能找出爱丽丝的cookie。然后我们只需要将请求中的cookie JSESSIONID值添加一个包括我们为Alice计算的会话cookie的值,65432FDJMB即可。这样就算我们没有Alice的密码,也能过以Alice的账号进行登陆。
在上面的例子中,我们看看如果登录cookie不是随机生成的,我们如何能猜到它们。我们用我们的猜测击败了一个网络应用程序的安全性,并以另一个用户的身份登录。**Cookies的另一个问题是,它们可能容易受到会话重放攻击。**如果一个攻击者能够窃听一个用户的连接并窃取cookie值,他们可以使用该cookie作为用户登录。为了防止这些重放攻击,管理员应该总是用安全属性来配置cookie。这可以确保cookie总是通过加密的连接发送,以防止窃听。
代码执行攻击是一类特殊的攻击,攻击者利用系统中的一个漏洞,允许他们在该系统上运行命令。攻击者有许多不同的方式在系统上获得这种立足点(foothold),但通常是通过目标系统向世界暴露的一些资源来完成的。例如,一个面向公众的网络服务器必须将80和443端口暴露给外界。而这些端口提供了对Apache或微软IIS等网络服务器的访问。如果攻击者了解到该网络服务器软件的代码执行漏洞,可以在未打补丁的服务器上利用该漏洞,并利用它在系统上执行他们想要的任何命令。
这种攻击者运行其所选择的命令的情况,被称为任意代码执行(Arbitrary code execution)。当它从远程系统发生时,也被称为远程代码执行(Remote code execution)。如果攻击者欺骗执行其代码的进程是以管理权限运行的,他们将获得对系统的完全访问权。并且他们可能采取的一些行动包括安装恶意代码、将系统加入僵尸网络、窃取敏感信息或创建账户以便日后访问系统等。
我们可以采取两个简单的步骤来保护自己的系统免受代码执行攻击:
软件开发人员必须注意编写不容易受到特权升级攻击的代码。这些攻击试图利用正常的用户账户,将其转化为具有管理权限的账户。这在有外部暴露的系统上可能特别危险,允许互联网上的人控制服务器。这些权限升级的漏洞往往是由于代码中的缓冲区溢出问题或其他安全问题引起的。
当终端用户获得对底层操作系统的访问权时,他们可以利用特权升级漏洞,利用这种访问权来获得管理权限。开发人员和运营团队可以采取一些基本的缓解策略,以减少成功的特权升级攻击的可能性:
设备驱动程序在计算中发挥着重要作用。它们作为硬件设备和操作系统之间的软件接口。设备驱动是我们可以在Windows或其他操作系统中使用来自各种制造商的几乎所有打印机的原因。微软不需要设计Windows来与市场上的每一台打印机一起工作。相反,他们为打印机制造商提供了为其打印机编写Windows驱动程序的能力。当制造商制造一台新的打印机时,他们也会设计一个驱动程序,为Windows提供如何与该打印机互动的说明。设备驱动程序需要对操作系统进行低级访问,而且它们以管理权限运行。如果攻击者能够说服用户在他们的电脑上安装一个恶意的驱动程序,那么这个恶意软件就可以获得对系统的完全控制。
复杂的攻击者可能会深入到设备驱动程序中,并以破坏安全的方式操纵它们。一般有两种方式驱动重构(driver refactoring)和驱动修饰(driver shimming)。
幸运的是,现代操作系统都包含针对恶意驱动的保护措施。这些保护措施中最重要的是代码签名。设备制造商编写驱动程序,然后对这些驱动程序应用数字签名,以便操作系统能够验证其真实性。如果驱动程序没有数字签名,操作系统可能会警告用户可疑的驱动程序或直接阻止其安装。驱动程序的特权性质使它们可以深入访问操作系统。安全专家必须确保他们组织中使用的驱动程序是合法的,没有被修改以进行恶意活动。
计算机必须管理操作系统和应用程序所使用的内存资源。当一个系统支持许多不同的用途时,隔离每个进程使用的内存以防止该内存被读取或以未经授权的方式改变就变得至关重要。对于内存或系统上的任何其他有限资源,我们需要注意的问题之一是资源耗尽。无论是有意还是无意,系统可能会消耗所有的内存、存储、处理时间或其他可用的资源,从而使系统无法使用或瘫痪,无法用于其他用途。
三个相关的例子:
内存泄漏(Memory leak): 如果一个应用程序向操作系统请求内存,它最终将不再需要该内存,然后应该将内存返回给操作系统用于其他用途。在一个有内存泄漏的应用程序的情况下,应用程序未能返回它不再需要的一些内存,也许只是失去了对它写入内存保留区域的对象的跟踪。如果应用程序在很长一段时间内继续这样做,它就会慢慢地消耗掉系统的所有可用内存,导致系统崩溃。重启系统通常会重置问题,将内存恢复到其他用途,但如果内存泄漏没有得到纠正,这个循环就会重新开始。
内存指针(Memory Pointers): 指针是应用程序开发中一个常用的概念。它们只是一个内存区域,用于存储内存中另一个位置的地址。例如,我们可能有一个名为Photo的指针,它包含内存中存储照片的位置的地址。当一个应用程序需要访问实际的照片时,它会执行一个叫做 pointer de-referencing的操作,也就是应用程序跟随指针。
访问指针地址所引用的内存可能出现的一个潜在问题是,如果指针是空的,包含程序员所说的空值。如果一个应用程序试图取消对这个空指针(Bull Pointer Dereferencing)的引用,就会引起一个被称为空指针异常的情况。在最好的情况下,空指针异常会导致程序崩溃,为攻击者提供了获得调试信息的机会,这些信息可能被用于侦察应用程序的安全性。在最坏的情况下,空指针异常可能允许攻击者绕过安全控制。
DLL注入:Windows依赖于动态链接库,或DLLs,以提供应用程序可能共享的公共代码。希望使用DLL的应用程序可以加载它,然后利用其内容。在DLL注入攻击中,攻击者可以将一个恶意的DLL插入到应用程序使用的内存区域,并欺骗应用程序使用该恶意的DLL。所有这些攻击都会带来严重的安全问题,可能影响系统和信息的保密性、完整性和可用性。
安全专家应该监测这些内存问题,并与应用程序开发人员和系统工程师合作,进行适当的内存管理。
竞争条件漏洞是一种特别危险的安全缺陷,需要软件开发者的仔细关注。当安全控制的正常运行取决于计算机或用户执行活动的时间时,就会出现竞争条件。如果时间没有按照预期发生,软件可能会以一种意外的方式行事,从而导致一个重大的安全漏洞。
一个常见的竞赛条件的例子是检查时间(Time of check) 与使用时间(Time of use) 的关系,或者说是通话漏洞(talk to vulnerability)。在通话漏洞中,软件检查一个活动是否被授权,然后过了一段时间才执行它所检查的动作。例如一个银行账户的例子。当一台发放现金的ATM机。这台机器的算法可能是这样的:用户插入一张ATM卡,输入一个密码。机器验证密码并检查可用的账户余额。用户要求得到一笔钱,如果这笔钱少于之前检查的可用余额,机器就会派发这笔钱。但是,如果有两个用户同时使用不同的ATM机进入同一个账户,要去提取750元。而两台ATM机都得知账户里有1000美元可用,然后两个用户都要求从该账户中提取750美元。750元小于1000玩,所以它们各自给自己的用户提供所要求的750美元。导致现在该账户透支了500美元。
我们可以很容易地修改这个算法,以防止对话竞赛的情况发生。可以通过添加一个锁来防止两个用户同时访问同一个账户。当第一个用户在第一台ATM机上访问该账户时,它将在该账户上加一个锁,防止第二个用户开始交易,直到第一个交易完成。
竞争条件会对应用程序的安全性产生重大影响。开发人员必须了解安全风险并规划他们的代码以避免这些问题。
参考资料来源:
https://www.linkedin.com/learning/paths/become-a-comptia-security-plus-certified-security-professional-sy0-601