一、前言
携程信息安全部门目前在研究百度 OpenRASP 技术,让它在携程落地进行服务漏洞扫描防护。做安全漏洞测试的同学都知道,用类似黑盒测试工具测试服务漏洞的时候,在测试服务接口的请求上做参数注入的修改,会污染测试服务的数据源,OpenRASP 技术也不例外。
本文主要讲述我们 IAST 漏洞扫描系统中 OpenRASP 在携程快速部署及如何防止流量重放对数据污染的一系列实践经验。让业务部门无感知地发现他们的服务在测试环境中暴露的漏洞。
这里先简单介绍下什么是 IAST,DAST 和 RASP。
IAST:Interactive Application Security Testing,交互式应用安全测试。近实时检测、误报率极低、可定位到代码行数、展示污点调用过程等等,非常适用于敏捷开发和 DevOps 理念。可以在软件的开发和测试阶段无缝集成现有开发流程,让开发人员和测试人员在执行功能测试的同时,无感知的完成安全测试,解决了现有应用安全测试技术面临的挑战。我们该套 IAST 产品中也会尽力体现污点调用过程,偏向代码层。
DAST:Dynamic Application Security Testing,动态应用程序安全测试。在测试或运行阶段分析应用程序的动态运行状态。它模拟黑客行为对应用程序进行动态攻击,分析应用程序的反应,从而确定该 Web 应用是否易受攻击。这种技术主要采用渗透测试,发现应用系统的潜在风险。
RASP:Runtime Application Security Testing,运行时应用安全测试。很多企业在上线前进行漏洞检测,都要求解决高中危漏洞,在业务紧急上线的情况下,低危漏洞往往可以选择性地忽略,DevOps 因为强调速度,这种情况会更多。但是作为一个安全人员或者项目经理,忽略低危漏洞真的放心吗?攻击者可能不会通过这些低危漏洞来直接攻击业务,但是往往会成为攻击链中的一环,获取某些敏感信息等,那 RASP 的作用就是,在运维阶段继续针对性的保护那些被忽略的低危漏洞。
二、挑战
IAST/RASP 的原理在这里就不介绍了,其主要优点就是检测精准。技术是好技术,但要在企业中大规模部署,缺点也很明显:
1)因为在从 IAST agent(OpenRASP)回传的流量会再次通过黑盒扫描工具 DAST(修改请求参数)重放流量,这会给待测试的服务造成数据污染。对于测试人员,这会影响到服务的测试流程,进而影响测试人员在服务里接入 IAST Agent 的意愿。目前业界也没有很好的方案来解决 IAST 黑盒测试产生的脏数据,如新思 seeker 只是通过其他机制减少脏数据的产生。
2)要实现大规模部署,携程集团有几千个应用系统、上万台服务器的适配、测试、部署、维护…推广和维护工作太重。虽然在 c0debreak 大佬团队的努力下,rasp agent 对服务器的性能影响已控制到 3%左右。但在旅游交易系统中,我们也不敢轻易上到生产环境“玩火”,只能将目标锁定在测试环境上。通过 PAAS 发布系统,在 docker 容器的镜像中直接打上 IAST agent 包来部署推广。
3)目前服务落地的数据一般是放到:关系数据库系统,缓存(redis 和 memcache),ElasticSearch,消息队列(kafka,qmq,hermes)中,如何做到流量重放产生的脏数据不落地。关键是落地组件数量多,如何做到一次性一劳永逸地解决掉。
三、找到问题
通常认知是,我们了解到数据落地的组件(DB,redis,ElasticSearch 等)都是通过网络来传送数据的,在这些组件的 java 实现中,我们很自然地就想到他们是使用 java 中套接字 Socket 来发送数据的,所以研究方法就是在 Socket 上做文章。
如何证实我们的猜测呢?那就是在这些落地组件读写数据时,通过 java 方法调用链是否能找到 Socket 的读写方法。
我们用到字节码操作工具 byte buddy,实现 java 方法调用链展示,主要跟踪了以下数据落地组件发送数据的调用链。
另一种方法就是本地调试看这些落地组件是否运行了 Socket 对象的输出流写数据的方法。
四、IAST 部署架构及数据污染的处理方案
IAST/DAST 部署架构
在携程实践的 IAST(agent 被动检测+分布式扫描器主动扫描)分为下面 4 个部分:
1)IAST agent
集成到测试环境应用 docker 容器的 agent,hook tomcat 底层调用,用来检测应用中的漏洞,同时会把所有访问到应用 docker 的 http 流量复制回传到用于收集流量的 kafka 消息队列。
2)IAST 服务管理端
管理 IAST agent 和漏洞详情展示统计分析的控制台。
3)流量回传的 kafka 消息队列
用于收集待扫描的流量,除了从 IAST agent 回传的流量,还有来自主动爬虫、chrome 插件以及提测平台调用 api 发送过来的流量。
4)分布式扫描器
消费 kafka 里的流量并且按照 url 去重,调用扫描器进行漏洞扫描。
这样一套架构的好处在于:
扫描覆盖率高:只要正常功能测试能覆盖的流量都能被扫到
漏洞检出率高:IAST+DAST 双重检测
误报率低:IAST 的特性决定的低误报
这套扫描系统在少量应用灰度期间就发现了内部存在已久未被发现的通用型漏洞,对于内部安全检测能力的补齐提供了很好的帮助。
IAST 流量重放产生数据污染的处理方案
利用 JDK Instrumentation API 我们可以提供一个 Agent 代理用来监测和协助运行在 JVM 上的程序,可以在程序启动前修改类的定义。简单来说就是在运行的应用中织入一个我们的程序。而在这个程序中我们就拥有了获取当前应用的上下文,在应用运行中实时分析数据流以及调用栈的能力。
插桩技术是在保证目标程序原有逻辑完整的情况下,在特定的位置插入代码段,从而收集程序运行时的动态上下文信息。在 Java 中插桩通过 Instrument 以及字节码操作工具(如:ASM,Javassist,Byte Buddy 等)实现。Instrumentation 会使用类 ClassFileTransformer 的 transform 方法对 jvm 中的未加载的类进行重写。已经加载过的类可以使用 retransform 去进行重写。
IAST agent 技术其实主要就是对编程语言的底层函数进行插桩 hook,毕竟再怎么编码转换以及调用,最后肯定会去执行最底层的某个方法然后对系统进行调用。由此可以反推出其 hook 点。在第三小节,我们了解到数据落地组件是在网络层发送数据包的,我们就在 Socket 输入输出流上的读写方法进行字节码操作插桩 hook 拦截处理。
下图展示的是 iast agent 启动加载处理脏数据的流程,关键点是通过字节码操作工具在程序里使用 SocketOutputStream 输出流对象调用方法 write 之前,加入代码判断是否是安全重放的流量,进行拦截发送的脏数据,并重定向到特定提示页面。
重放拦截关键代码如下:
五、总结
字节码操作技术能解决很多其他场景的问题,如 IntelliJ Idea 的代码调试 Debug,应用热部署等。本文主要讲述的就是在 Socket 输入输出流的方法上,进行字节码修改插桩来防止脏数据落地。
对于在 java 中使用 BIO 流(Block Input/Output,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序)进行通信的组件(关系型数据库 MySql DB,redis)来插装 hook SocketOutputSteam 的 write 写数据方法,隔离避免脏数据的产生,不影响服务的测试流程。这种字节码操作技术能拦截所有使用 Socket 流来发送接收的数据。
作者介绍:
Eric,携程资深开发工程师,关注应用安全、渗透测试方面的技术和相关开源产品的二次开发。
本文转载自公众号携程技术(ID:ctriptech)。
原文链接:
评论