JavaAgent
JDK1.5 开始引入了 Agent 机制 (即启动 java 程序时添加 -javaagent 参数”, 如 java -javaagent:/data/test.jar LingXeTest),Java Agent 机制允许用户在 JVM 加载 class 文件的时候先加载自己编写的 Agent 文件,通过修改 JVM 传入的字节码来实现注入 RASP 防御逻辑。这种方式因为必须是在容器启动时添加 jvm 参数,所以需要重启 Web 容器。JDK1.6 新增了 attach 方式 (agentmain),可以对运行中的 java 进程附加 agent。使用附加的方式可以在容器运行时动态的注入 RASP 防御逻辑。
Java
IAST
概念比较
| 概念 | 描述 | 备注 |
|---|---|---|
| SAST | 静态应用程序安全测试,在编码阶段分析应用程序的源代码或二进制文件的语法、结构、过程、接口等来发现程序代码存在的安全漏洞。 | 白盒测试 |
| DAST | 动态应用程序安全测试,模拟黑客行为对应用程序进行动态攻击,分析应用程序的反应,从而确定该 Web 应用是否易受攻击。 | 黑盒测试 |
| IAST | 交互式应用程序安全测试,通过 Web 应用服务端部署运行时插桩、终端流量代理/VPN、旁路流量镜像及部署主机 Agent流量嗅探软件等,收集、监控 Web 应用程序运行时函数执行、数据传输,并与分析引擎端进行实时交互,高效、准确的识别安全缺陷及漏洞。 | 灰盒测试 |
运行时插桩模式
主动插桩技术需要在被测试应用程序中部署插桩探针,使用时需要外部扫描器去触发这个 Agent。一个组件产生恶意攻击流量,另一个组件在被测应用程序中监测应用程序的反应,由此来进行漏洞定位和降低误报。
主动插桩
- 被测试服务器中安装 IAST 插桩探针;
- DAST Scanner 主动发起扫描测试;
- IAST 插桩探针追踪被测试应用程序在扫描期间的反应,并动态分析测试覆盖率和上下文。当当定位到具体漏洞信息时,将有关信息发送给管理控制台,控制台展示安全测试结果。
被动插桩
- 被测试服务器中安装 IAST 插桩探针;
- 插桩探针在应用程序运行时获取请求和代码数据流、代码控制流,进行动态污点追踪;
- 当定位到具体漏洞信息,插桩探针将获取的信息发送给管理控制台,控制台展示应用安全测试结果。
不会主动对 Web 应用程序执行攻击,而是纯粹被动地分析检测代码。
终端流量代理模式
不需要装agent,安全测试会产生一定的脏数据。

RASP
运行时应用程序自我保护,它的实现方式是通过Instrumentation编写一个agent,在 agent 中加入 hook 点,当程序运行流程到了 hook 点时,将检测流程插入到字节码文件中,统一进入JVM中执行。RASP需要能修改.class文件并且在JVM解释执行的时候注入保护程序。

Java部署的两种方式
一个代理实现ClassFileTransformer接口用于改变运行时的字节码class File,这个改变发生在jvm加载这个类之前。对所有的类加载器有效。
class File这个术语定义于虚拟机规范3.1,指的是字节码的byte数组,而不是文件系统中的class文件。
premain方式
允许在main开始前修改字节码,也就是在大部分类加载前对字节码进行修改。
实现方式:
通过修改 Tomcat、Jetty 和 Springboot 等的启动脚本,给JVM增加 javaagent 参数来让JVM加载一个Java Agent
1 | java -javaagent:/path/to/your/agent.jar -jar XXX.jar |
知道 web 容器的安装路径
具体代码:
创建PreTest.jar
1 | public class test { |
创建PreAgent.jar
1 | import java.lang.instrument.Instrumentation; |
运行java -javaagent:PreAgent.jar -jar PreTest.jar

agentmain方式
允许在main执行后通过com.sun.tools.attach的Attach API attach到程序运行时中,通过retransform的方式修改字节码,也就是在类加载后通过类重新转换(定义)的方式在方法体中对字节码进行修改,其本质还是在类加载前对字节码进行修改。
实现方式:
RASP 守护进程发现了 Java 进程之后,对Java进程依赖的jar包进行分析,从对象存储服务下载对应 jar 包的插件到目标主机上,然后 attach 到目标 JVM 上,目标 JVM 在初始化一个 **轻量级的 Agent (仅一个类)**,最后动态加载核心插件 jar 包。
MANIFEST.MF参数
1 | Premain-Class: 包含 premain 方法的类(类的全路径名) |
需要修改已经被JVM加载过的类的字节码,那么还需要设置在
MANIFEST.MF中添加Can-Retransform-Classes: true或Can-Redefine-Classes: true。
两者区别
agent运作模式不同:premain相当于在main前类加载时进行字节码修改,agentmain是main后在类调用前通过重新转换类完成字节码修改。可以发现他们的本质都是在类加载前完成的字节码修改,但是premain可以直接修改或者通过redefined进行类重定义,而agentmian必须通过retransform进行类重新转换才能完成字节码修改操作。
部署方式不同:由于agent运作模式的不同,所以才导致premain需要在程序启动前指定agent,而agentmain需要通过Attach API进行attach。而且由于都是在类加载前进行字节码的修改,所以如果premain模式的hook进行了更新,就只能重启服务器,而agentmain模式的hook如果进行了更新的话,需要重新attach。
两者缺陷
- premain:每次修改需要重启服务。
- agentmain:由于attach的运行时中的进程,因JVM的进程保护机制,禁止在程序运行时对运行时的类进行自由的修改,具体的限制如下:
- 父类应为同一个类
- 实现的接口数要相同
- 类访问符要一致
- 字段数和字段名必须一致
- 新增的方法必须是
private static/final的 - 可是删除修改方法
通过动态污点跟踪,基于词法分析的漏洞检测解决如何跟踪信息流,如何检测安全性两个问题。






