☰
使用 Semgrep 检测 Android 应用中的非随机源(Non-random Sources):OWASP MASTG-DEMO-0008 实战指南
2026/10/6 12:09:50 网站建设 项目流程
  • 文档
  • 教程
  • 网络安全

【免费下载链接】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 Mobile Application Security Testing Guide(MASTG)通过一系列可复现的 Demo 演示移动应用安全测试的具体手法。本文以 MASTG-DEMO-0008 为骨架,完整讲解如何在 Android 应用中用静态分析工具 semgrep 检测"使用非随机源生成随机值"这一高危密码学缺陷:从漏洞样本代码、semgrep 规则原理、命令行运行方式,到扫描结果的解读与人工复核流程,帮助读者掌握一套可复制到真实项目中的静态安全测试(SAST)实操方案。读完本文,你将能够独立编写并运行针对new Date()、System.currentTimeMillis()、Calendar.get(...)等非随机源的 semgrep 检测规则,并能结合 MASTG 测试用例流程对告警做安全相关性人工研判。

Demo 背景:为什么"非随机源"是密码学弱点

MASTG-DEMO-0008 属于 MASTG 中 MASVS-CRYPTO 类别(移动应用密码学要求)下的演示用例,其关联的测试用例为 MASTG-TEST-0205(Non-random Sources Usage)。该测试用例指出:

Android applications sometimes use non-random sources to generate "random" values, leading to potential security vulnerabilities. Common practices include relying on the current time, such asDate().getTime(), or accessingCalendar.MILLISECONDto produce values that are easily guessable and reproducible.

问题本质在于:时间戳、日历字段等值具有高度可预测性。若开发者在生成加密密钥、初始化向量(IV)、nonce、认证令牌(authentication token)、会话标识(session identifier)、密码或 PIN 时使用了这类"伪随机"来源,攻击者只需掌握生成时间或算法规律,就能推算出这些值,从而绕过认证或解密敏感数据。

这与 MASTG 知识库中的 MASTG-KNOW-0013(Random Number Generation)一脉相承:密码学需要安全的伪随机数生成器(PRNG),标准 Java 类如java.util.Random及时间来源无法提供足够的随机性,可能导致攻击者猜出下一个生成值;正确做法是使用SecureRandom的默认无参构造器(其底层由 AndroidOpenSSL/Conscrypt 提供的SHA1PRNG实现),并遵循最佳实践 MASTG-BEST-0001:"Use a cryptographically secure pseudorandom number generator as provided by the platform or programming language you are using."。

MASTG-DEMO-0008 正是通过一个精心构造的恶意样本,演示如何用 semgrep 自动定位这类"非随机源"代码位置。

样本代码:故意埋入的"非随机随机数"

Demo 的核心样本为 MastgTest.kt,原始 Kotlin 代码如下:

package org.owasp.mastestapp import android.content.Context import java.util.Calendar import java.util.Date class MastgTest (private val context: Context){ fun mastgTest(): String { // SUMMARY: This sample demonstrates different ways of creating non-random tokens in Java. // FAIL: [android-insecure-random-use] The app uses Date().time for generating authentication tokens. val random1 = Date().time.toInt() val c = Calendar.getInstance() // FAIL: [android-insecure-random-use] The app uses Calendar.getInstance().timeInMillis for generating authentication tokens. val random2 = c.get(Calendar.MILLISECOND) return "Generated random numbers:\n$random1 \n$random2" } }

样本在mastgTest()方法中故意使用两种非随机源生成"随机数":

  1. Date().time.toInt():取当前时间戳并截断为Int,用于"生成认证令牌";
  2. Calendar.getInstance()后调用c.get(Calendar.MILLISECOND):取出当前时间的毫秒字段,同样用于"生成认证令牌"。

代码注释中的FAIL: [android-insecure-random-use]明确标注了这两处是预期被检测出的漏洞点。注意两点实践细节:

  • 这类时间来源生成的"随机数"随运行时刻变化,攻击者只要知道大致生成时间就能大幅缩小猜测范围,不具备密码学所需的不可预测性;
  • 样本同时演示了"令牌/安全值生成逻辑被塞进普通方法"的典型反模式,这正是后续人工研判时需要关注安全相关性的原因。

逆向视角:Kotlin 反编译后的 Java 形态

MASTG 的静态分析通常作用在逆向产物而非原始源码上,因此 Demo 提供了反编译版本 MastgTest_reversed.java。该文件是 Kotlin 字节码反编译(含@Metadata注解与Intrinsics检查)后的 Java 代码,核心方法如下:

public final String mastgTest() { int random1 = (int) new Date().getTime(); Calendar c = Calendar.getInstance(); int random2 = c.get(14); return "Generated random numbers:\n" + random1 + " \n" + random2; }

关键观察点:

  • Date().time.toInt()被还原为(int) new Date().getTime();
  • c.get(Calendar.MILLISECOND)被还原为c.get(14)——Calendar.MILLISECOND是编译期常量,值为 14。这意味着在反编译/去混淆后的代码中,常量字段名可能被数值替换,扫描规则需要具备对这种形态的识别能力(本 Demo 规则通过(Calendar $C).get(...)匹配.get(...)调用本身来覆盖这一点);
  • 反编译产物中import java.util.Calendar;、import java.util.Date;依然保留,是 semgrep 能够跨文件识别类型的基础。

Semgrep 规则原理:MASTG 官方非随机源检测规则

MASTG 为这一检测场景提供了现成的 semgrep 规则文件 rules/mastg-android-non-random-use.yml,完整内容如下:

rules: - id: mastg-android-non-random-use severity: WARNING languages: - java metadata: summary: This rule looks for common patterns including classes and methods that represent non-random sources e.g. via `Calendar.MILLISECOND` or `new Date()`. original_source: https://github.com/mindedsecurity/semgrep-rules-android-security/blob/main/rules/crypto/mstg-crypto-6.yaml message: "[MASVS-CRYPTO-1] The application makes use of non-random sources." pattern-either: - patterns: - pattern-inside: $M(...){ ... } - pattern-either: - pattern: new Date() - pattern: System.currentTimeMillis() - pattern: (Calendar $C).get(...)

逐项拆解该规则的检测逻辑:

配置项值作用
idmastg-android-non-random-use规则唯一标识,会出现在扫描结果中
severityWARNING告警级别;非随机源本身是风险信号,是否构成漏洞取决于具体用途(安全相关性)
languagesjava作用于 Java 语言代码(对反编译产物、Java 源码均有效)
message[MASVS-CRYPTO-1] The application makes use of non-random sources.输出到告警信息的说明,直接关联 MASVS-CRYPTO-1 要求
pattern-either三类子模式命中任一模式即告警

核心是pattern-either中的三种非随机源模式:

  1. new Date():直接匹配java.util.Date的无参构造调用;
  2. System.currentTimeMillis():匹配系统当前毫秒时间获取调用;
  3. (Calendar $C).get(...):匹配对任意Calendar实例调用get()方法——这是为了覆盖Calendar.getInstance()之后的各种字段读取(如MILLISECOND、SECOND、MINUTE等)。

同时,外层用pattern-inside: $M(...){ ... }将匹配限定在方法体内部,避免误报类字段初始化等非方法上下文的用法。pattern-either与内层pattern-either的嵌套,实际表达的是:"在任意方法内,若出现new Date()或System.currentTimeMillis()或(Calendar $C).get(...)三者中任意一种,即触发告警"。metadata.summary还给出了规则的语义说明,并标注了该规则源自社区 semgrep 规则集mindedsecurity/semgrep-rules-android-security中的mstg-crypto-6.yaml,便于追踪规则血缘。

从源码结构看,MASTG 将这类规则统一存放在仓库 rules 目录下(如mastg-android-non-random-use.yml、mastg-android-non-random-use相关规则体系),供各 Demo 直接引用,形成"规则即文档、规则可复用"的测试资产模式。

运行步骤:用 Semgrep 扫描反编译代码

Demo 的 run.sh 给出了标准的命令行调用方式:

NO_COLOR=true semgrep -c ../../../../rules/mastg-android-non-random-use.yml ./MastgTest_reversed.java > output.txt

命令分解:

  • NO_COLOR=true:禁用 semgrep 输出的 ANSI 颜色码,便于将结果重定向到文件或接入 CI 日志;
  • semgrep:扫描器本体,MASTG-TOOL-0110 将其定位为"能够扫描 Java、Kotlin 和 Swift 的静态代码扫描器";
  • -c ../../../../rules/mastg-android-non-random-use.yml:指定规则配置文件(路径从 Demo 目录向上四级到达仓库根目录rules/下);
  • ./MastgTest_reversed.java:扫描目标——注意这里是反编译后的 Java 文件,而非原始 Kotlin 源码,体现了真实安全测试"拿 APK 逆向产物做静态分析"的工作流;
  • > output.txt:把扫描报告写入 output.txt。

前置条件:

  • 安装 semgrep(参考 MASTG-TOOL-0110 对应的 semgrep 官方安装方式,如pip install semgrep或各包管理器发行版);
  • 若从零分析一个 APK,通常先按 MASTG-TECH-0013(Reverse Engineering Android Apps)对 APK 进行反编译,得到可供扫描的 Java 代码;
  • 对反编译代码做静态分析时,可进一步参考 MASTG-TECH-0014(Static Analysis on Android)了解通用方法论——该技术页明确以 grep 与 semgrep(@MASTG-TOOL-0110)为静态分析工具示例,并演示了如何用 semgrep 检测new SecureRandom($SEED)这类确定性种子用法。

由于 Demo 中run.sh的规则路径是相对 Demo 目录的(../../../../rules/...),在实际项目中复用时,请将规则路径调整为你的工作目录结构;亦可在仓库根目录直接执行:

semgrep -c rules/mastg-android-non-random-use.yml demos/android/MASVS-CRYPTO/MASTG-DEMO-0008/MastgTest_reversed.java

观察结果:命中报告解读

运行上述命令后得到的 output.txt 内容如下:

┌─────────────────┐ │ 2 Code Findings │ └─────────────────┘ MastgTest_reversed.java ❯❱ rules.mastg-android-non-random-use [MASVS-CRYPTO-1] The application makes use of non-random sources. 22┆ int random1 = (int) new Date().getTime(); ⋮┆---------------------------------------- 24┆ int random2 = c.get(14);

报告解读要点:

  1. 命中数量:共 2 处 Code Findings,与样本中故意埋入的 2 处非随机源一一对应;
  2. 命中规则:rules.mastg-android-non-random-use,即上文分析的规则 ID;
  3. 告警消息:[MASVS-CRYPTO-1] The application makes use of non-random sources.,与规则message字段一致,直接对应 MASVS-CRYPTO-1(密码学实现正确性);
  4. 精确行号定位:
    • 第 22 行int random1 = (int) new Date().getTime();——命中new Date()模式;
    • 第 24 行int random2 = c.get(14);——命中(Calendar $C).get(...)模式,且证实了前文推断:Calendar.MILLISECOND反编译后成为字面量14,规则通过匹配get(...)调用而非常量名,保证了在常量被内联后依然有效。

这个输出正是 MASTG-TEST-0205 中"Observation"所要求的形态:"The output should contain a list of locations where non-random sources are used."——即产出非随机源使用位置的清单,供测试人员逐一定位与后续处置。

评估阶段:对命中点做安全相关性人工研判

MASTG-DEMO-0008 的最后一步是 "Review each of the reported instances"(逐一审查每个报告实例),这一步对应 MASTG-TEST-0205 的 Evaluation 逻辑:

The test case fails if you can find security-relevant values, such as passwords or tokens, generated using non-random sources.

也就是说:静态规则只负责"找位置",是否构成漏洞(测试失败)取决于这些位置是否用于安全相关目的。测试用例给出的人工复核流程如下:

  • 使用 MASTG-TECH-0023(Reviewing Decompiled Java Code)逐一检查每个被报告的位置;
  • 判断生成的值是否用于安全相关用途,例如:
    • 生成加密密钥(cryptographic keys);
    • 生成初始化向量 IV(initialization vectors);
    • 生成nonce;
    • 生成认证令牌(authentication tokens);
    • 生成会话标识(session identifiers);
    • 生成密码或 PIN(passwords or PINs)。

套用到本 Demo:样本代码注释明确写道"generating authentication tokens",即random1、random2被用于生成认证令牌,属于安全相关用途。因此,如果这是真实应用代码,测试结论应为失败——存在使用非随机源生成安全敏感值的漏洞,攻击者可预测令牌值。

若命中的位置仅用于 UI 展示、动画随机偏移、A/B 分流等非安全场景,则规则告警可视为误报/低风险,无需修复——这正是severity: WARNING而非ERROR的原因,也是"静态扫描 + 人工研判"组合的意义所在。

修复方向与最佳实践

确认漏洞后,修复方向遵循 MASTG-BEST-0001 与 MASTG-KNOW-0013 的指导:

  1. 使用SecureRandom默认无参构造器替代一切时间/日历来源,例如:
import java.security.SecureRandom; SecureRandom secureRandom = new SecureRandom(); byte[] token = new byte[32]; secureRandom.nextBytes(token);
  1. 避免向SecureRandom传入确定性种子(如new SecureRandom(seed)),除非种子来源本身具备足够熵;
  2. 关注低版本兼容性:若应用需支持 Android 4.4(API level 19)以下的系统,需注意 Android 4.1–4.3(API 16–18)上 PRNG 初始化缺陷的历史问题(详见 MASTG-KNOW-0013 中引用的官方说明),在初始化阶段做额外加固;
  3. 建立回归防线:将 mastg-android-non-random-use.yml 这类规则接入 CI,让new Date()、System.currentTimeMillis()、Calendar.get(...)出现在安全敏感路径时能被自动拦截,再配合人工 review 判定安全相关性。

总结:从 Demo 到可复用的检测能力

MASTG-DEMO-0008 演示了一条完整的"漏洞样本 → 静态规则 → 命令行扫描 → 结果解读 → 人工研判"链路:

  • 样本(MastgTest.kt)与反编译产物(MastgTest_reversed.java)展示了非随机源的典型写法及其逆向形态;
  • 规则(mastg-android-non-random-use.yml)用pattern-either精准覆盖new Date()、System.currentTimeMillis()、(Calendar $C).get(...)三类模式;
  • 命令(run.sh)演示了 semgrep 的标准调用方式;
  • 输出(output.txt)证明规则在反编译代码上稳定命中两处漏洞点;
  • 研判(对照 MASTG-TEST-0205)明确了"非随机源 + 安全相关用途 = 测试失败"的判定标准。

这套方法完全可以直接迁移到真实项目:把规则文件引入你的扫描配置,针对反编译代码或源码库执行 semgrep,再按安全相关性分级处置告警,即可将 MASTG 的密码学检测能力落地为可持续运行的自动化防线。

  • 文档
  • 教程
  • 网络安全

【免费下载链接】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
点击查看免费下载

相关推荐

上一篇:Docker容器资源限制完全指南
下一篇:神经反馈可视化技术揭秘:NeuroLab Android频谱图与记忆图谱解析

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

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

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

立即咨询