在成长中的公司中扩展安全覆盖范围很困难。有效做到这一点的唯一方法是使一线开发人员能够轻松地发现,分类和修复漏洞,然后再将其植入生产服务器。
今天,我们很高兴地宣布我们将开放 模糊的光年:我们开发了一种测试框架,用于 通过有状态的Swagger模糊测试来识别不安全的直接对象引用(IDOR)漏洞,该状态量身定制来支持企业微服务架构。它与我们的持续集成(CI)管道集成在一起,以随着Web应用程序的发展提供一致的自动测试覆盖率。

问题

作为一种漏洞,IDOR可以说是企业代码库中最难以系统防御的漏洞之一。它易于利用,并具有潜在的影响,使其成为高风险的漏洞,我们希望将漏洞降到最低。
在安全行业中,主要有两种防御威胁的方法。首先,尝试防止它们发生。如果无法做到这一点,请确保可以检测到它们以进行快速修复。
IDOR的问题在于很难做到其中之一。

难以预防

防止IDOR漏洞的主要问题是,没有可以轻松实施的系统来缓解它。对于跨站点脚本(XSS)攻击,您可以利用有效的模板系统。对于SQL Injection攻击,您可以使用参数化查询。对于IDOR,业界常见的建议是利用映射(例如,随机字符串)以使其更难以枚举作为攻击者的值。但是,实际上,这并不像看起来那样容易。
维护映射会导致两类警告:

  1. 缓存管理
    假设您有一个当前容易受到IDOR攻击的端点: /resource/1。现在,您想要实现一个映射,该映射用一个随机字符串屏蔽URL中的此ID:,/resource/abcdef其中abcdef映射到1。
    在这个人为的示例中,您可能会不赞成使用旧的端点,而只使用新的端点。但是,这可能会破坏浏览器缓存,用户书签以及由搜索引擎索引的页面。试着推出IDOR预防系统时,想象一下SEO受到意外的打击!
    另一种选择是,您可以将流量从旧的端点重定向到新的端点,并使其在较长时间内进入生产环境。但是,对于重定向到位的时间,您仍然容易受到IDOR漏洞的影响。此外,此映射在此期间可以公开获取,因此有人可能会在以后存储和使用它来执行相同的攻击-枚举值较小。
  2. 处理内部参考
    ID参考遍及许多不同的内部系统:各种日志,Kafka消息和数据库条目,仅举几例。从一种参考方法转换为另一种参考方法时,如何确保这些系统都不会损坏?
    一种好的方法是仅将映射字符串用于面向公众的资产,将其数字对应项用于内部引用。但是,您如何强制做到这一点呢?总是会有更多的数据入口,并且问题空间可能会减少为“笨拙”的方法,要么在新的数据入口处转换它,要么在下游处理两种类型的ID。

业界的另一项常见建议是在操纵资源之前仅执行访问控制检查。尽管这样做比较容易,但是它更适合现场修复,因为这是通过代码审核实施的痛苦的手动过程。此外,它要求所有开发人员都知道何时何地实施这些访问控制检查。例如,如果将其放在ORM级别,则可能需要考虑合法的管理案例,以了解何时需要“绕开”这些检查。如果将其放在视图层(假设使用MVC布局),则可能会发现自己到处都在复制代码。
您如何确保所有开发人员都在积极考虑此攻击媒介, 知道如何缓解它?

检测缓慢

此类漏洞的检测策略也有些乏味。尽管手动代码审核很有效,但它们却无法扩展且通常很昂贵。事实证明,现成的静态代码分析器比其价值更高,而且由于可以进行访问控制检查的地方数量众多,因此需要复杂的污点分析模型。
传统的API模糊测试似乎是另一个有效的选择,但事实并非如此。传统的模糊测试的问题在于,它试图以失败暗示漏洞的假设来破坏应用程序。但是,这不一定是正确的。作为安全团队,我们不太关心攻击者可能会或可能不会收到的错误。相反,我们想确定恶意操作何时成功,而传统的模糊测试将完全忽略这些行为 。

解决方案

2019年2月,微软发布了一份 研究论文 ,描述了有状态的Swagger模糊如何能够检测REST API中的常见漏洞,包括IDOR漏洞。该策略的前提如下:

  1. 让用户会话执行一系列请求。
  2. 对于相同的请求序列,让攻击者的会话执行它们。这是为了确保用户和攻击者能够达到相同的状态。
  3. 对于序列中的最后一个请求,让攻击者的会话执行用户的请求。如果成功,则发现潜在的漏洞。

【20200504】Automated IDOR Discovery through Stateful Swagger Fuzzing - 图1
在假设的请求序列中检测IDOR

有状态的模糊测试与传统的模糊测试

一般而言,使用模糊请求来查找漏洞的技术依赖于一个核心假设:应用程序应能够处理向它们抛出的任何输入。这意味着当应用程序由于“格式错误”的输入而中断时,表明存在潜在的利用漏洞,需要进一步调查。
这种方法的问题在于,作为安全团队,我们不太关心应用程序是否针对特定用户而中断,而更关心成功请求在应该失败的情况下。
Swagger作为一种标准化的API规范,非常适合以编程方式定义模糊测试引擎的参与规则。此外,通过使其具有状态,我们可以通过适当的API请求/响应(在每个响应之间保持状态)来模拟用户行为。然后可以将此状态用于模糊将来的请求参数,以便单个请求序列能够准确地模拟用户的会话,从而实现 混乱的工程测试
最后,用户会话测试允许精心设计的场景来断言给定API的各种安全属性。在这种情况下,我们利用它来检查用户是否能够访问不属于他们的私有资源。
这个概念的简单性是深远的。通过与我们的CI管道集成,它提供了一种以自动方式扩展IDOR检测的方法。但是,虽然我们的解决方案受到Microsoft研究的启发,但在将其适应我们的生态系统时遇到了一些问题。

问题

基础架构依赖性

在微服务架构中,服务通常依赖于其他服务。这意味着,为了模糊给定的服务,我们需要与其他嵌套的依存服务一起旋转其依存服务。为了解决这个问题,我们利用Docker Compose 扩展了一个沙箱环境,以便我们可以对该服务执行验收测试。
验收测试是一种将您的服务视为黑匣子,并测试整个系统是否整体正常运行的一种做法。从微服务的角度来看,这与集成测试(模拟外部依赖项)不同,因为验收测试会旋转沙盒实例以进行更现实的端到端测试。由于fuzz-lightyear通过分析成功的请求来识别潜在的IDOR漏洞,因此可以很好地补充此框架。在沙盒实例中运行测试还可以防止在暂存或生产数据库上留下后遗症,因此我们不会用模糊的随机输入来污染我们的数据。验收测试通常集成到CI / CD管道中,但也可以由开发人员在本地运行。
我们在Yelp上使用的一种流行的工具可以方便地进行验收测试,即Docker Compose。这使开发人员可以在一个YAML文件中定义服务依赖关系,并使他们能够轻松启动/停止它们。通过利用此工具,我们可以获得两个优势。首先,我们通过无缝集成到已建立的开发/测试工作流程中来增强开发人员的能力。其次,它可以轻松地与我们现有的CI管道集成,以提供连续的覆盖范围,并通过所有新更改在生成的沙盒环境中测试IDOR漏洞。

资源生命周期不完整

原始研究论文中的一个基本假设是,经过测试的应用程序支持所有CRUD(创建,检索,更新,删除)方法。由于可以在应用程序的API中创建和处理任何资源,因此可以进行状态模糊测试。
但是,Yelp并非如此。通常,服务仅提供接口来检索和更新直接与该服务相对应的资源,而依靠其他服务来创建此类资源。这意味着如果我们不在请求序列中创建资源,则有状态的模糊测试将是无效的,因为无法测试资源的检索。
例如,服务A具有将X business_id作为输入的端点X ,但是服务A本身不具备创建业务的能力。有状态的模糊测试算法本身将永远无法测试端点X,因为我们无法产生业务!
我们不能仅仅将另一个服务的API附加到请求序列生成过程中,因为这会大大扩展算法的搜索空间。因此,我们的解决方案是为开发人员提供定义模糊测试时可以使用的工厂固定装置的能力。灯具的外观如下:

@ fuzz_lightyear。register_factory(’userID’)
def create_biz_user_id():
返回 do_some_magic_to_create_business()

查看GitHub 托管的❤的原始register_factory.py
这注册create_biz_user_iduserID资源的提供者,因此,如果请求中fuzz_lightyear需要userID资源,则可以使用工厂生成资源。fuzz_lightyear通过降低创建依赖项资源的复杂性,此Fixture系统使开发人员可以轻松配置生成漏洞测试请求序列。

预期直接对象参考

并非所有允许直接对象引用的端点都需要进行身份验证。他们可能只是提供有关正在查询的对象的非敏感信息。例如,考虑我们的开源 Yelp Love 应用程序。该 端点 需要身份验证,但是它返回的详细信息在应用程序上下文中并不敏感。因此,在这种情况下检查IDOR漏洞没有任何意义。
为了解决此问题,我们实施了端点白名单系统,以配置应从fuzz_lightyear扫描中排除哪些端点。这允许开发人员将测试框架配置为仅警告高信号端点,从而最大程度地减少测试脆弱性。

外卖

自动IDOR检测是一项艰巨的任务。即使采用Microsoft启发的状态模糊测试方法,在微服务生态系统中应用此概念仍然存在局限性。为了解决这些问题,我们设计了一个测试框架,使开发人员可以轻松配置动态测试,并将其平稳地集成到我们的CI管道中。这样,我们可以实现连续的自动IDOR覆盖范围,并使开发人员能够独立解决这些问题。
想看看吗?在我们的Github页面上查看有关fuzz-lightyear的更多详细信息 。

贡献者

我要感谢以下人员(按字母顺序排列)在构建此系统以及继续加强Yelp的安全性方面的辛勤工作。