☰
OWASP MASTG 实战:Android 用户界面组件中的敏感数据掩码与防泄漏检测指南
2026/10/7 2:26:53 网站建设 项目流程
  • 文档
  • 教程
  • 网络安全

【免费下载链接】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)中MASVS-STORAGE分类下的「用户界面组件(User Interface Components)」知识条目,系统讲解如何检测与防范 Android 应用在用户界面(UI)中暴露敏感数据的问题。文中不仅继承了 MASTG 对 UI 掩码(masking)要求、肩窥(shoulder surfing)风险的核心定义,还结合仓库中的相关测试用例(MASTG-TEST-0008、MASTG-TEST-0316)、键盘缓存知识条目(MASTG-KNOW-0055)与源码级演示(MASTG-DEMO-0064),给出从静态审查、动态验证到自动化规则检测的完整实战方案。读完本文,你将掌握:敏感输入字段的掩码配置方法(XML、传统 View 体系、Jetpack Compose 三种写法)、inputType位掩码的解码技巧、键盘缓存风险的排查思路,以及如何像安全测试工程师一样对 UI 数据泄露做出 PASS/FAIL 判定。


一、问题背景:UI 中的敏感数据为什么需要掩码

MASTG-KNOW-0052 指出:在某些时间点,用户必然需要在应用中输入敏感信息。这些数据可能是信用卡号、用户账户密码等金融信息,也可能是医疗健康数据。如果应用在输入过程中没有对数据进行适当的掩码处理,这些数据就可能暴露在屏幕上。

具体风险被称为肩窥(shoulder surfing)——攻击者在用户身后或通过摄像头,直接观察屏幕上以明文显示(clear text)的密码、PIN、验证码等敏感输入。MASTG 对该问题的安全要求非常明确:

  • 除非确实需要(例如正在输入密码的瞬间),不得通过用户界面暴露任何敏感数据;
  • 对于必须在界面上呈现的数据,应当进行恰当的掩码(masked),典型做法是用星号(asterisks)或圆点(dots)替代明文。

这正是 MASVS-STORAGE 分类关注 UI 组件的原因:数据泄露不一定只发生在存储层或网络层,屏幕上的一次明文回显同样是一次数据泄露事件。与之对应的旧版测试项 MSTG-STORAGE-7(MASTG-TEST-0008)就是专门用于「检查通过用户界面泄露敏感数据」的。

二、检测方法总览:静态分析与动态分析

MASTG 对 UI 敏感数据泄露的检测遵循「先静态后动态」的两段式流程,这在 MASTG-TEST-0008 与新版测试 MASTG-TEST-0316 中有完整体现。

2.1 静态分析:审查所有相关 UI 组件

静态阶段需要仔细审查所有展示敏感信息或接收敏感输入的 UI 组件,搜索任何敏感信息的痕迹,并评估它应当被掩码还是被完全移除。重点检查对象有两类:

  1. 文本输入字段(Text Fields):确认EditText是否正确配置掩码属性(详见第三节);
  2. 应用通知(App Notifications):在静态评估时,建议搜索NotificationManager类的使用,它可能是某种通知管理行为的迹象。如果使用了该类,下一步需要理解应用是如何生成通知的。这些代码位置可以反馈给动态分析环节,帮助定位应用内可能动态生成通知的位置。

2.2 动态分析:运行应用并触发所有路径

动态阶段的目标是运行应用,找出所有可能泄露信息的组件:

  • 对文本字段:如果信息被掩码(例如输入被替换为星号或圆点),则应用没有向用户界面泄露数据;
  • 对通知:需要遍历整个应用及其所有可用功能,寻找触发通知的方式。注意,某些通知可能需要你在应用之外执行操作才能触发(例如服务器推送)。

在运行应用期间,可以跟踪所有与通知创建相关的函数调用,例如NotificationCompat.Builder的setContentTitle、setContentText。观察最终的调用轨迹,评估其中是否包含敏感信息。

三、文本输入字段的掩码:三种实现方式

在 Android 中,让输入字段显示圆点而非明文的核心手段是配置inputType。MASTG 测试明确给出了三种主流写法。

3.1 XML 布局方式(传统 View 体系)

在布局文件中,为EditText设置android:inputType属性。最经典的值是textPassword,它会令字段以圆点(dots)显示输入字符,从而防止应用把密码或 PIN 明文泄露到界面:

<EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/password_hint" android:inputType="textPassword" />

该示例取自 MASTG-KNOW-0055 中「XML Layouts」小节;MASTG-TEST-0316 对 XML 视图的检测同样以此为判据:

<EditText android:inputType="textPassword" ... />

3.2 程序化设置(Kotlin/Java 代码)

在代码中动态创建输入字段时,可以通过setInputType方法或直接给inputType属性赋值。例如在 Kotlin 中创建一个掩码的 PIN 输入框:

val input = EditText(context).apply { hint = "Enter PIN" inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD }

这里TYPE_CLASS_NUMBER声明数字输入类别,TYPE_NUMBER_VARIATION_PASSWORD声明密码变体,两者按位或组合后即得到与 XML 中numberPassword等价的效果。

3.3 Jetpack Compose 方式

在 Jetpack Compose 中不再直接使用EditText,而是使用TextField/OutlinedTextField等可组合函数,配合keyboardOptions与visualTransformation参数实现同等行为。MASTG-KNOW-0055 给出的密码字段示例:

OutlinedTextField( value = password, onValueChange = { password = it }, label = { Text("Enter Password") }, visualTransformation = PasswordVisualTransformation(), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Password, autoCorrect = false ), modifier = Modifier.fillMaxWidth() )

其中PasswordVisualTransformation()负责掩码输入,KeyboardOptions中的KeyboardType.Password指定密码输入类型,autoCorrect = false关闭自动更正,防止输入联想缓存。

此外,新版测试 MASTG-TEST-0316 特别提及 Jetpack Compose 中更专门的SecureTextField组件:它通过TextObfuscationMode控制掩码行为,默认值是TextObfuscationMode.RevealLastTyped(仅回显最后输入的字符),因此开发者不显式设置也能获得基本掩码:

SecureTextField( // textObfuscationMode defaults to TextObfuscationMode.RevealLastTyped textObfuscationMode = TextObfuscationMode.RevealLastTyped, // or TextObfuscationMode.Hidden ... )

需要特别警惕的是:即便SecureTextField使用默认的RevealLastTyped或被显式配置为RevealLastTyped/Hidden,后续仍可在代码中被程序化改为Visible——这恰恰是 MASTG-TEST-0316 评价阶段重点排查的失败场景之一。

四、深入原理:inputType 位掩码与逆向解码

要判断一个字段是否真正做到了掩码,安全测试者通常面对的是反编译后的代码——此时inputType已变成一串数字(如129、18)。MASTG-KNOW-0055 对此给出了完整的解码方法论。

4.1 inputType 的构成

Android 的inputType属性是类(Class)、变体(Variation)、标志(Flag)三类常量的按位组合:

  • 类常量(TYPE_CLASS_*):定义输入类型大类(文本、数字、电话等);
  • 变体常量(TYPE_TEXT_VARIATION_*等):定义具体行为(密码、邮箱、URI 等);
  • 标志常量(TYPE_TEXT_FLAG_*):附加修饰(禁止联想、多行等)。

例如:

inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD

其中TYPE_CLASS_TEXT = 1、TYPE_TEXT_VARIATION_PASSWORD = 128,组合结果1 or 128 = 129——这就是你在反编译代码中看到的数值。

4.2 常用非缓存/掩码输入类型一览

无论采用哪种实现方式,MASTG 认可的、能禁用联想并阻止缓存的inputType取值如下表(引用自 MASTG-KNOW-0055 与旧版 MASTG-TEST-0006):

XMLandroid:inputType代码InputType常量最低 API 级别
textNoSuggestionsTYPE_TEXT_FLAG_NO_SUGGESTIONS3
textPasswordTYPE_TEXT_VARIATION_PASSWORD3
textVisiblePasswordTYPE_TEXT_VARIATION_VISIBLE_PASSWORD3
numberPasswordTYPE_NUMBER_VARIATION_PASSWORD11
textWebPasswordTYPE_TEXT_VARIATION_WEB_PASSWORD11

关于 minSdkVersion 的注意事项:旧版测试(MASTG-TEST-0006)要求检查 AndroidManifest 中的android:minSdkVersion是否支持所用常量(例如textWebPassword需要 API 11),否则编译产物不会遵循这些输入类型常量,键盘缓存将重新生效。而 MASTG 新版测试明确表示不再检查minSdkVersion,因为测试对象被假定为现代应用——如果你在测试较老的应用,则仍应做此核查(见 MASTG-TEST-0258)。

4.3 反编译数值的快速解码

MASTG-KNOW-0055 给出三组掩码,用按位与即可拆分inputType的数值:

  • TYPE_MASK_CLASS=0x0000000F(提取类部分)
  • TYPE_MASK_VARIATION=0x00000FF0(提取变体部分)
  • TYPE_MASK_FLAGS=0x00FFF000(提取标志部分)

例如用 Python 快速验证:

129 & 0x0000000F # 1 (TYPE_CLASS_TEXT) 129 & 0x00000FF0 # 128 (TYPE_TEXT_VARIATION_PASSWORD)

五、实战演示:MASTG-DEMO-0064 的 PASS/FAIL 判定

仓库中的演示项目 MASTG-DEMO-0064 完整展示了如何用 semgrep 规则自动化检测键盘缓存风险,其样例源码 MastgTest.kt 是理解inputType数值与掩码逻辑的绝佳教材。

5.1 样例代码中的三个字段

showPopup方法创建一个弹窗,内含三个EditText输入字段:

  • password:TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_PASSWORD→ 正确,密码不应被缓存;
  • passphrase:仅TYPE_CLASS_TEXT→ 错误,明文文本类输入允许缓存;
  • PIN:初始为TYPE_CLASS_NUMBER or TYPE_NUMBER_VARIATION_PASSWORD,但紧接着又被input3.inputType = InputType.TYPE_CLASS_NUMBER覆盖 → 错误,覆盖后变为可缓存类型。

5.2 semgrep 规则与输出解码

演示使用MASTG-TOOL-0110(semgrep)并配合仓库规则 rules/mastg-android-keyboard-cache-input-types.yml 运行,规则捕获每一个setInputType调用及其参数。检测输出包含行号、反编译后的对象名、方法名与输入类型数值。随后按位解码:

  • (PASS)129:129 & 0x0000000F = 1(TYPE_CLASS_TEXT)、129 & 0x00000FF0 = 128(TYPE_TEXT_VARIATION_PASSWORD),阻止密码缓存,正确;
  • (FAIL)1:仅TYPE_CLASS_TEXT,明文文本允许缓存。正确值应为129;
  • (FAIL)input3先为18(18 & 0x0000000F = 2即TYPE_CLASS_NUMBER,18 & 0x00000FF0 = 16即TYPE_NUMBER_VARIATION_PASSWORD),本应正确;但反编译代码中存在第二次setInputType(2)(2 & 0x0000000F = 2,TYPE_CLASS_NUMBER),属于可缓存类型,因此判定失败。

这个例子揭示了两点实战要点:一是反向工程中必须检查同一字段是否存在多次setInputType覆盖;二是数值解码是判断掩码是否真正生效的唯一可靠手段。

5.3 查找已被缓存的键盘数据

如果应用没有正确禁用缓存,攻击者(或测试者)可以直接从输入法缓存数据库中找回用户曾输入的敏感字符串。MASTG-KNOW-0055 给出了验证方法:在 passphrase 字段中多次输入某个测试字符串(例如 "OWASPMAS"),随后:

adb shell 'strings /data/data/com.google.android.inputmethod.latin/databases/trainingcachev3.db' | grep -i "OWASPMAS" OWASPMAS@ OWASPMAS@ OWASPMAS%

能在缓存数据库中检索到明文输入,即证明键盘缓存未被正确禁用。该技巧在动态分析阶段可快速确认应用是否存在 UI 输入层面的敏感数据留存。

六、新版测试体系:MASTG-TEST-0316 的完整流程

旧版测试 MSTG-STORAGE-7(MASTG-TEST-0008)已在 MASTG V2 中弃用,由新版测试 MASTG-TEST-0316(App Exposing User Authentication Data in Text Input Fields)取代,并与键盘缓存测试 MASTG-TEST-0258 形成互补。MASTG-TEST-0316 的完整流程如下:

测试目标:验证应用是否正确处理用户输入,确保访问码(密码或 PIN)与验证码(OTP)不在文本输入字段中以明文暴露。

执行步骤:

  1. 使用 MASTG-TECH-0013 对应用进行逆向工程;
  2. 使用 MASTG-TECH-0014 查找相关 API 的调用位置。

观察输出:应得到一份「所有用于访问码或验证码的文本输入字段位置」清单。

评价标准:若发现任何用于访问码/验证码的输入字段未掩码,测试失败。典型失败原因包括:

  • 使用了普通的TextField(Compose 中无掩码的可组合函数);
  • 使用了SecureTextField但配置为TextObfuscationMode.Visible。

进一步验证:由于「哪些字段处理访问码或验证码」取决于上下文,需使用 MASTG-TECH-0023 逐一检查每个报告的位置,确认字段是否处理敏感数据以及是否被正确掩码。

预期的漏报(False Negatives):如果应用使用不依赖标准类(如TextField、SecureTextField)的自定义文本输入控件(例如自定义 UI 框架或游戏引擎中的输入组件),本测试可能产生漏报——这类场景需要人工补充验证。

与之配套的键盘缓存测试 MASTG-TEST-0258(引用知识条目 MASTG-KNOW-0055 与最佳实践 MASTG-BEST-0019)则从另一角度验证:应用是否通过inputType正确配置输入字段,防止键盘缓存密码或个人数据等敏感信息。其检查点包括:布局文件res/layout中的android:inputTypeXML 属性、代码中setInputType方法的调用、以及 Jetpack Compose 中KeyboardOptions的keyboardType与autoCorrect参数。

七、审计清单:快速核查要点

结合上述文档与源码,一次完整的 Android UI 敏感数据掩码审计应覆盖以下核查点:

  1. 输入字段:所有接收密码、PIN、OTP、信用卡号、身份证号的EditText/ Compose 字段是否设置了textPassword/numberPassword/textWebPassword等掩码类型;Compose 是否使用PasswordVisualTransformation或SecureTextField,且TextObfuscationMode未被程序化改为Visible。
  2. 覆盖检查:反向工程中逐一确认同一字段不存在后续setInputType/inputType覆写(参考 MASTG-DEMO-0064 中 PIN 字段被二次赋值的失败案例)。
  3. 键盘缓存:敏感字段是否使用非缓存输入类型(表见第四节),可借助 rules/mastg-android-keyboard-cache-input-types.yml 规则批量扫描,并用adb shell strings抽查输入法缓存数据库。
  4. 通知:应用是否通过NotificationManager/NotificationCompat.Builder在通知标题或正文中暴露敏感明文(检查setContentTitle、setContentText)。
  5. minSdkVersion:若测试老应用,确认所用输入类型常量与android:minSdkVersion匹配(textWebPassword、numberPassword需要 API 11)。

八、总结

MASTG 对用户界面组件的要求可归结为一句话:敏感数据在界面上要么不出现,出现了就必须掩码。从 MASTG-KNOW-0052 的风险定义出发,本文串联了旧版测试 MASTG-TEST-0008 的静态/动态方法论、新版测试 MASTG-TEST-0316 的完整流程、MASTG-KNOW-0055 的位掩码解码原理,以及 MASTG-DEMO-0064 的自动化检测实例。在实际测试中,建议将掩码检查(MASTG-TEST-0316)与键盘缓存检查(MASTG-TEST-0258)配合执行,前者回答「明文是否可见」,后者回答「输入历史是否被留存」,二者共同覆盖 UI 层敏感数据泄露的两个主要面,从而完整对齐 MASVS-STORAGE 的安全目标。

  • 文档
  • 教程
  • 网络安全

【免费下载链接】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
点击查看免费下载
上一篇:PinchTab 安全与信任模型:本地沙箱化浏览器自动化工具的完整安全指南
下一篇:抖音无水印视频下载器:5分钟快速上手,免费批量下载神器!

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

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

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

立即咨询