背景
在现代微服务服务架构转型和企业安全水准越来越高的情况下,传统的安全漏洞越来越少,更多的漏洞集中于越权(IDOR)、并发条件竞争(race condition)这类逻辑漏洞。在 2021 年发布的 OWASP Top 10 里,权限类漏洞风险(Broken Access Control-控制权限失效) 也被列在首位。相比较传统安全漏洞,越权漏洞可能产生的危害更大,影响面更广,例如某个 API 接口可以越权访问其他用户敏感信息,通过遍历就能窃取全站所有用户的信息,某云服务厂商可以越权删除其他用户的服务器…类似案例层出不群。但由于用户权限和企业技术架构强绑定,且随着业务形态越来越复杂,不同用户的权限可能几十上百种,很难有一套通用的方案来解决越权问题。这里我们介绍下陌陌安全是如何通过自动化手段治理越权漏洞的风险。
技术选型
要通过自动化手段治理越权问题,先看看目前已有的安全能力能否满足需求,甲方 SDL 建设中常用的自动化发现漏洞手段有代码扫描(SAST),交互式扫描(IAST)和黑盒扫描(DAST)
- 代码扫描通过 AST 和正则分析代码语句来判断有无漏洞,但主要目的为发现安全漏洞,对于逻辑类漏洞无能为力;
- 交互式扫描通过插桩 Agent,收集堆栈信息来判断是否存在漏洞。由于业务线后端为 Golang,目前插桩 Agent 技术暂未成熟且部署成本过高,固放弃;
- 黑盒扫描为使用 payload 替换参数构造 HTTP 请求,根据返回值和响应信息来判断有无漏洞,理论上是可以可以用来判断有无越权漏洞,但其缺点也很明显:可能由于获取接口不全无法进入代码逻辑、发送大量请求会产生很多垃圾日志和脏数据、很多接口返回信息特征不明显等一系列问题。
作为甲方,可以利用如下内部信息的透明性调整技术方案,联动其他内部平台获取以上信息可以最大限度的弥补传统黑盒扫描的不足,打造一个更适合扫描越权漏洞的黑盒漏洞扫描器。
- 通过网关路由规则,可以知道有多少对外接口
- 通过网关流量,可以知道每个接口的请求和响应是什么
- 通过仓库代码和数据表结构,可以请求参数类型和含义
- 通过链路追踪平台,可以知道请求是经过怎样的内部 RPC 调用、操作缓存和SQL得到最终返回
黑盒扫描流程
最终的扫描流程如图一所示,从 API 网关旁路解析 HTTP 流量后进行预处理、接口打标去重后再推送给扫描引擎进行越权漏洞扫描
图一:整体扫描流程
一、流量预处理
流量预处理的主要目的是填充流量信息和清洗移除无需关注的流量条目。从网关拿到包含有 Request 和 Response 完整流量后,先清洗移除静态资源、错误状态码、外部攻击流量等一系列无需扫描器去关注的流量,再通过网关路由配置匹配当前流量 URL 所属于的后端服务与路由接口信息。添加路由信息时可直接使用网关所用到的路由匹配算法,在 Golang 技术栈中最常用的为基于基数树的优先级路由算法(httprouter),其他语言如 Java 技术栈下也有类似的路由匹配算法(Spring Cloud Gateway)。
图二:httprouter 路由树
在填充路由信息的同时,可以通过敏感数据检测引擎标记请求/返回中包含敏感信息的接口,敏感信息类型可参考公司内部数据安全规范。
二、接口打标去重
想要弥补黑盒扫描的不足,用最少的请求量来发现漏洞,还需要对已填充服务和路由信息的流量做进一步精细化处理。根据返回值特征和公司 REST API 规范尝试判断请求中动态参数类型,如下面 URL
# URLhttp://api.domain.com/v1/users/100/order/76e97bccb2e9ea0c?end=1671528968&limit=10# 网关路由规则Host: api.domain.com Route: /v1/users/:id/order/:oid# 动态参数识别后http://api.domain.com/v1/users/{{user_id}}/order/{{order_id}}?end={{timestamp}}&limit={{limit_number}}在后续替换参数构造请求时可以从已知的 user_id/order_id 中替换对应资源的已知值,不用盲目遍历和猜测参数类型,能很大程度的减少发送请求量。
敏感接口打标和新增接口打标也是类似的作用,对接口根据业务特征和是否是新上线接口做标记,被标记的接口优先扫描和降低疑似漏洞判断阈值。
通过路由规则匹配和动态参数识别后,可以将同类型的 URL 收敛为一条接口,基于此规则做去重后便可用于扫描。
三、漏洞扫描
经过上面处理后的流量才进入真正的扫描,这里我们将越权漏洞按照操作资源类型分为「资源查询类越权」和「资源修改类越权」,分别执行不同的扫描逻辑。
注:关于扫描器的架构和其他类型漏洞的检测本文不做详述,重点介绍越权漏洞扫描相关。
资源读取类越权
查询类越权的定义是能够通过接口获取到其他用户的敏感数据,如果获取到流量中包含敏感数据则执行此扫描逻辑,如下面获取用户账单 orderID 的返回中存在敏感数据手机号字段”phone”:13300000000
// GET https://api.domain.com/v1/users/100/order/76e97bccb2e9ea0c{“meta”:{“code”:200000,“message”:”OK”},“data”:{“users”:{“id”:”100″,“phone”:13300000000,…},“orders”:{…}}}扫描逻辑如下
1、预先建立测试帐号池,并给每个测试帐号创建好资源类型和填充敏感数据。
图三:用户池
2、扫描器 worker 端拿到流量后,从用户池拿测试帐号的认证信息替换登录态构造请求,依据之前识别的动态参数资源类型,替换成用户池中其他帐号的资源 ID 发送请求。
3、如果返回值中包含测试帐号预先设定的敏感数据,则说明此接口存在查询类越权。
资源查询类越权特征明显,依赖外部信息较少,可优先治理这类风险。
资源修改类越权
资源修改类请求以 POST/PUT/DELETE 这些方法为主,响应内容一般较少,很难通过返回值来判断有无越权漏洞。
// 修改订单// POST http://api.domain.com/v1/users/100/order/76e97bccb2e9ea0c{“meta”:{“code”:200000,”message”:”OK”},”data”:””}我们思考一次成功的修改订单请求是如何生效的,请求经过网关和内部服务复杂的判断和调用,最终响应成功是会对数据库或缓存中的订单执行 Update 类操作,那如何知道一个请求是否成功修改了数据库呢?这里介绍 TraceID 概念。
在微服务架构中,一个请求从网关流入,往往会调用多个服务对请求进行处理,拿到最终结果。这个过程中服务之间的通信又是单独的请求,如果请求经过的服务出现故障或反应较慢都会对结果产生影响。为了增强可观测性,能在出现故障时定位到具体服务,就需要为整个系统引入分布式链路追踪。外部请求进入网关后网关会生成一个全局唯一的 traceID,在整个请求的调用链中,请求会一直携带 traceID 往下游服务传递,最终可以通过 traceID 还原出整个请求的调用链路视图。
在链路追踪平台查看上面修改订单请求的调用链路如图四所示
图四:链路追踪平台信息
可以看到经过复杂的服务调用,最终修改订单成功是成功执行 UPDATE SQL 语句。如果此接口存在越权可以修改其他用户的订单信息,说明越权请求的调用链路上也会执行同样的 UPDATE 语句,因此此类越权的检测逻辑如下:
- 在敏感接口打标环节加入链路信息,从链路追踪平台获取原始请求链路信息,如果链路中有对 Cache/DB 的增删改类操作,标记为资源修改类接口,并储存原始调用链路信息
- 扫描器 workers 拿到此类接口后,从用户池替换登录态和参数重放请求,判断响应是否正常。
- 对比新请求和原始请求调用链路是否一致,如果新请求链路上有一样增删改类操作,则说明大概率存在越权,人工复测。
面对不断更新的业务需求和数以万计的接口,通过上面检测可快速缩小存在越权漏洞的接口范围,极大程度的减少人力测试投入。
总结
本文主要介绍了我们基于网关流量和联动内部各个平台来治理越权漏洞的一些实践和方案,目前支持「资源查询类」和「资源修改类」越权的检测。自扫描系统上线以来,已发现多个有价值的漏洞,未来我们也将探索一些更复杂的越权漏洞场景的治理方案,欢迎大家留言评论交流。
参考
- OWASP TOP10:2021 – Broken Access Control
- Meta fined $276 million over Facebook data leak involving more than 533 million users
- AWS ECR Public Vulnerability
- Feei-基于甲方视角的漏洞发现
- Gin HttpRouter GitHub 项目地址
- How Spring Cloud Gateway Works
- KCON 2022 API Fuzz 实践
- Jaeger: open source, end-to-end distributed tracing
还没有评论,来说两句吧...