草庐IT

API安全风险主动感知与度量探索

m0l1ce 2023-03-28 原文

0x1 背景

随着应用越来越多,每天大量的代码变更会带来很多潜在的安全风险,如果这些风险没有被挖掘出来带病上线,那我们暴露出去的风险就会越来越多,如何在代码变更后及时的感知到这些风险成为非常重要的事情,只有及时的感知,才能确保风险能得到检测和确认,而目前我们尚没有这样的机制来确保代码变更产生风险时第一时间展示出来并布置更多的跟进处理措施,这样就会不断的有新的风险暴露出去。

0x2 及时全面

当src又又收到外部白帽子提交的漏洞时,复盘大会上我们该怎么说呢?

  1. 这个功能点/api不知道啥时候上线的
  2. 这个功能点当时测试的没问题啊(测试case、测试流量都在呢,那这个为什么没测试到?每个请求对应测试的是哪个类型的漏洞)
  3. 这个漏洞修复了啊,代码不知道啥时候回滚了,orz
  4. 这个当时活太多没来得及测,orz
  5. 自动化工具没有覆盖这个漏洞的检测能力(那么我们的自动化检测工具提供了哪些测试能力能列出来吗,这块的检测能力有改进空间吗?)
以上回复基本都是因为没测到、没来的及测,总结下就是两个很关键的点没有得到保障

  1. 测试覆盖度
  2. 测试时效性
综上,当应用更新时只有及时全面的进行安全测试才能确保应用是相对安全的,那么及时和全面就分别对应测试时效性和测试覆盖度

0x201 测试覆盖度

先说下测试覆盖度,安全测试和业务(质量)测试(QUALITY ASSURANCE)同学的工作性质有点类似,如果有个功能点或者api没测试到根据墨菲定律这个点就很容易会出现问题,那么如何避免这个问题呢,那就是需要有平台有数据来量化测试覆盖度,这个平台有多少api,测试了多少,测试了多少不同类型的case,测试覆盖度依赖于以上数据。

0x202 测试时效性

如果每次研发同学发布了新的代码,安全同学如果都是一年以后来检查这些代码有没有新的风险那安全检测的意义好像就变低了,当然现实中是不可避免的人力不足,比如一个安全同学负责成百上千个应用的安全,如果没有好用的自动化工具那么安全同学其实是很难应付的过来,安全测试的时效性就很难保障,目前集团有非常棒的扫描平台来支持我们做白盒扫描/黑盒扫描,同时目前iast模式的灰盒测试也在推广中了,这些都是非常棒的实践。

0x3 风险度量

度量的目的是让我们能够清楚的知道我们的工作重点应该在哪里,不能为了度量而度量,度量或者分析后面应该跟进很多安全动作,比如新增了接口就需要及时的进行安全测试,这样就能确保每个新增api及时的得到安全测试,这样就能覆盖全部的api,同时保证了时效性。要确保覆盖度,最重要的一点就是我们需要知道我们的分子、分母分别是什么。不同的应用对外提供服务的方式不一样,基于目前B/S、C/S架构来讲,目前绝大多数风险在S端对应的后端应用上,目前对公网开放应用绝大多数还是通过rest-api的方式提供服务,后端服务除了api还有大量的rpc接口,目前来看webx、springboot、nodejs等框架类应用普及率越来越高,那么我们就拿webx为例来分享下如何做到应用风险可见,那我们思考下,一个应用在merge代码的时候可能会带来哪些安全问题,针对使用最多的java应用,我总结了两点

1  更新了pom文件,引入/消除了新的存在问题的二/三方组件
2  api或者api代码调用链发生了变化

理论上只要我们分析出以上两个变更就可以非常清楚的知道一次commit到底会不会带来新的风险,对于一些特殊场景,比如api下线,不仅仅意味着风险的消亡,同样意味着我们需要去更新我们的资产库标记相应的api已下线。

0x301 覆盖率中的变化的分母

要确保一个应用中的api/rpc接口全部得到测试,我们就需要获取到一个应用中包含的全部api/rpc接口,这是我们计算测试覆盖度的分母,而且随着应用代码的迭代这个分母是变化的,这个分母的变化就会带来风险。

pom里更新组件带来的问题目前基于漏洞库已经基本上覆盖掉了,那我们说下第二点 api层面的变更和api调用链的变化


从上图我们举个栗子来讲,先从commit1和commit2来讲下,假设commit1的时候我们通过自动化、人工确认应用是相对安全的了,那我们标记应用当前的状态是 safe,当监控到应用有merge时,也就是应用处于commit2状态时我们通过自动化分析发现api还是3个,但是api2的调用链上某个方法发生了变化,这时候我们就需要标注出当前应用因为代码更新新增的风险是 api2的调用链上某个方法发生变更了,这时候就需要我们去确认是否有新增风险。

再比如commit2到commit3 ,新增了一个api4,这时候 新增的这个api4 就是需要我们去关注的风险。

按照上面的逻辑,我们应该可以把新增的风险梳理出来,主要是防止新增风险慢慢变成存量风险,不积硅步无以至千里,哎,好像不大应景。。。

就像前面说的一个应用对外提供服务基本就两种方式,一个是rest-api,一个是rpc接口,也就是对一个应用而言除去运行环境下,暴露的攻击面就是各种接口了, 这就是一个应用全部的分母,也就是我们保护的对象。
想要梳理一个应用包含哪些api/rpc接口方法有很多,基于流量、AST分析、插桩、swagger插件都是可以的,从源码层面分析最简单的应该是基于AST来获取,针对常规的springboot项目或者pandoraboot项目,通过AST很容易分析出其中的api变化,当然如果做的精致一些可以基于源码输出类似swagger组件输出一样的数据,接口、入参名、入参类型、返回类型、返回如果是一个对象、对象的属性有哪些,这些信息对安全测试而言同样都是非常有用的信息。

0x302 谁来保证分子

要想保证分子是更加接近分母就需要思考以下问题,

  1. 这个应用有多少api?(资产库)
  2. 这些api测试了吗?
    2.1 谁测试的?
    2.2 什么时候测试的?
    2.3 测试时候的代码和现在的代码一样吗?也就是现在的api还是当时的api吗?不会更新了吧?不会回滚了吧?
    2.4 测试记录还在吗?(怎么证明你测了!!!)
    2.5 测试了哪些姿势?(这么敏感的接口居然没测试过越权?自动化工具不支持?)
  3. 代码更新以后风险能感知到吗?
  4. 感知到以后需要哪些能力支持我们去自动化确认这些风险?黑盒、白盒、人工、iast
当前最实际的问题是线上运行的成千上万的应用中包含的漏洞该怎么挖掘出来,同时怎么防止新增风险变成存量风险。这两个问题中更重要的应该是怎么防止新增风险变成存量风险,否则我们就会陷入一直在处理存量风险的困境。那么让新增风险可见就变成了一个非常紧急且重要的事情。要实现风险可见需要几个关键点。

风险可见的关键点:

  1. 自动化分析是否有新增api
  2. 自动化分析原有api调用链以及调用链上各个方法是否有变更
而要实现第二点就需要把每个api对应的调用链和调用链上的各个方法统一存储进来方便进行比对。

0x4 新增风险分析实践

此图为在猿辅导打工时团队产出的脑图(手动感谢andr01la、l4yn3liu、T00ls01)


基于上图拿内部某个应用进行实践,通过实践我们可以输出代码变更时是否有新的api产生,是否有api对应的调用链的变化

0x401 基于ast分析api/rpc接口

0x40101 rest-api

使用AST梳理api可以根据类或者方法注解进行查找,最常见的注解为以下几类

a. @Controller
b. @RestController
c. @ResourceMapping
e. servlet-mapping方式映射url和java类
比如针对以下代码通过分析注解也可以获取到类似swagger的数据输出

package com.xxx.xxxx.xxxx.server.web.ctrl;

import ... ...;

@RestController
@Slf4j
@RequestMapping(value = "/theme")
public class MomentThemeController {

@Autowired
private MomentThemeLogic momentThemeLogic;

/**
* 获取话题详情
* @param themeId
* @return
*/
@ApiOperation(value = "获取话题详情")
@GetMapping(value = "/moment-theme/theme")
public MomentThemeVO getThemeById(@RequestParam(required = true) Long themeId) {
return momentThemeLogic.getById(themeId);
}
}

0x40102 hsf/dubbo

同样的道理hsf/dubbo接口也可以使用ast分析获取到,此处就不举例子了

0x402 调用链关系获取

条条大路通罗马,获取调用链的方式有很多种,现在我用codeql简单的拿某个api演示下获取调用链以后可以做哪些事情
从某个api开始分析

@Verify
@RequestMapping(value = "/contract/buy/quxxxxyxeail.json",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Object queryInfoByEmail(HttpServletRequest request, HttpServletResponse response) throws
TradeCreateaException {

ContractCaontext contraactContext = ContractContaextUtil.buildaContractContext(request);
TradxxeContractPartixxcipantDto retVal= queryxxxxmail.execute(contractContext);
ContraxactContextUtil.outputContractResp(request, contractContext);
return retVal;
}
/contract/buy/queryInfoByEmail.json对应的入口方法是queryInfoByEmail,从该方法做为开始我们通过codeQL获取其调用链上的各个方法

以上我们通过批量、递归操作就可以获取到一个api对应的入口方法开始其中调用链上的各个方法和在代码中的索引值,知道了索引值也就可以从源码中获取到每个方法的代码块和调用位置,就可以获取到类似以下的信息

如此就可以获取到某个应用某个commitid下api对应的调用链信息和每个方法的具体代码了,当应用被更新时,重新执行以上流程就可以获取到在新的commitid下api信息以及调用链信息,对信息进行比对就可以获取到差异,而风险就存在于变化之中。

0x403 产品化

以上我们可以获取到api以及api调用上的变化,那么这些变化就是需要确认的风险点,通过产品或者平台将这些信息展示出来我们就可以很直观的看到风险点,下一步就是确认这些风险是否是需要进一步处理的,最原始的方法就是人工确认,最起码这就有了一个可以做动作的入口。同时如果通过自动化手段可以把api、api调用链变化信息、调用链中每个方法的源码、api测试样例都能在一套平台里展示出来,那都将极大的提升审查漏洞、复核漏洞的效率。

0x5 需要的能力

0x501 API发现能力

一部分通过AST解析获取代码中的api,另一部分来自于流量清洗获取。 这两种方式各有优劣,ast准确率高但是缺少请求样例,流量中解析需要做归一化处理,如果处理不好一个应用下就变成了有十几万API,优势就是有请求样例(request、response),如果ast和流量解析出来的请求能统一起来,那么我们就可以获取到指定应用下有多少api、api入口类和方法、请求样例、对应的响应样例,这样一个应用下基础信息就有了。后续每个api会透出什么信息、是哪类敏感信息就都可以做了。

0x502 检测能力量化

不管是所谓的大厂还是小厂,真正接触过后才知道很多应用其实是根本没有做过安全测试的,有些是没有流量触发不了扫描,有些是post接口担心影响业务不敢扫,假如有了前面的api列表信息,并且黑盒能够标注哪些做过检测了,检测的漏洞类型是什么都记录下来,那么我们就可以很清晰的知道咱们应用哪些漏洞类型还没有做检测,没有做的检测就需要我们黑白盒、安全运营工程师一起努力来打造、提升检测能力;另一方面外部提交漏洞时也可以快速的复盘知道这个api我们内部到底有没有测试到这个api、何时、何人测试的。

0x503 接口变更感知能力

前面同样铺垫过了,所有的变化都是需要能被感知到的,并且需要有能力检测到哪些变更会带来风险,带来的风险需要谁去判断是否真正存在漏洞,谁来卡点?是统一在一个平台比如soc处理,还是需要安全工程师来回切换,比如接口是mtop发布然后就需要去mtop看接口信息、看入参、出参?
是不是可以根据过往数据来分析呢?比如新增了一个api返回的数据类型和另一个已发布接口的数据类型是一样的,比如都是某个Order类型的对象,那是不是就可以作为参考呢?

0x6 总结

以上是最近在安全运营工作中在遇到一些迷惑之处的思考,大佬们有其他意见和建议也可以在下方留言或者wx(m0l1ce)

有关API安全风险主动感知与度量探索的更多相关文章

  1. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  2. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  3. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

  6. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  7. ruby-on-rails - 在 Ruby (on Rails) 中使用 imgur API 获取图像 - 2

    我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path

  8. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  9. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  10. ruby-on-rails - 是否使用 API - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我的公司有一个巨大的数据库,该数据库接收来自多个来源的(许多)事件,用于监控和报告目的。到目前为止,数据中的每个新仪表板或图形都是一个新的Rails应用程序,在巨大的数据库中有额外的表,并且可以完全访问数据库内容。最近,有一个想法让外部(不是我们公司,而是姊妹公司)客户访问我们的数据,并且决定我们应该公开一个只读的RESTfulAPI来查询我们的数据。我的观点是-我们是否也应该为我们的自己

随机推荐