RASP(Runtime Application Self-Protection)——一种直接嵌入到应用程序中并在运行时分析其行为以检测攻击的安全技术。与网络防火墙或 WAF 不同,RASP 从内部工作:它不仅能看到传入的请求,还能看到代码如何处理该请求——调用了哪些函数、从内存中读取了哪些数据、执行了哪些系统调用。根据 OWASP Runtime Protection Project(2025)的数据,RASP 解决方案可在攻击到达易受攻击的代码之前阻止高达 94% 的攻击。RASP 不需要更改基础设施——所有必要的工作都在应用程序进程内完成。
要点
运行时应用自我保护(RASP)——在构建阶段或通过运行时代理集成到应用程序中的安全技术。RASP 在应用程序执行期间分析其行为,并根据上下文做出阻止攻击的决定:调用来源、传输的数据、堆栈状态。与基于签名的系统不同,RASP 不寻找已知的攻击模式——它检测偏离预期代码执行场景的异常行为。
RASP 概念由 Gartner 于 2011 年正式提出,首个商业实现出现在 2014–2015 年。对于移动平台,RASP 从 2017 年开始被积极应用,当时市场意识到传统混淆技术的不足。根据 MarketsandMarkets(2025)的报告,RASP 解决方案市场规模达 28 亿美元,年增长率为 24.5%。OWASP Mobile Top 10 和 PCI DSS 4.0 标准建议处理支付数据的应用程序采用 RASP。
RASP 在两个层面上工作:拦截和评估。拦截——通过在构建阶段或运行时通过动态插桩嵌入到代码中的钩子来拦截系统和库调用。评估——分析调用上下文:检查输入参数、调用栈、沙箱状态、调试器存在性。决策基于开发者设置的安全策略。策略可以是严格的(阻止)、温和的(记录)或自适应的(根据威胁级别改变行为)。
RASP 代理的架构由三个组件组成:插桩层、分析器和策略。插桩层拦截系统调用和框架调用。分析器检查上下文是否与预期模式一致。策略确定反应。
对于移动应用,使用编译时插桩(compile-time):字节码或原生代码在构建阶段被修改——在每个危险调用之前插入检查。RASP 代理的编译器修改 FileOutputStream.write()、Runtime.exec()、Class.forName() 和 android.app.Activity.onStart() 入口点。对于 Android,通过 Gradle 插件进行 DEX 字节码转换;对于 iOS,通过 post-link 脚本修改 Mach-O 二进制文件。
在拦截调用时,RASP 分析:调用类和方法(谁调用)、堆栈跟踪(调用链)、参数(传输的数据)、返回值(返回的内容)、时间戳和线程 ID。当例如 Runtime.exec() 不是从 UI 线程和应用程序代码调用,而是从通过 JNI 以非标准路径加载的库中调用时,会记录异常。或者当 FileOutputStream.write() 接收到的数据包含可执行字节码而不是预期的 PNG 头时。
RASP 支持三种响应类型:Block——检测到攻击时紧急终止应用程序,Log——在不停止应用程序的情况下将事件详情发送到日志收集服务器,Deceive——将返回值替换为假值以使攻击者接收到错误数据。Log 和 Deceive 的组合可以在不透露检测事实的情况下收集有关攻击者的情报。
// 示例:RASP 对 Runtime.exec() 调用的检查
public class RASPAgent {
public static Object onExecCalled(String command,
StackTraceElement[] stack) {
// 检查调用者
String caller = stack[1].getClassName();
// 如果调用不是来自我们的包——可疑
if (!caller.startsWith("com.example.app")) {
SecurityPolicy.reportIncident(
"UNEXPECTED_EXEC", command, stack
);
return SecurityPolicy.getAction().execute(command);
}
// 检查命令是否在黑名单中
String[] blocked = {"su", "frida", "ptrace", "/data/local"};
for (String pattern : blocked) {
if (command.contains(pattern)) {
SecurityPolicy.reportIncident(
"BLOCKED_CMD", command, stack
);
return new Process(); // deceiving:空进程
}
}
return null; // 允许执行
}
}
RASP 经常与 Web 应用防火墙(WAF)进行比较,但根本区别在于定位。WAF 位于网络外围,仅分析 HTTP 请求。RASP 在应用程序内部工作,可以看到处理逻辑。
| 特性 | WAF | RASP |
|---|---|---|
| 位置 | 网络外围 | 应用程序内部 |
| 分析内容 | HTTP 请求 | 系统调用、内存、堆栈 |
| 加密流量 | 需要 TLS 解密 | 解密后可见 |
| 移动攻击 | 不可见(Frida、调试) | 直接检测 |
| 误报 | 高(正则规则) | 中等(上下文分析) |
| 性能影响 | 最小 | 3–7%(取决于分析深度) |
与使代码不可读的混淆(ProGuard、DexGuard)不同,RASP 在攻击利用期间主动检测攻击。混淆是被动保护:如果攻击者花费足够的时间进行逆向工程,代码将被读取。RASP 是主动的:它看到攻击者试图调试应用程序,并在读取到任何代码行之前做出反应。混淆 + RASP 的组合提供了多层保护,其中混淆减慢分析,而 RASP 在插桩阶段中断攻击。
移动 RASP 解决方案针对 Android 和 iOS 的特性进行了调整。与服务器端 Java 应用不同,移动 RASP 代理在有限内存和电池条件下工作,这需要轻量级的插桩。
在 Android 上,RASP 代理通过 Gradle 插件嵌入,该插件在构建阶段修改 DEX 字节码。代理拦截超过 50 个系统调用,包括:Runtime.exec()(用于检测 su 或 Frida 的启动)、Class.forName()(用于识别可疑类的加载)、System.loadLibrary()(用于控制从非标准路径加载原生库)。此外,检查 /proc/self/maps 中是否存在 frida-agent、frida-helper、libinject 和 substrate 库。
在 iOS 上,RASP 通过 Mach-O 二进制文件的后处理实现。由于 Apple 对二进制文件修改的严格要求,iOS 的复杂性更高。代理拦截 fork()、dlopen()、ptrace() 函数的调用,并检查已加载库中是否存在 CydiaSubstrate.dylib。iOS 的 RASP 不能在 App Store 构建中修改代码——仅适用于企业分发。对于 App Store,建议通过 Swift Macro 或 Objective-C method swizzling 使用编译时插桩。
移动 RASP 检测:Frida(通过检查 /proc/self/maps 和 /data/local/tmp/frida*)、Xposed 框架(通过在 ClassLoader 中检查 de.robv.android.xposed.XposedBridge)、JDWP 调试器(通过 Debug.isDebuggerConnected())、模拟器(通过检查 Build.FINGERPRINT、Build.HARDWARE、Build.MODEL)和 AndroidManifest 中的 debuggable 标志。根据 NowSecure Mobile Threat Report(2025)的数据,RASP 代理能检测 89–97% 的 Frida 插桩会话。
在移动应用中部署 RASP 需要配置插桩、定义策略以及与 SIEM 系统集成以收集事件日志。
编译时插桩(compile-time)——在构建阶段修改字节码,不影响运行时性能。运行时插桩(runtime)(通过服务器上的 Java Agent 或客户端上的 Frida)——更灵活,但增加了 5–10% 的开销。对于移动应用,推荐使用编译时方法,因为它不需要持续的网络连接,并且不消耗电池用于分析。
RASP 代理必须与流行的 SDK 正确配合。Firebase Crashlytics、Google Analytics 和 Appsee 不应被阻止。必须为已知库配置白名单。在代理配置中设置例外:如果调用来自 com.google.firebase 类,则跳过检查。白名单随着每次 SDK 发布而更新。
当 RASP 代理检测到 Frida 时:收集上下文(堆栈跟踪、操作系统版本、时间)、以加密形式将数据发送到日志服务器、执行策略(crash、log-only 或 deceive)、递增计数器以确定大规模攻击。来自不同设备的数据在服务器上聚合以识别攻击模式。
class RASPManager {
fun analyzeAndReact() {
val threats = detectThreats()
if (threats.isNotEmpty()) {
val report = ThreatReport().apply {
threats = threats
timestamp = System.currentTimeMillis()
deviceId = DeviceInfo.getHashedId()
stackTrace = Thread
.currentThread()
.stackTrace
.take(10)
.toList()
}
val policy = SecurityPolicy.getPolicy(threats.maxBy { it.severity })
when (policy) {
Policy.BLOCK -> throw SecurityException("Protection triggered")
Policy.LOG -> ServerLogger.sendReport(report)
Policy.DECEIVE -> DeceptionLayer.activate(report)
}
}
}
}
RASP 不是银弹。该技术在设计保护时必须考虑其局限性。
每个被拦截的调用都会增加一次上下文检查。在激进配置下(拦截所有 IO 和 exec 调用),性能可能下降 5–15%。对于移动应用,启动时间至关重要:RASP 初始化在启动时增加 200–500 毫秒。建议进行点式插桩——仅针对关键函数,而非所有可能的函数。在测试阶段必须使用 RASP 代理进行性能分析。
RASP 可能会阻止合法行为:通过网络调用发送错误堆栈的 Firebase Crashlytics 可能被评估为数据泄露;检查设备完整性的 Google Play Integrity API 可能被识别为可疑调用。为减少误报,需要 7–14 天的学习模式,在此期间 RASP 仅记录但不阻止。
如果攻击者获得内核级访问权限(通过内核漏洞利用),RASP 甚至无法信任自己的检查——代理在用户空间中运行,只能看到内核允许其看到的内容。为防止内核级绕过,使用 Secure Boot Chain 检查结合服务器认证。此外,RASP 代理本身必须经过混淆并受到调试保护——否则攻击者将在开始攻击之前删除或禁用 RASP。
常见问题
防病毒软件在操作系统级别工作,根据签名扫描文件和进程。RASP 在特定应用程序内部工作并分析其行为上下文。防病毒软件不知道特定应用程序应该如何工作;RASP 知道,因为它内嵌在应用程序中并看到所有内部调用和状态。
是的,但有局限性。Apple 不允许在 App Store 中修改运行时代码,因此 iOS 版本的 RASP 通过 Swift Macro 使用编译时插桩。通过 Gradle 插件的 Android 版本 RASP 完全兼容 Google Play。两个平台都要求 RASP 不侵犯用户隐私并且在未经同意的情况下不收集数据。
是的,RASP 最初出现在 Java 栈上。Java 代理通过 java.lang.instrument 在 JVM 级别拦截调用。开源解决方案:OpenRASP(百度)和 jRASP。商业解决方案:Contrast Security、Hdiv、Prevoty。对于微服务架构,RASP 被分别部署到每个服务中。
针对移动应用的商业 RASP 解决方案根据应用数量和支持级别每年费用在 3,000 到 15,000 美元之间。OpenRASP(百度)——适用于服务器应用的免费开源选项。移动 RASP SDK 通常与混淆器捆绑销售(DexGuard + RASP、Arxan、Promon)。
测试方法包括:尝试将 Frida 连接到应用程序并检查 RASP 反应、在已 root/越狱的设备上运行应用程序、通过 jadx 反编译 APK 并确认 RASP 代码未被删除。测试工具:Frida、Objection、MobSF(移动安全框架)用于自动化检查。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。