本文概述
- 从OWASP十大列表中删除的问题
- 合并问题
- OWASP十大列表中的新问题
- 下一步
- 总结
2001年, 一个新的组织进入了舞台。其目标是解决影响网站和应用程序的安全问题。它被适当地命名为Open Web Application Security Project(OWASP)。如今, 它发布资源, 组织会议并提出有关Web和应用程序安全性的标准。 Web应用程序安全性的事实上的标准是OWASP十大项目。它列出了十种最普遍的安全威胁。决定获得什么的影响因素是大量的数据和社区反馈。 2017年末, 该项目进行了更新。对许多现代Web应用程序至关重要的几个新问题占据了自己的位置, 而其中一些已经从列表中逃脱了。
本文是对原始列表的补充, 并说明了列表的最新更改。它描述了威胁, 试图提供清晰的示例以便于理解, 并提出了应对安全威胁的方法。
从OWASP十大列表中删除的问题 在2017年更新之前, 2013年的列表是最新列表。考虑到现在构建和使用Web应用程序的方式的变化, 只有进行彻底的修订才有意义。微服务正在发挥自己的作用, 而新的凉爽而有光泽的框架正在取代原始代码战斗工具。这些事实意味着, 之前列出的某些威胁已被消除, 而另一些则已取代。
我们将确保对本文中长期被遗忘的问题进行记忆, 并介绍新的坏狼。了解历史是不重复同样错误的唯一肯定的方法。
跨站请求伪造
跨站点请求伪造(CSRF)是项目最近迭代中的” 失败者” 之一。之所以消失, 是因为许多现代的Web框架都包含CSRF防御机制。因此, 使你的应用程序遭受威胁的可能性迅速降低。
无论CSRF是否退出列表, 刷新内存仍然是一件好事。让我们确保它不会比以往更强大。
本质上, CSRF是一种感觉像烟雾弹的漏洞利用。攻击者诱使毫无戒心的用户在Web应用程序中执行不需要的请求或操作。简而言之, 攻击者迫使其受害者将请求发送到第三方应用程序, 而受害者却不知道该请求曾经被发送过。该请求可能是用于检索资源的HTTP GET请求, 甚至可能是在受害人的控制下更改资源的HTTP POST请求。在袭击过程中, 受害者认为一切都很好, 甚至常常没有注意到后台正在发生任何事情。空气清除后, 损坏已经完成或丢失了一些东西, 没人知道发生了什么。
目标应用程序内成功的先前用户身份验证使陷阱有效。用户在攻击登录到应用程序之前的某个时候。该应用程序向受害者发送了一个cookie以记住他们。一旦网络浏览器发送了恶意请求, 该Cookie就会与任何潜在的有效载荷一起自动发送, 并且该应用程序不反对将请求提供给它已经认识的用户。
最著名的例子之一就是欺骗用户, 将钱从他们的帐户转移到攻击者控制的帐户中。用户登录到电子银行系统以检查其帐户余额。之后, 他们访问一个在线论坛以检查新手机的评论。一名使用炸药钓鱼的攻击者发布了一个评论, 其中包括带有看似损坏的图像超链接的图像。攻击者使用了电子银行系统内部用来将资金从帐户A转移到帐户B的超链接, 而不是真实的超链接:https://payments.dummybank.com?receiver = attacker&amount = 100。银行系统使经过身份验证的用户成为发送者, “ 接收者” 参数中的值成为资金的接收者。当然, 攻击者将其离岸账户指定为接收者。
由于浏览器在呈现页面时会自动加载图像, 因此请求发生在后台。如果银行的付款系统使用HTTP GET请求实现汇款, 那么一切都无法阻止灾难的发生。请注意, 该示例很简单, 很可能不是通过HTTP GET处理传输。但是, 攻击者仅需一点点困难, 就可以设法更改论坛的HTML消息发布表单中的” 操作” 属性。然后, 浏览器将请求发送到银行的支付系统, 而不是论坛的后端。
偷钱只是那里众多例子之一。更改用户的电子邮件地址或进行意外购买也属于此类别。经常发生的情况是, 社会工程学和一些技术知识可以有效地防止软件工程错误。
在设计系统时, 请记住以下几点:
- 不要将HTTP GET请求用于封装修改资源的操作。你应仅将这些请求用于检索信息。请记住, 经验法则是使GET请求成为幂等。
- 确实, 使用HTTP POST请求在内部传输数据时, 除了将参数编码为查询字符串外, 它倾向于以JSON, XML或其他某种格式发送数据。使用非平凡的数据格式可以减少有人创建虚假HTML表单(将数据发送到你的服务)的危险。
- 确保确保在HTML表单中创建并包含一个唯一且不可预测的令牌。这些令牌对于每个请求也应该是唯一的。检查此类令牌的存在和正确性将降低发生威胁的风险。为了找出令牌并将其用于伪造请求中, 攻击者需要访问你的系统并直接从那里获取令牌。由于令牌是一次性的, 因此它们无法在恶意代码中重复使用。
请记住, CSRF并没有消失, 它并不像以前那样普遍。
文章图片
未经验证的重定向和转发
许多应用程序在完成操作后会将用户重定向或转发到该应用程序的另一部分, 甚至其他一些应用程序。例如, 成功登录到应用程序将触发重定向到首页或用户最初访问的页面。通常, 目的地是表单操作或链接地址的一部分。如果处理重定向或转发的组件不能确保目标地址确实是应用程序生成的地址, 则可能会造成威胁。这是一个安全漏洞, 称为” 未经验证的重定向和转发” 。
网络钓鱼和凭据劫持是导致未经验证的重定向和转发被视为危险的两个主要原因。攻击者可以设法更改重定向/转发目标位置, 并将用户发送到几乎与原始应用程序没有区别的恶意应用程序。毫无戒心的用户会向恶意的第三方泄露其凭据和机密信息。在他们意识到发生了什么之前, 已经为时已晚。
例如, Web应用程序经常实现登录并支持重定向到上次访问的页面。为了能够轻松做到这一点, HTML表单的action属性可能类似于http://myapp.example.com/signin?url=http://myapp.example.com/puppies。你是幼犬的忠实拥护者, 因此请安装一个浏览器扩展程序, 用你喜欢的幼犬的缩略图替换网站图标, 这是很有意义的。不幸的是, 这是一个狗吃狗的世界。浏览器扩展的作者决定利用你的无条件爱心来兑现, 并引入其他” 功能” 。每次你访问自己喜欢的小狗粉丝网站时, 它都会使用指向其自己网站的链接来替换表单的action属性中的” url” 参数。由于网站看起来完全一样, 因此当你提供信用卡详细信息以购买小狗纸牌时, 实际上是在资助恶意攻击者, 而不是你的嗜好。
解决漏洞需要通过确保目标位置是目标位置来进行检查。如果框架或库执行了完整的重定向或转发逻辑, 则检查实施并在必要时更新代码会很有帮助。否则, 你需要进行手动检查以防止受到攻击。
你可以进行几种检查。为了获得最佳保护, 请结合使用多种方法, 而不是仅坚持其中一种。
- 验证传出URL, 确保它指向你控制的域。
- 与其使用显式地址, 不如在前端对它们进行编码, 然后在后端对它们进行解码和验证。
- 准备受信任URL的白名单。仅允许转发和重定向到白名单位置。首选这种方法来维护黑名单。通常只有在发生不良情况时, 黑名单才会填充新项目。白名单限制更严格。
- 使用LinkedIn和其他一些应用程序使用的方法:向你的用户显示一个页面, 要求他们确认重定向/转发, 以明确他们将离开你的应用程序。
存取控制中断
漏洞是由对应用程序某些部分的权限和访问控制不充分或完全缺乏引起的。在OWASP十大项目的先前迭代中, 存在两个问题:不安全的直接对象引用和缺少功能级别的访问控制。由于它们的相似性, 它们现在合并为一个。
直接对象引用
URL中经常使用直接对象引用来标识正在操作的资源。例如, 当用户登录时, 他们可以通过单击包含其个人资料标识符的链接来访问其个人资料。如果该标识符存储在数据库中并用于检索个人资料信息, 并且应用程序假定人们只能通过登录页面进入个人资料页面, 则更改URL中的个人资料标识符会暴露另一个用户的个人资料信息。
设置删除配置文件格式为http://myapp.example.com/users/15/delete的URL的应用程序清楚表明, 该应用程序中至少还有14个其他用户。在这种情况下, 弄清楚如何获取其他用户的删除形式不是火箭科学。
该问题的解决方案是对每个资源执行授权检查, 而无需假设只能采用某些路径来访问应用程序的某些部分。此外, 删除直接引用并使用间接引用是又一个进步, 因为这使恶意用户很难弄清楚如何创建引用。
在开发过程中, 为预防起见, 请写下一个简单的状态机图。让状态代表应用程序中的不同页面, 并转换用户可以执行的操作。这样可以更轻松地列出所有需要特别注意的过渡和页面。
文章图片
缺少功能级别的访问控制
缺少功能级别的访问控制与不安全的直接对象引用非常相似。在这种情况下, 用户修改URL或其他参数以尝试访问应用程序的受保护部分。如果没有适当的访问控制来检查访问级别, 则用户可以获得对应用程序资源或它们的存在的至少某些了解的特权访问。
从直接对象引用的示例中借用, 如果应用程序假定访问删除表单的用户仅是超级用户, 因为超级用户无需进行任何进一步授权就可以看到指向删除表单的链接, 因此会出现巨大的安全漏洞。依靠某些UI元素的可用性是不合适的访问控制。
通过始终确保在应用程序的所有层中执行检查来解决此问题。前端接口可能不是恶意用户访问你的域层的唯一方法。另外, 请勿依赖用户传递的有关其访问级别的信息。执行适当的会话控制, 并始终仔细检查接收到的数据。仅仅因为请求正文说用户是管理员, 并不意味着他们就是管理员。
现在, 损坏的访问控制结合了与访问控制不足有关的所有问题, 无论是在应用程序级别还是在系统级别, 例如文件系统的配置错误。
文章图片
OWASP十大列表中的新问题 新的前端框架的出现和新软件开发实践的采用, 将安全性关注点转移到了全新的主题上。新技术还设法解决了我们以前手动处理的一些常见问题。因此, 修改列表并根据现代趋势对其进行调整变得非常有益。
XML外部实体
XML标准提供了一个鲜为人知的想法, 即外部实体, 它是文档的数据类型定义(DTD)的一部分。它允许文档作者指定到外部实体的链接, 然后可以引用这些链接并将其包含在主文档中。一个非常简单的示例是:
<
?xml version="1.0" encoding="ISO-8859-1"?>
<
!DOCTYPE foo [
<
!ELEMENT foo ANY>
<
!ENTITY bar "baz">
]>
<
foo>
&
bar;
<
/foo>
在解析期间, 引用&bar; 被定义的实体中的内容替换, 从而产生< foo> baz < / foo> 。
如果应用程序接受外部输入并将其不加任何检查地直接包含到XML文档定义中, 则可能会发生广泛的数据泄漏和攻击。
神奇的事情是, 实体不必是简单的字符串, 它可以是对文件系统上文件的引用。 XML解析器很乐意获取指定文件的内容, 并将其包含在生成的响应中, 从而可能揭示敏感的系统信息。如OWASP所示, 通过将实体定义为以下内容, 很容易获得系统用户的信息。
<
!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
此漏洞的一个特别麻烦的” 功能” 是轻松执行拒绝服务攻击的可能性。一种简单的方法是列出无尽文件的内容, 例如/ dev / random。另一个是创建一系列实体, 每个实体多次引用前一个实体。这将最终引用转换为可能非常宽和很深的树的根, 其解析可能会耗尽系统内存。这种攻击甚至被称为” 十亿笑” 。如Wikipedia所示, 定义了一系列虚拟实体, 这为攻击者提供了在最终文档中包含10亿个lol的机会。
<
?xml version="1.0"?>
<
!DOCTYPE lolz [
<
!ENTITY lol "lol">
<
!ELEMENT lolz (#PCDATA)>
<
!ENTITY lol1 "&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
&
lol;
">
<
!ENTITY lol2 "&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
&
lol1;
">
<
!ENTITY lol3 "&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
&
lol2;
">
<
!ENTITY lol4 "&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
&
lol3;
">
<
!ENTITY lol5 "&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
&
lol4;
">
<
!ENTITY lol6 "&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
&
lol5;
">
<
!ENTITY lol7 "&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
&
lol6;
">
<
!ENTITY lol8 "&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
&
lol7;
">
<
!ENTITY lol9 "&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
&
lol8;
">
]>
<
lolz>
&
lol9;
<
/lolz>
可以通过使用不太复杂的数据格式来防止XML外部实体被利用。 JSON是一个很好的替代品, 但由于可能会对它进行攻击, 因此也要采取一些预防措施。必须更新XML库, 同时禁用外部实体处理和DTD。与往常一样, 请在使用之前或将其包含在文档中之前, 对来自不受信任来源的数据进行验证和清除。
不安全的反序列化
在编写代码时, 开发人员有权使用自己编写的代码来控制正在开发的系统。控制仅编写少量代码甚至不编写代码的第三方系统的行为有多棒?由于人们并不完美, 并且图书馆存在缺陷, 这确实是有可能的。
应用程序状态和配置通常被序列化和存储。如果序列化数据与当前用户紧密耦合, 有时浏览器将充当存储引擎。试图变得聪明并节省处理时间的应用程序可以使用cookie来标记用户已登录。由于只能在成功登录后创建cookie, 因此将用户名存储在cookie中是有意义的。然后根据cookie的存在和内容对用户进行身份验证和授权。如果人们没有恶意, 那就没有错。老实说, 他们也不必好奇。
如果好奇的用户在他们的计算机上发现了cookie, 他们可能会看到类似以下的内容:
{"username": "joe.doe", "expires": "2018-06-01 10:28:16"}
完全有效的Python字典, 序列化为JSON, 没什么特别的。好奇的用户可能会更改到期日期, 以防止应用程序强制退出。甚至更好奇的用户可能会尝试将用户名修改为” jane.doe” 。如果该用户名存在, 它将为现在可以访问私有数据的毫无戒心的用户打开一个全新的世界。
一个简单的将数据序列化为JSON并使所有内容保持透明的示例远没有发生过的最糟糕的事情。如果攻击者成功修改了一些序列化数据, 则他们可能能够以迫使你的系统执行任意代码的方式对其进行修改。
假设你正在构建一个REST API, 允许人们使用Python编写自己的机器学习模型并将其上传到你的服务。该服务将评估上传的模型并使用你的数据集对其进行训练。这使人们可以使用你的计算资源和大量可用数据集来快速轻松地建立模型。
该服务不会以纯文本格式存储代码。用户腌制其代码, 使用其私钥对其加密, 然后将其发送到API进行培训。当服务需要运行模型时, 它将对代码解密, 解密并运行。棘手的部分是, 泡菜协议是不安全的。可以以允许在反序列化期间执行任意恶意代码的方式构造代码。
Python的pickle协议允许类定义__reduce__方法, 该方法返回有关如何反序列化自定义对象的信息。受支持的返回值之一是两个参数的元组:可调用的和将传递给可调用的参数的元组。考虑到你的ML模型训练系统旨在提供最大的代码结构灵活性, 因此可以编写以下代码:
class Algo(object):
def run(self):
pass
def __reduce__(self):
import itertools
return (list, (itertools.count(1), ))
一旦需要反序列化对象(取消选择), 则仅使用一个参数调用函数列表。函数列表是Python中的列表构造函数, 函数itertools.count会生成一个无限值的迭代器, 从传递的参数开始。将无限迭代器转换为有限列表可能会对系统的性能和稳定性造成灾难性的影响。
解决此类漏洞的唯一真正方法是选择不对来自外部来源的数据进行反序列化。如果无法做到这一点, 建议使用校验和或数字签名来防止反序列化可能被恶意用户修改的数据。另外, 尝试设置与主系统分离的沙箱环境, 以限制可能出现的问题的影响。
当使用外部库对数据进行反序列化(例如从XML或JSON)时, 请尝试选择允许你在执行实际的反序列化过程之前执行对象类型检查的库。这可能会捕获意想不到的对象类型, 其唯一目的是损害系统。
与你的应用程序执行的所有其他操作一样, 强制进行广泛的日志记录和监视。反序列化经常发生或比正常失败更多, 这表明发生了不良情况。尽早发现问题。
日志和监控不足
你花费多少时间来确保记录应用程序中发生的所有警告和错误?你只存储代码中发生的错误, 还是还记录验证错误?如果不满足你域的业务规则会怎样?无法将所有错误和可疑的活动保留在你的应用程序中会带来安全性和数据危害。
想象以下情况。与大多数情况一样, 你的应用程序包含一个登录页面。该表单有两个字段, 一个字段用于输入电子邮件, 另一个字段用于输入密码。如果用户尝试登录并提供了错误的密码, 则可以重试。不幸的是, 错误尝试的次数没有限制, 因此N次失败尝试后登录页面将不会被锁定。攻击者可以利用此机会, 并在给了一封正确的电子邮件的情况下, 继续从Rainbow表中输入密码, 直到一种组合最终成功为止。如果你的应用程序具有足够的安全性, 并且你在将密码输入数据库之前对密码进行了哈希处理, 则这种特殊的攻击将不会起作用。但是, 你是否具有识别入侵的机制?
仅仅因为这一尝试未能破解你的登录页面, 并不意味着其他尝试就不会成功。登录页面也可能不是你拥有的唯一潜在后门。如果没有其他用途, 则有人可能会尝试对你使用损坏的访问控制。即使精心设计的应用程序也应该知道有人正在尝试攻击它们, 即使这不可能。虽然总是如此。
为了尽力保护自己免受此类攻击, 请执行以下步骤:
- 记录应用程序中发生的所有故障和警告, 无论是代码中引发的异常还是访问控制, 验证和数据操作错误。必须将所有存储的信息复制并保留足够长的时间, 以便可以进行追溯检查和分析。
- 确定格式和持久层很重要。具有任意文本格式的大文件很容易实现;以后再处理不是。选择一个易于存储和读取数据的存储选项, 以及一种可以轻松快速地进行反序列化的格式。将JSON存储在数据库中以实现快速访问可以简化使用。定期备份以保持数据库较小。
- 如果你要处理重要且有价值的数据, 请跟踪操作以跟踪最终状态。实施防止数据篡改的机制。
- 让后台系统分析日志并在出现问题时提醒你。检查(就像测试用户是否反复尝试访问应用程序的受保护部分一样简单)帮助。不过, 不要让虚拟检查使系统超负荷。监视系统必须作为单独的服务运行, 并且不得影响主系统的性能。
文章图片
下一步 意识到Web应用程序中的潜在威胁和漏洞很重要。更加重要的是, 开始在你的应用程序中识别它们并应用补丁程序将其删除。
重视应用程序安全性是软件开发项目所有步骤的重要组成部分。软件设计师, 开发人员和测试人员都必须将软件测试过程纳入其工作流程。将安全检查表和自动化测试用于软件开发过程的适当步骤中以降低安全风险是有益的。
无论是分析现有应用程序还是开发新的应用程序, 都应研究OWASP应用程序安全验证标准项目(ASVS)。该项目的目标是为应用程序安全验证开发标准。该标准列举了开发安全Web应用程序的测试和要求。为测试分配的级别是1到3, 其中1表示最小的危险程度, 而3表示最大的潜在威胁程度。通过分类, 应用程序管理员可以确定哪些威胁更可能发生和更重要。不必在每个应用程序中都包含每个测试。
新的和现有的Web应用程序项目, 尤其是那些遵循敏捷原则的Web应用程序项目, 都将从结构化的安全应用计划中受益。如果你决定使用OWASP安全知识框架, 则OWASP ASVS测试的计划会更容易。这是一个用于管理面向安全测试的sprint的应用程序, 附带了一系列有关如何解决常见安全问题的示例, 以及基于OWASP ASVS的易于遵循的清单。
如果你刚刚开始探索Web应用程序的安全性并且需要一个安全的沙箱游乐场, 请使用OWASP WebGoat中的Web应用程序实现。这是故意不安全的网络应用实现。该应用程序将指导你完成所有课程, 每节课程都专注于一种安全威胁。
在应用程序开发期间, 请确保你:
- 识别威胁并确定优先级。定义可能实际发生的威胁并对你的应用程序构成风险。确定威胁的优先级, 并确定哪些威胁应进行最多的开发和测试。如果你在为静态博客提供服务, 则需要花费很多精力来解决日志记录和监视不足的问题。
- 评估应用程序的体系结构和设计。在应用程序开发的后期阶段, 很难解决某些漏洞。例如, 如果你打算执行第三方代码, 并且没有使用沙箱环境的计划, 那么很难抵御不安全的反序列化和注入攻击。
- 更新软件开发过程。针对Web应用程序威胁的测试必须尽可能地是一个自动化过程。通过尝试发现安全漏洞的自动化测试来扩展CI / CD工作流程将非常有益。你甚至可以利用现有的单元测试系统来开发安全测试并定期运行它们。
- 学习和改进。问题和漏洞列表不是一成不变的, 并且绝对不限于十个或十五个威胁。新的功能和思想为新型攻击打开了大门。重要的是要了解Web应用程序安全世界中的最新趋势, 以保持最新状态。运用所学知识;否则, 你会浪费时间。
【变更日志(OWASP十大项目)】哦, 别忘了, 世界不是黑白的。安全漏洞并不孤单;他们经常交织在一起。暴露于一个漏洞通常意味着很多其他漏洞将在拐角处, 等着抬起丑陋的头, 有时甚至不是你的错, 作为系统安全开发人员, 你仍然应该修补漏洞以遏制网络犯罪。有关示例, 请参阅被黑客入侵的信用卡号仍可在Google上使用。
推荐阅读
- 现在该使用Node 8了吗()
- 智能Node.js表单验证
- 使用Spring Boot进行OAuth2和JWT REST保护
- 如何创建安全的Node.js GraphQL API
- 使用Laravel构建GraphQL服务器
- 加快生产中故障排除速度的7种调试技术
- 深入浅出(创建Flask项目完整实例步骤)
- Android-HttpURLConnection-Get与Post请求登录功能
- app内嵌 h5页面 再滑动的时候 触发击穿底下的一些touchstart事件