☰
使用 semgrep 检测 Android 安全锁屏 API:基于 OWASP MASTG 的 KeyguardManager 与 BiometricManager 静态分析实战
2026/10/6 15:59:06 网站建设 项目流程
  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

项目地址:https://gitcode.com/gh_mirrors/ow/mastg
点击查看免费下载

本指南以 OWASP MASTG 仓库中的 MASTG-DEMO-0028 演示为核心,完整讲解如何通过 semgrep 静态扫描 Android 应用中对KeyguardManager.isDeviceSecure与BiometricManager.canAuthenticate的调用,从而验证设备访问安全策略(Device-Access-Security Policy)。读完本文,你将掌握 MASTG 中"检测安全锁屏 API 引用"测试(MASTG-TEST-0247)的完整落地流程:从规则文件、样本源码、反编译产物到命令行执行与结果判定。

为什么需要检测安全锁屏 API

处理敏感信息的移动应用应运行在可信且安全的环境中。为此,应用可以通过查询系统状态来实施"设备访问安全策略",检查项通常包括:PIN/密码保护的设备锁定、较新的 Android 系统版本、USB 调试是否开启、设备加密状态以及设备是否被 Root 等。

在 MASTG V1 中,这一主题由 MASTG-TEST-0012(MSTG-STORAGE-11,Level 2)覆盖;该测试在 MASTG V2 中已被弃用,并拆分为 MASTG-TEST-0247 与 MASTG-TEST-0249 两个新测试。MASTG-TEST-0247 的核心论断是:

如果应用不调用任何 API 来验证安全锁屏是否存在,则该测试失败。

换句话说,一个宣称"只在有安全锁屏的设备上运行"的应用,其代码中必须出现可验证的 API 引用痕迹——这正是本演示要回答的问题:如何用静态分析工具自动找出这些引用?

样本程序:两种 Android 安全锁屏检测 API

演示样本位于 MastgTest.kt,是一个用 Kotlin 编写的MastgTest类,封装了两种互补的检测手段:

package org.owasp.mastestapp import android.app.KeyguardManager import android.content.Context import android.hardware.biometrics.BiometricManager import android.os.Build class MastgTest(private val context: Context) { fun mastgTest(): String { val isLocked = isDeviceSecure(context) val biometricStatus = checkStrongBiometricStatus() return "Device has a passcode: $isLocked\n\n" + "Biometric status: $biometricStatus" } fun isDeviceSecure(context: Context): Boolean { val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager return keyguardManager.isDeviceSecure } fun checkStrongBiometricStatus(): String { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val biometricManager = context.getSystemService(BiometricManager::class.java) val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) return when (result) { BiometricManager.BIOMETRIC_SUCCESS -> "BIOMETRIC_SUCCESS - Strong biometric authentication is available." BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> "BIOMETRIC_ERROR_NO_HARDWARE - No biometric hardware available." BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> "BIOMETRIC_ERROR_HW_UNAVAILABLE - Biometric hardware is currently unavailable." BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> "BIOMETRIC_ERROR_NONE_ENROLLED - No biometrics enrolled." else -> "Unknown biometric status: $result" } } else { return "Strong biometric authentication check is not supported on this API level." } } }

检测路径一:KeyguardManager.isDeviceSecure

isDeviceSecure(context)通过context.getSystemService(Context.KEYGUARD_SERVICE)获取KeyguardManager实例,然后读取其isDeviceSecure属性。该方法返回布尔值:true表示设备已设置 PIN、图案或密码等安全锁屏,false表示设备未设置任何安全锁。这是判断"设备是否被锁定保护"最直接、最经典的方式。

检测路径二:BiometricManager.canAuthenticate

checkStrongBiometricStatus()使用BiometricManager检查强生物识别(指纹、人脸、虹膜)是否可用且已录入凭据。代码中对 API 级别做了显式门槛:Build.VERSION.SDK_INT >= Build.VERSION_CODES.R(即 Android 11 / API 30 及以上),低于该级别直接返回"不支持"。

返回值语义如下表:

常量数值(反编译产物中可见)含义
BIOMETRIC_SUCCESS0强生物识别可用
BIOMETRIC_ERROR_HW_UNAVAILABLE1生物识别硬件当前不可用
BIOMETRIC_ERROR_NONE_ENROLLED11未录入任何生物识别凭据
BIOMETRIC_ERROR_NO_HARDWARE12无生物识别硬件

补充原理:由于 Android 的生物识别认证以安全锁屏为兜底(fallback),BiometricManager.canAuthenticate可以充当KeyguardManager不可用或受设备厂商限制时的替代检查。但需要注意——应用无法在系统层面强制用户开启生物识别,只能通过 BiometricPrompt 声明了android.permission.USE_BIOMETRIC权限,这是使用生物识别 API 的必要前提。

semgrep 规则:如何精确匹配这两类 API 调用

本演示使用 semgrep(MASTG-TOOL-0110,一款可扫描 Java、Kotlin 与 Swift 的静态代码扫描器)执行规则 mastg-android-device-passcode-present.yml。规则全文如下:

rules: - id: mastg-android-device-passcode-present languages: - java severity: INFO metadata: summary: This rule searches for API that checks whether the device passcode is set. message: "[MASVS-STORAGE] Make sure to verify that your app runs on a device with a passcode set" pattern-either: - pattern: | $X.getSystemService("keyguard"); ... $Y.isDeviceSecure(); - pattern: | BiometricManager $BM = (BiometricManager) $X.getSystemService(BiometricManager.class); ... $BM.canAuthenticate($VAL);

规则设计要点

  • languages: [java]:规则目标语言为 Java。由于实际扫描的是反编译后的 Java 代码(MastgTest_reversed.java),这一设定与工作流完全匹配;
  • severity: INFO:该规则定位为信息级提示,用于"确认存在"而非"标记漏洞",这与 MASTG-TEST-0247 的测试目标(找出 API 引用)一致;
  • pattern-either:两个模式取任一命中即触发。模式一用$X.getSystemService("keyguard")配合后续$Y.isDeviceSecure()匹配 KeyguardManager 检查;模式二用BiometricManager的类型转换与服务获取配合canAuthenticate($VAL)匹配生物识别检查。模式中的$X、$Y、$BM、$VAL是 semgrep 的元变量(metavariable),...表示允许中间存在任意代码段——这正是静态分析"放宽上下文、聚焦关键调用对"的典型写法;
  • message:命中时输出的提示文案,标注了对应的 MASVS 控制域(MASVS-STORAGE),提醒开发者确认应用确实运行在设置了密码(passcode)的设备上。

实战步骤:对反编译产物执行 semgrep 扫描

演示的运行脚本 run.sh 只有一条命令:

NO_COLOR=true semgrep -c ../../../../rules/mastg-android-device-passcode-present.yml ./MastgTest_reversed.java > output.txt

命令各参数含义:

参数作用
NO_COLOR=true禁用终端颜色输出,保证结果文件为纯文本,便于后续处理与归档
semgrep调用 semgrep 扫描器(MASTG-TOOL-0110)
-c <规则文件>指定要加载的 YAML 规则文件(-c即--config)
./MastgTest_reversed.java扫描目标:反编译后的 Java 源码文件
> output.txt将扫描结果重定向写入文件

为什么扫描的是反编译后的 Java?

工作流遵循 MASTG 标准的静态分析流程:先用逆向工程技术(对应 MASTG-TECH-0013)将 APK 反编译,再在反编译产物上搜索相关 API(对应 MASTG-TECH-0014)。仓库中同时保留了 MastgTest_reversed.java 这一反编译产物——它由 Kotlin 字节码反编译而来,可读性与 Java 源码几乎一致。从中可以清楚地看到 Kotlin 源码是如何被"翻译"成 Java 语义的:

public final boolean isDeviceSecure(Context context) { Intrinsics.checkNotNullParameter(context, "context"); Object systemService = context.getSystemService("keyguard"); Intrinsics.checkNotNull(systemService, "null cannot be cast to non-null type android.app.KeyguardManager"); KeyguardManager keyguardManager = (KeyguardManager) systemService; return keyguardManager.isDeviceSecure(); } public final String checkStrongBiometricStatus() { if (Build.VERSION.SDK_INT >= 30) { BiometricManager biometricManager = (BiometricManager) this.context.getSystemService(BiometricManager.class); int result = biometricManager.canAuthenticate(15); // switch (result) { ... } } return "Strong biometric authentication check is not supported on this API level."; }

几个值得注意的细节:

  1. Kotlin 的isDeviceSecure属性访问被编译为keyguardManager.isDeviceSecure()方法调用;
  2. context.getSystemService(Context.KEYGUARD_SERVICE)被编译为context.getSystemService("keyguard")字符串形式,这正是规则模式一中的匹配锚点;
  3. BiometricManager.Authenticators.BIOMETRIC_STRONG编译为整型常量15,在规则中由元变量$VAL匹配;
  4. Kotlin 编译器插入了Intrinsics.checkNotNullParameter/Intrinsics.checkNotNull空值检查,反编译产物中保留了@Metadata注解——这些都属于静态分析时需要辨别、但在本规则命中范围内无碍的"噪音"。

观察结果:两条命中的输出解析

扫描结束后,output.txt 记录了完整的 semgrep 报告:

┌─────────────────┐ │ 2 Code Findings │ └─────────────────┘ MastgTest_reversed.java ❱ rules.mastg-android-device-passcode-present [MASVS-STORAGE] Make sure to verify that your app runs on a device with a passcode set 30┆ Object systemService = context.getSystemService("keyguard"); 31┆ Intrinsics.checkNotNull(systemService, "null cannot be cast to non-null type android.app.KeyguardManager"); 32┆ KeyguardManager keyguardManager = (KeyguardManager) systemService; 33┆ return keyguardManager.isDeviceSecure(); ⋮┆---------------------------------------- 38┆ BiometricManager biometricManager = (BiometricManager) this.context.getSystemService(BiometricManager.class); 39┆ int result = biometricManager.canAuthenticate(15);

报告共产生2 条 Code Findings,全部命中在MastgTest_reversed.java:

  • 命中 1(第 30–33 行):getSystemService("keyguard")到keyguardManager.isDeviceSecure()的调用链,对应KeyguardManager安全锁屏检查;
  • 命中 2(第 38–39 行):getSystemService(BiometricManager.class)到canAuthenticate(15)的调用链,对应强生物识别可用性检查。

每条命中都同时给出了触发规则的 message([MASVS-STORAGE] Make sure to verify that your app runs on a device with a passcode set)与精确到行的源码上下文,方便审查者直接定位代码位置。

结果评估:测试通过的标准

演示给出的判定结论是:测试通过(pass)。判定依据完全来自扫描输出中对安全锁屏 API 的引用证据,具体为:

  • KeyguardManager.isDeviceSecure—— 出现在反编译产物的第 33 行(return keyguardManager.isDeviceSecure(););
  • BiometricManager.canAuthenticate—— 出现在第 39 行(int result = biometricManager.canAuthenticate(15);)。

这与 MASTG-TEST-0247 的评估标准严格对应:测试失败的条件是"应用未使用任何 API 验证安全锁屏是否存在";一旦扫描器在反编译代码中确认了上述任一(或全部)API 引用,即可判定为通过。本样本同时覆盖了两条检测路径,属于完整达标的实现。

延伸思考:从静态证据到安全结论

从源码结构看,本演示还揭示了移动安全测试中的两层思维:

  1. 证据链闭环:MASTG 的演示(DEMO)与测试用例(TEST)一一对应——DEMO 提供可复现的样本与命令,TEST 给出测试目标与判定标准,规则(rules)则封装了可移植的检测逻辑。三者共同构成"规则驱动、样本验证、结果可审计"的静态分析工作流;
  2. "有引用"≠"已强制":本测试只验证 API 引用是否存在(静态证据),并不验证应用是否真正执行了这些检查并据此阻断敏感操作(动态行为)。如需验证检查是否可被绕过,应进一步结合动态分析(对应原 MASTG-TEST-0012 中"若检查可被绕过则必须验证"的说明)。实践中,审查者还应核对应用是否通过BiometricPrompt强制生物识别认证、是否将认证与 Android KeyStore 密钥访问绑定,才能形成完整的设备访问安全评估。

参考资源

  • 演示文档:MASTG-DEMO-0028
  • 样本源码:MastgTest.kt / MastgTest_reversed.java
  • 运行脚本与结果:run.sh / output.txt
  • semgrep 规则:mastg-android-device-passcode-present.yml
  • 对应测试用例:MASTG-TEST-0247(V2)与已弃用的 MASTG-TEST-0012(V1,MSTG-STORAGE-11)
  • 工具与技术背景:MASTG-TOOL-0110(semgrep)、MASTG-TECH-0108(Taint Analysis)
  • 文档
  • 教程
  • 网络安全

【免费下载链接】mastg

The OWASP Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes technical processes for verifying the OWASP Mobile Security Weakness Enumeration (MASWE) weaknesses, which are in alignment with the OWASP MASVS.

项目地址:https://gitcode.com/gh_mirrors/ow/mastg
点击查看免费下载

相关推荐

上一篇:三步搞定《明日方舟》公开招募:MAA智能助手让你的招募效率提升300%
下一篇:大麦自动抢票工具实操指南:环境安装、配置拆解与排错一次讲清

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询