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

Posted crazy_itman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web 应用程序的十大安全漏洞相关的知识,希望对你有一定的参考价值。

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

OWASP 是一个致力于 Web 应用程序安全的国际组织,社区每四年发布一次OWASP Top 10报告,其中概述了 Web 应用程序最紧迫的安全问题。我们将从 php 开发人员的角度审视这些漏洞,但它们与使用任何编程语言构建应用程序都相关。

OWASP 安全漏洞:概述和比较

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

下表比较了 2017 年和 2021 年的列表。(2021 年列表中引入的安全漏洞以粗体标出,其余的只是重新排列)

2017 OWASP Top 102021 OWASP Top 10
#1 – Injection#1 – Broken Access Control
#2 – Broken Authentication#2 – Cryptographic Failures
#3 – Sensitive Data Exposure#3 – Injection
#4 – XML External Entities (XXE)#4 – Insecure Design
#5 – Broken Access Control#5 – Security Misconfiguration
#6 – Security Misconfiguration#6 – Vulnerable and Outdated Components
#7 – Cross-site Scripting (XSS)#7 – Identification and Authentication Failures
#8 – Insecure Deserialization#8 – Software and Data Integrity Failures
#9 – Using Components with Known Vulnerabilities#9 – Security Logging and Monitoring Failures
#10 – Insufficient Logging and Monitoring#10 – Server-side Request Forgery (SSRF)

该表表明大多数针对 Web 应用程序的安全漏洞都没有改变。当开发人员试图修复这些缺陷时,他们的方法发生了变化。与普遍的看法相反,避免这些安全漏洞很容易入手;我们只需要知道适用于特定安全问题的一些基本规则。

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

损坏的访问控制

根据 2021 年版的 OWASP,我们最应该关注的问题是访问控制被破坏。损坏的访问控制就像它听起来的那样:当我们对控制应用程序的访问方式存在缺陷时,就会发生这种情况。损坏的访问控制示例如下图所示。

<form method="post" action="">
<input type="text" name="Username" placeholder="Your Username?">
<input type="text" name="Password" placeholder="Your Password?">
<input type="submit" name="Submit" value="Log In">
</form>

<?php
if(isset($_POST['Submit'])) 
  $Username = $_POST['Username'];
  $Password = $_POST['Password'];
  if(!empty($Username)) 
    if(!empty($Password)) 
    header("loggedin_page.php");
    exit;
    
  

?>

看到问题了吗?该代码只是检查用户名和密码字段是否不为空。如何在数据库中运行几个查询以确保用户名和密码存在?验证相关帐户?那部分很容易被遗忘。用户可以简单地在用户名和密码字段中输入任何内容以确保它们不为空,单击提交,用户将登录。

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

加密失败

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

加密失败涵盖了加密数据的失败,这通常会导致敏感数据暴露。PHP 中的密码失败主要与密码有关:使用设计缓慢的散列算法(想想 BCrypt 和 Blowfish)以外的任何东西来散列它们都是密码失败,因为其他类型的散列(MD5 和类似的)很容易且快速蛮力。

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

如果有很多用户使用您的应用程序,您可能还想研究一下salting。对于大量的哈希值,盐会减慢破解过程。

注入和不安全设计

注入是网络上讨论最频繁的安全问题。每个人都听说过:将用户输入传递给数据库,你就有了注入漏洞。注入攻击相对容易克服,但由于连接到数据库的应用程序数量庞大,它们仍然是一个问题。

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

<form method="post" action="">
<input type="text" name="Username" placeholder="Your Username?">
<input type="text" name="Password" placeholder="Your Password?">
<input type="submit" name="Submit" value="Log In">
</form>

<?php
if(isset($_POST['Submit'])) 
  $Username = $_POST['Username'];
  $Password = $_POST['Password'];
  if(!empty($Username)) 
    if(!empty($Password)) 
$Query = $DB->query("SELECT * FROM users WHERE username = $Username AND password = $Password");
     else 
    echo "Password empty!";
    exit;
    
   else 
    echo "Username empty!";
    exit;
  

?>

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

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

  • 攻击者可以备份用户表,对其他信息系统进行撞库攻击。

  • 攻击者可以获得数据库内部的管理权限,然后修改或删除其中的表。

如果成功执行这两项操作,将对任何业务都不利。用户表的数据库转储将导致它在暗网上出售,一旦出售并且攻击者获利,其他攻击者将使用该数据进行撞库攻击。获得对存储用户数据的数据库的管理权限的攻击者也会造成严重破坏——不仅对网站用户,而且对网站所有者,他们将受到负面公众审查的风暴。

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

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

<?php
if(isset($_POST['Submit'])) 
  $Username = $_POST['Username'];
  $Password = $_POST['Password'];
  if(!empty($Username)) 
    if(!empty($Password)) 
    $Query = $DB->prepare("SELECT * FROM users WHERE username = :Username AND password = :Password");
    $Query->execute(array(":Username" => $Username, ":Password" => $Password));
     else 
    echo "Password empty!";
    exit;
    
   else 
    echo "Username empty!";
    exit;
  

?>

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

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

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

这两个缺陷与前面提到的不同,但它们也是非常危险的。

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

这就是为什么始终执行以下操作至关重要:

  • 确保您的应用程序使用的组件始终是最新的。

  • 确保在一段时间不活动后强行注销用户。(也就是说,确保会话在指定时间段后过期。)

  • 如果可能,请考虑在尝试提交表单或登录网站的某个部分等一段时间后尝试实施验证码。

  • 如果可能,请使用 Web 应用程序防火墙来保护您的 Web 应用程序免受针对它的攻击,并考虑使用类似Cloudflare提供的服务来同时保护您的应用程序免受 DoS 和 DDoS 攻击。

为避免错误配置和过时的组件缺陷:确保您使用的是更新的组件,并且您的代码遵循上述基本安全标准。

为了使您的应用程序更加安全,请特别注意让用户验证自己的组件。

识别和认证失败

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

  • 该应用程序不会通过使用验证码或其他措施来保护其表单免受暴力破解。

  • 应用程序的注册页面允许使用弱密码。(也就是说,应用程序没有定义最小密码长度。)

  • 注册表单缺少“重复密码”字段。(也就是说,用户注册时没有仔细检查他们的密码是否正确。)

  • 更改密码的表单不受CSRF(跨站点请求伪造)的保护,允许用户 B 代表用户 A 伪造请求。(也就是说,用户 B 可以发送一个特制的 URL,该 URL 在打开时会用户 A 的密码。)

  • 可以枚举帐户:应用程序根据某个帐户是否存在于数据库中来提供不同种类的消息。

  • 该应用程序以纯文本形式存储密码。

  • 应用程序在输入参数中指定用户名后返回用户名,而不对其进行过滤。(这种方法会引发XSS 攻击,攻击者能够将恶意脚本注入网站。)

为避免识别和身份验证失败:确保安全地构建注册和登录表单。当然,说起来容易做起来难,但是按照下面概述的步骤操作,您就可以开始了:

  • 确保所有注册用户都使用安全密码。(执行八个字符或更多字符的策略。)

  • 在登录尝试失败一定次数(例如五次或更多次)后,向用户显示验证码。换句话说,强制执行速率限制。

  • 确保用户提供的所有参数都是干净的。(也就是说,不要在未经验证的情况下将用户输入返回给用户。这样做会引发 XSS 攻击。)

  • 确保允许更改密码的表单针对 CSRF 进行保护。换句话说,生成一个令牌,该令牌在每次请求时都会发生变化,以使攻击者无法伪造请求并伪装成用户。

  • 尽可能使用双因素身份验证,以避免针对您的登录表单的凭据填充攻击。

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

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

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

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAg046MgnOM80zWlRWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<form method="post" action="">
<input type="text" name="Username" placeholder="Your Username?">
<input type="text" name="Password" placeholder="Your Password?">
<input type="submit" name="Submit" value="Log In">
</form>

<?php
if(isset($_POST['Submit'])) 
  $Username = $_POST['Username'];
  $Password = $_POST['Password'];
  if(!empty($Username)) 
    if(!empty($Password)) 
    $Query = $DB->prepare("SELECT * FROM users WHERE username = :Username AND password = :Password");
    $Query->execute(array(":Username" => $Username, ":Password" => $Password));
     else 
    echo "Password empty!";
    exit;
    
   else 
    echo "Username empty!";
    exit;
  

?>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenUlKFdBIe4zVFOs0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

样式表和加载到其中的 javascript 文件都受到完整性属性的保护。完整性属性对于确保加载到 Web 应用程序中的样式表和 JavaScript 文件未被篡改至关重要。如果文件的代码自首次生成完整性属性时发生了根本变化,则脚本将不会加载到 Web 应用程序中,而是会显示错误,如下图所示。

虽然在某些情况下违反完整性会发出警告(如上图所示),但在其他情况下后果会更严重并可能导致数据泄露。

为确保您的代码未被篡改,正确监控您的基础设施至关重要,但这种方法本身可能存在缺陷。当您的监控方法有缺陷时,您不会发现错误。有些错误很小,如上图所示。有些错误更为严重,例如当您的应用程序容易受到 SQL 注入、安全配置错误或上面列出的任何其他缺陷的攻击时。因此,请务必确保您的应用程序正在记录与您网站的关键功能相关的任何异常情况。

这样做说起来容易做起来难,但是使用软件来监控您网站的整个周边以防止未经授权的、与安全相关的事件是一个很好的起点。不幸的是,只有当您的应用程序相当小时,手动监控一切才可行,但从长远来看,它不会让您走得太远。

要缓解软件和完整性故障以及日志记录和监控问题:查看 Web 应用程序防火墙产品,例如CloudflareSucuriImperva提供的产品。请记住:向安全供应商付费总是比从数据泄露中恢复更便宜。

服务器端请求伪造

2021 年 OWASP Top 10 列表中的最后一个重要问题是服务器端请求伪造 (SSRF)。SSRF是一种允许恶意方通过易受攻击的服务器向网站发送请求的攻击。SSRF 是 OWASP 列表中的一个新漏洞,它的行为与其 CSRF 表亲相似。CSRF 旨在代表用户发出意外请求,而 SSRF 则针对服务器。SSRF 强制应用程序向攻击者设置的位置发出请求。请看下图所示的一段代码。(请注意,对函数的调用应该在任何文本写入页面之前header()完成,否则调用可能会被忽略)

<?php
if(isset ($_POST['Submit'])) 
  $URL = $_GET('picture_url'];
  if(filter_var($URL, FILTER_VALIDATE_URL)) 
  $Contents = file_get_contents($URL);
  header("Content-Type: image/png");
  echo $Contents;
  header ("Location:picture_changed.php");
  exit;
   else 
  echo "Incorrect URL.";
  exit;
  

?>

这段代码做了几件事。它首先检查 GET 参数中提供的 URL 是否picture_url是有效的 URL。然后它将 URL 中的内容提供给用户,并将用户重定向到另一个 PHP 脚本。向用户提供 URL 中的内容正是使此 PHP 代码容易受到 SSRF 攻击的原因。显示用户提供的任何内容都是危险的,因为用户可以执行以下任何操作:

  • 提供指向服务器上内部文件的 URL 并读取敏感信息。例如,当file:///etc/passwd/提供类似 URL 时,易受 SSRF 影响的应用程序将/etc/passwd在屏幕上显示该文件。但是此文件包含有关拥有在服务器上运行的进程的用户的信息。

  • 为应用程序提供服务器上文件的 URL,然后读取文件。(考虑为服务器上的 Web 服务提供 URL,等等。)

  • 向应用程序提供网络钓鱼页面的 URL,然后将其转发给用户。由于网络钓鱼页面将驻留在原始 URL(您服务器的 URL)上,因此毫无戒心的用户很可能会上当受骗。

避免 SSRF:可以说,避免此类攻击的最简单方法是使用可使用的 URL 白名单。PHP Web 应用程序中的白名单类似于下图所示的代码行。(特别注意第 25 到 28 行)

<?php
if(isset ($_POST['Submit'])) 
  $URL = $_GET('picture_url'];

  $whitelist = array("https://google.com", "https://twitter.com", ""...");
  if(!in_array($URL, $whitelist)) 
    echo "Incorrect URL.";
  

  if(filter_var($URL, FILTER_VALIDATE_URL)) 
  $Contents = file_get_contents($URL);
  header("Content-Type: image/png");
  echo $Contents;
  header ("Location:picture_changed.php");
  exit;
   else 
  echo "Incorrect URL.";
  exit;
  

?>
</div>
</form>

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

概括

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

以上是关于Web 应用程序的十大安全漏洞的主要内容,如果未能解决你的问题,请参考以下文章

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

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

十大开源Web应用安全测试工具

2017 年十大 Web 应用安全风险;微软脚本编程语言 TypeScript 2.6.2 发布

owaps 十大安全风险漏洞

十大Webserver漏洞扫描工具