PHP

Web应用程序的十大安全漏洞

    卢卡斯Vileikis
    分享

    考虑您构建的应用程序的安全性是非常重要的。有很多方法可以解决安全问题,但是最有效的入门方法是解决OWASP(开放Web应用程序安全项目)确定的十大安全问题。在本文中,我们将介绍当前应用程序的十大安全漏洞。

    OWASP是一个致力于web应用程序安全的国际组织,该社区每四年发布一次OWASP前10名报告,概述了web应用程序最紧迫的安全问题。我们将从PHP开发人员的角度来研究这些漏洞,但它们与使用任何编程语言构建应用程序有关。

    OWASP安全漏洞:概述与比较

    2021年OWASP十大安全漏洞榜单列出了10个最危险的web应用程序安全漏洞。如果我们将当前的列表与2017年的列表进行比较,我们可以看到一些安全漏洞仍然在列表中,但位置不同,并且一些新的安全漏洞也出现在列表中。

    下表是2017年和2021年的榜单对比。(2021年名单中引入的安全漏洞概述在大胆的,其余的只是重新洗牌。)

    2017年OWASP十强 2021年OWASP前10名
    #1 -注入 #1 -访问控制中断
    #2 -破碎的认证 #2 -密码失败
    #3 -敏感数据暴露 #3 -注入
    XML外部实体(XXE) #4 -不安全的设计
    #5 -访问控制中断 #5 -安全错误配置
    #6 -安全错误配置 #6 -易受攻击和过时的组件
    #7 -跨站脚本(XSS) #7 -识别和身份验证失败
    #8 -不安全的反序列化 #8 -软件和数据完整性故障
    #9 -使用具有已知漏洞的组件 #9 -安全日志和监控故障
    #10 -日志记录和监控不足 服务器端请求伪造(SSRF)

    这个表格表明大多数针对web应用程序的安全漏洞都没有改变。改变的是开发人员在试图修复这些缺陷时的方法。与流行的观点相反,从一开始就避免这些安全漏洞是相当容易的;我们只需要了解一些适用于特定安全问题的基本规则。

    让我们深入研究这些安全问题。

    访问控制中断

    根据2021年版OWASP,我们最应该关注的问题是访问控制中断。访问控制中断就像它听起来的那样:它发生在什么时候我们控制应用程序访问的方式是有缺陷的.下面是一个被破坏的访问控制的例子。

    一段容易被破坏的访问控制的代码"loading=

    <形式方法帖子行动><输入类型文本的名字用户名占位符你的用户名吗?><输入类型文本的名字密码占位符你的密码?><输入类型提交的名字提交价值登录>形式><?php如果收取$ _POST“提交”美元的用户名$ _POST“用户名”美元的密码$ _POST“密码”如果美元的用户名如果美元的密码“loggedin_page.php”退出? >

    你看到问题了吗?代码只是检查用户名和密码字段是否为空。在数据库中运行几个查询以确保用户名和密码存在,怎么样?去核实你的说法?这部分被很容易地遗忘了。用户可以简单地在用户名和密码字段中输入任何内容,以确保它们不是空的,单击提交,该用户将登录。

    为了避免破坏访问控制问题:在将用户标记为已登录之前,始终根据数据库验证用户名(电子邮件)和密码字段。

    密码失败

    密码失败以前被称为“敏感数据暴露”。敏感数据暴露被重命名为“密码故障”,因为这解决了许多安全问题,而“敏感数据暴露”只解决了其中一个问题。

    密码失败覆盖加密数据的失败,这通常会导致敏感数据暴露。PHP中的加密失败主要与密码有关:使用除设计为较慢的哈希算法(想想BCrypt和Blowfish)之外的任何算法来哈希它们是一种加密失败,因为其他类型的哈希(MD5和类似的)很容易且快速地使用暴力。

    为了避免密码失败:确保存储在数据库中的所有密码都使用一种慢于暴力破解的算法进行散列。我们建议您选择Blowfish或BCrypt,因为这些算法长期使用是安全的,并已经过安全专家的测试,并已被证明可以抵御攻击。

    如果有很多用户在使用您的应用程序,您可能还需要进行调查.对于大量的散列,盐可以减缓裂解过程。

    注入与不安全设计

    注入是Web上最常讨论的安全问题。每个人都听说过:将用户输入传递到数据库,就有注入缺陷。注入攻击相对来说比较容易克服,但由于连接到数据库的应用程序数量庞大,它们仍然是一个问题。

    下图描述了一个相关的代码示例。

    一段容易被SQL注入的代码"loading=

    <形式方法帖子行动><输入类型文本的名字用户名占位符你的用户名吗?><输入类型文本的名字密码占位符你的密码?><输入类型提交的名字提交价值登录>形式><?php如果收取$ _POST“提交”美元的用户名$ _POST“用户名”美元的密码$ _POST“密码”如果美元的用户名如果美元的密码美元的查询$ DB->查询“SELECT * FROM users WHERE username = .美元的用户名AND密码=美元的密码其他的回声“密码空!”退出其他的回声“用户名空!”退出? >

    上面显示的缺陷是不言自明的:当任何用户输入被传递到数据库时,任何人都可以做他们想到的任何事情。这个缺陷不是PHP独有的。如果您使用任何其他编程语言将用户输入直接传递到数据库,那么您将遇到完全相同的问题。

    成功安装的SQL注入攻击的后果范围很广,但在大多数情况下,它们涵盖以下内容:

    • 攻击者可以获取用户表的备份副本,对其他信息系统执行凭据填充攻击。
    • 攻击者可以获得数据库内部的管理权限,然后修改或删除其中的表。

    这两种行为,如果执行成功,将不利于任何企业。从用户表获取的数据库转储将导致它在暗Web上出售,一旦出售,攻击者获利,其他攻击者将使用该数据进行凭据填充攻击。攻击者获得存储用户数据的数据库的管理权限也会造成严重破坏——不仅对网站用户,对网站所有者也会造成严重破坏,他们将遭受公众负面审查的风暴。

    避免SQL注入:与参数化查询一起使用PDO。这种方法可以保护应用程序不受SQL注入的影响,因为数据是与查询本身分开发送的。

    前面显示的查询的这种方法如下图所示(注意第13行和第14行中的变化)。

    一段SQL注入漏洞已被修补的代码"loading=

    <?php如果收取$ _POST“提交”美元的用户名$ _POST“用户名”美元的密码$ _POST“密码”如果美元的用户名如果美元的密码美元的查询$ DB->准备“SELECT * FROM users WHERE username =: username AND password =: password”美元的查询->执行数组”:用户名”=>美元的用户名”:密码”=>美元的密码其他的回声“密码空!”退出其他的回声“用户名空!”退出? >

    另一方面,不安全设计不同于注入,有一个单独的类别。注入是不安全设计的一部分,但不安全设计不是注入。不安全的设计涵盖如何根据设计(即默认情况下)编写代码。这意味着,如果在默认情况下,您的代码将任何用户输入传递到数据库,或者允许用户在不验证自己的情况下登录,或者允许用户在不检查扩展名的情况下上传文件,或者在不验证的情况下返回用户输入,那么您就存在不安全的设计缺陷。

    为了避免SQL注入、将用户输入传递到数据库以及不安全的设计缺陷,请确保遵循以下步骤由OWASP概述的安全编码指南或者其他供应商。如果你遵循这些指导方针,你在这方面应该是安全的。

    安全错误配置和过时的组件

    在第五位和第六位,我们有安全错误配置和过时的组件。这两个缺陷与前面提到的不同,但它们也非常危险。

    当探测应用程序中可能存在的安全错误配置漏洞时,攻击者将查看所有内容。他们会试图访问默认帐户,访问应受保护的页面,利用未修补的漏洞,等等。在这种情况下,我们唯一的希望是更新组件并针对各种漏洞打补丁。过时的组件通常带有严重的漏洞,如果被利用,可能会导致数据库泄露和敏感数据暴露,服务器宕机,声誉受损,罚款等等。

    这就是为什么做以下事情是至关重要的:

    • 确保您的应用程序使用的组件始终是最新的。
    • 确保在一段时间不活动后强制注销用户。(也就是说,确保会话在指定的时间后过期。)
    • 如果可能的话,考虑在提交表单或登录网站的某个部分失败一段时间后实现CAPTCHA。
    • 如果可能的话,使用web应用程序防火墙来保护您的web应用程序免受针对它的攻击,并考虑使用类似于Cloudflare同时保护您的应用程序免受DoS和DDoS攻击。

    为了避免错误配置和过时的组件缺陷:确保您使用的是更新的组件,并且您的代码与之一致基本安全标准比如上面提到的那些。

    为了使应用程序更加安全,尤其要密切关注允许用户对自己进行身份验证的组件。

    识别和认证失败

    识别和身份验证失败以前被称为“身份验证损坏”漏洞。当应用程序没有充分保护让用户验证自己的部分时,就会出现这样的漏洞,这可能意味着以下一种或多种情况:

    • 应用程序不能通过使用CAPTCHA或其他措施来保护其表单免受暴力攻击。
    • 应用程序的注册页面允许使用弱密码。(也就是说,应用程序没有定义最小密码长度。)
    • 注册表单缺少“重复密码”字段。(也就是说,用户注册时没有仔细检查密码是否正确。)
    • 密码更改表单不受保护CSRF(跨站请求伪造),让用户B代表用户a伪造请求(即用户B可以发送一个专门制作的URL,该URL打开后将更改用户a的密码)。
    • 可以枚举帐户:应用程序根据某个帐户是否存在于数据库中而提供不同类型的消息。
    • 应用程序以明文形式存储密码。
    • 应用程序在输入参数中指定用户名后返回该用户名,而不进行过滤。(这种方法可以实现XSS攻击,攻击者可以在网站中注入恶意脚本。)

    避免识别和认证失败:确保安全构建注册和登录表单。当然,说起来容易做起来难,但是按照下面列出的步骤来做,你应该会做得很好:

    • 确保所有注册用户使用安全密码。(执行8个或更多字符的策略。)
    • 在一组不成功的登录尝试(例如,5次或更多)后,向用户提供验证码。换句话说,执行速率限制。
    • 确保用户提供的所有参数都是干净的。(也就是说,不要在没有验证的情况下将用户输入返回给用户。这样做会导致XSS攻击。)
    • 确保允许更改密码的表单不受CSRF的保护。换句话说,生成一个令牌,在每个请求上都要更改,以使攻击者无法伪造请求并冒充用户。
    • 尽可能使用双因素身份验证,以避免针对登录表单的凭据填充攻击。

    软件和完整性故障以及日志和监控问题

    虽然与日志记录和监控机制相关的问题是相对不言自明的,但软件和完整性故障可能不是。不过,这并没有什么神奇之处:OWASP社区只是告诉我们,我们应该验证所使用的各种软件的完整性,不管它是否是基于php的。想一想:您上次更新应用程序是什么时候?你是否验证了更新的完整性?加载到web应用程序中的资产呢?

    请看下面的代码示例。你注意到什么了吗?

    样式表和javascript文件的一段具有子资源完整性(SRI)的代码"loading=

    <链接hrefhttps://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.cssrel样式表完整性sha384-rbsA2VBKQhggwzxH7pPCaAg046MgnOM80zWlRWuH61DGLwZJEdK2Kadq2F9CUG65crossorigin匿名><形式方法帖子行动><输入类型文本的名字用户名占位符你的用户名吗?><输入类型文本的名字密码占位符你的密码?><输入类型提交的名字提交价值登录>形式><?php如果收取$ _POST“提交”美元的用户名$ _POST“用户名”美元的密码$ _POST“密码”如果美元的用户名如果美元的密码美元的查询$ DB->准备“SELECT * FROM users WHERE username =: username AND password =: password”美元的查询->执行数组”:用户名”=>美元的用户名”:密码”=>美元的密码其他的回声“密码空!”退出其他的回声“用户名空!”退出? ><脚本srchttps://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js完整性sha384-kenUlKFdBIe4zVFOs0G1M5b4hcpxyD9F7jL + jjXkk + Q2h455rYXK / 7 hauojl + 0预告crossorigin匿名>脚本>

    样式表和加载到其中的JavaScript文件都受到完整性属性的保护。完整性属性对于确保加载到web应用程序中的样式表和JavaScript文件没有被篡改至关重要。如果文件的代码与完整性属性第一次生成时发生了任何变化,那么脚本将不会加载到web应用程序中,相反,我们将看到一个错误,如下图所示。

    与子资源完整性(SRI)相关的错误"loading=

    诚信无处不在。虽然在某些情况下,违反完整性将提供警告(如上图所示),但在其他情况下,后果将更加严重,并可能导致数据泄露。

    为了确保您的代码没有被篡改,正确地监视您的基础设施是非常重要的但这种方法本身可能存在缺陷。当您的监视方法有缺陷时,您将无法捕获错误。有些错误很小,如上图所示。有些错误更为严重,例如当您的应用程序容易受到SQL注入、安全错误配置或上述任何其他缺陷的攻击时。因此,一定要确保你的应用程序记录了任何与你的网站的关键功能相关的异常。

    这样做说起来容易做起来难,但是使用软件来监控你网站的整个边界,以防止未经授权的安全相关事件是一个很好的开始。不幸的是,手动监控所有内容仅在应用程序相当小的情况下是可行的,但从长远来看,这不会对您有太大帮助。

    为了减轻软件和完整性故障,以及日志和监控问题:查看web应用程序防火墙产品,例如CloudflareSucuri,或Imperva.记住:付钱给安全供应商总是比从数据泄露中恢复更便宜。

    服务器端请求伪造

    2021年OWASP十大榜单中的最后一个重要问题是服务器端请求伪造(SSRF)。SSRF是一种允许恶意方通过易受攻击的服务器向网站发送请求的攻击。SSRF是OWASP列表中的一个新漏洞,其行为与CSRF类似。CSRF的目标是代表用户发出非预期的请求,而SSRF的目标是服务器。SSRF迫使应用程序向攻击者设置的位置发出请求。请看下面这段代码。(注意对头()功能应完成之前任何文本都被写入页面,否则调用可能会被忽略。)

    一段易受SSRF影响的代码"loading=

    <?php如果收取$ _POST“提交”$ URL$ _GET“picture_url”如果使用filter_var$ URLFILTER_VALIDATE_URL美元的内容函数$ URL“内容类型:图像/ png”回声美元的内容“位置:picture_changed.php”退出其他的回声“不正确的URL。退出? >

    这段代码做了两件事。方法中提供的URL是否为picture_urlGET参数是一个有效的URL。然后,它将URL中的内容提供给用户,并将用户重定向到另一个PHP脚本。向用户提供URL中的内容正是使此PHP代码容易受到SSRF影响的原因。显示用户提供的任何东西都是危险的,因为用户可以做以下任何事情:

    • 向服务器上的内部文件提供URL并读取敏感信息。例如,当一个URL像file:///etc/passwd/,易受SSRF影响的应用程序将显示/ etc / passwd文件显示在屏幕上。但是这个文件包含关于拥有在服务器上运行的进程的用户的信息。
    • 向应用程序提供服务器上文件的URL,然后读取文件。(考虑为服务器上的web服务提供一个URL,等等。)
    • 向应用程序提供一个指向钓鱼页面的URL,然后将其转发给用户。由于钓鱼页面将驻留在原始URL(您的服务器的URL)上,毫无戒心的用户很有可能落入这种圈套。

    避免SSRF:可以说,避免这种攻击的最简单方法是使用可使用的url白名单。PHP web应用程序中的白名单应该与下图中的代码类似。(特别注意第25至28行。)

    一段不受SSRF影响的代码"loading=

    <?php如果(收取($ _POST['提交'])){$ URL = $ _GET (' picture_url '];白名单美元=数组(" https://google.com ", " https://twitter.com ", ""...");如果(!in_array($URL, $whitelist)) {echo "错误的URL.";} if(filter_var($URL, FILTER_VALIDATE_URL)) {$Contents = file_get_contents($URL);标题(“内容类型:图像/ png”);echo $内容;标题(“位置:picture_changed.php”);退出; } else { echo "Incorrect URL."; exit; } } ?>div>形式>

    现在,应用程序将URL输出回显给用户不再是问题,因为URL列表是由您控制的。您的应用程序不再容易受到SSRF的攻击!

    总结

    在本文中,我们向您介绍了可能危及PHP web应用程序的十大安全漏洞。其中一些缺陷是在2021年首次进入OWASP的,其他缺陷是从2017年的OWASP旧版中重新洗牌的。然而,有一个原则是不变的:所有这些都是相对危险的,应该妥善处理。

    希望本文对提高应用程序的安全性有所帮助。我推荐你去深潜让自己沉浸在OWASP的世界中,学习更多关于如何最好地保护您的web应用程序的知识

    轻松发现WordPress漏洞"></a>
         <div class= 轻松发现WordPress漏洞 查尔斯·科斯塔
    我最喜欢的5个AngularJS演示应用"></a>
         <div class= 我最喜欢的5个AngularJS演示应用 山姆-迪尔岭
    5更多的PHP安全漏洞"></a>
         <div class= 5更多的PHP安全漏洞 大卫Shirey说
    十大PHP安全漏洞"></a>
         <div class= 十大PHP安全漏洞 大卫Shirey说
    Baidu