ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OWASP MASTG 演示实战:使用 WebStorage API 清理 Android WebView 敏感数据(MASTG-DEMO-0082 完整复现与原理剖析)

OWASP MASTG 演示实战:使用 WebStorage API 清理 Android WebView 敏感数据(MASTG-DEMO-0082 完整复现与原理剖析) 文档教程网络安全【免费下载链接】mastgThe 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 MASTGMobile Application Security Testing Guide仓库中的动态分析演示 MASTG-DEMO-0082 展开它展示了一个会向 WebView 的 localStorage 写入令牌与驾照编号等敏感数据的 Android 应用以及应用如何在生命周期回调中调用WebStorage.deleteAllData()完成清理并配套给出基于 Frida 的运行时验证方案。读完本文你将掌握WebView 存储区域有哪些、如何用 Frida 挂钩清理 API、如何用 adb 在app_webview目录中验证敏感数据残留这一整套可复用的动态测试方法并能独立判断目标应用是否满足 MASTG-TEST-0320 的判定标准。一、背景WebView 敏感数据残留为什么值得测试Android 的 WebView 基于 Chromium 内核自 Android 4.4 起每个应用拥有自己独立的 WebView 存储区不与其他应用共享。绝大多数 Web 相关数据都落在 Chromium profile 目录中/data/data/app_package/app_webview/按照 MASTG-KNOW-0018WebViews 的归纳WebView 会按 origin 持久化以下几类数据缓存网络资源服务器返回带Cache-Control/Expires等缓存头时产生存在内存与磁盘上的 Chromium cache 中DOM 存储localStorage与sessionStorageWebSQL在现代 WebView 中已移除IndexedDB与Origin Private File SystemOPFS由 Chromium 内部管理不以普通文件形式出现在应用沙箱里Cookies包括会话 Cookie 与持久 Cookie。如果应用在 WebView 中处理了敏感数据令牌、证件号、交易信息等却不清理这些数据就会在设备上留存超出必要的时间构成MASWE-0001敏感数据泄漏/过度留存类弱点。这正是 MASTG-TEST-0320WebViews Not Cleaning Up Sensitive Data 要验证的核心问题应用启用哪些存储区域、是否在不再需要 WebView 时调用了对应的清理 API。测试用例明确列举了需要关注的启用 API ↔ 清理 API配对关系启用的存储能力对应的清理要求WebSettings.setAppCacheEnabled()或setCacheMode()非LOAD_NO_CACHE调用WebView.clearCache(includeDiskFiles true)WebSettings.setDomStorageEnabled(true)DOM 存储调用WebStorage.deleteAllData()WebSettings.setDatabaseEnabled(true)数据库调用WebStorage.deleteAllData()CookieManager.setAcceptCookie()未显式设为false默认开启调用CookieManager.removeAllCookies(...)注意无论应用自身是否显式调用这些 APIWebView 在渲染页面例如页面里的 JavaScript 使用localStorage时都可能在内部用到它们因此测试既要追踪相关 API 调用也要检查文件系统层面的实际残留。二、演示样本应用如何制造脏数据本演示的应用源码位于 demos/android/MASVS-PLATFORM/MASTG-DEMO-0082包含三个核心文件MainActivityWebView.ktActivity在onStop()生命周期回调中执行清理MastgTestWebView.ktWebView 配置与内联 HTML负责写入敏感数据AndroidManifest.xml声明INTERNET权限与入口 Activity。2.1 在生命周期回调中执行清理清理动作发生在 MainActivityWebView.kt 第 40-43 行override fun onStop() { WebStorage.getInstance().deleteAllData() super.onStop() }选择onStop()作为清理时机是经过考量的当用户离开当前 Activity例如按下返回、跳转其他页面时系统会调用onStop()此时 WebView 已不再需要展示正是清除其存储数据的合理窗口。这也是 MASTG-BEST-0028 建议的在 WebView 不再需要时清理实践的一种落地方式。2.2 WebView 配置与敏感数据写入MastgTestWebView.kt 负责配置 WebView 并注入页面SuppressLint(SetJavaScriptEnabled) fun mastgTest(webView: WebView) { webView.apply { settings.apply { javaScriptEnabled true // 启用 JS domStorageEnabled true // 启用 DOM 存储localStorage 的前提 } addJavascriptInterface(AndroidBridge(), Android) // 暴露给页面的 JS 桥 ... loadDataWithBaseURL(https://mas.owasp.org/, html, text/html, utf-8, null) } }关键细节domStorageEnabled true与javaScriptEnabled true是页面脚本能够使用localStorage的前提同时也就此启用了 DOM 存储这一存储区域——按 MASTG-TEST-0320 的判定逻辑启用后就必须配套清理loadDataWithBaseURL(https://mas.owasp.org/, ...)指定了 base URL为内联 HTML 定义了 localStorage 的 origin数据才会真正写入磁盘上的 LevelDBaddJavascriptInterface(AndroidBridge(), Android)注入一个 JS 桥页面上倒计时结束后调用Android.closeApp()桥接方法内部通过runOnUiThread { activity.finish() }关闭 Activity从而触发onStop()清理路径。2.3 页面写入的敏感数据内联 HTML 通过页面脚本写入两条敏感数据MastgTestWebView.kt 第 60-63 行localStorage.setItem(sensitive_token, SECRET_TOKEN_123456); localStorage.setItem(driving_license_id, DL-987654321);sensitive_token→SECRET_TOKEN_123456令牌类敏感数据driving_license_id→DL-987654321个人身份类敏感数据页面随后显示 10 秒倒计时结束后调用Android.closeApp()关闭应用。这两条字符串将贯穿全文Frida 挂钩用于观察清理 API 的调用adb 搜索则用于验证数据是否真的从磁盘消失。三、测试步骤完整复现 WebView 存储清理验证按 MASTG-DEMO-0082.md 给出的步骤整套动态测试流程如下安装应用到测试设备见 MASTG-TECH-0005Installing Apps准备动态分析环境在测试机安装 Frida即演示中引用的 MASTG-TOOL-0001并在设备上运行frida-server运行run.sh用 Frida 以 spawn 方式启动应用并加载挂钩脚本在应用界面点击Start按钮打开 WebView等待页面倒计时结束、Activity 关闭期间 Frida 脚本捕获 WebView 清理相关调用退出 Frida CLI 停止脚本取证验证按 MASTG-TECH-0002Host-Device Data Transfer 的方法在/data/data/org.owasp.mastestapp/app_webview/目录中搜索之前写入的敏感数据。3.1 启动脚本 run.shrun.sh 内容极简一条命令完成 spawn、注入与日志落盘#!/bin/bash frida -U -n MASTestApp -l script.js -o output.json参数含义-U连接 USB 连接的设备-n MASTestApp按进程名应用包名对应的进程附加目标-l script.js加载挂钩脚本-o output.json将 Frida 控制台输出重定向到output.json便于后续分析。3.2 取证搜索命令成功场景下用于验证残留的 adb 命令如下即output_adb_deletion_succeeded.txt的内容adb shell grep -nri -E SECRET_TOKEN_123456|DL-987654321 /data/data/org.owasp.mastestapp/app_webview这条命令递归-r、忽略大小写-i、显示行号-n地在 WebView 存储目录中搜索两条敏感数据字符串。localStorage 在 Chromium 中落盘为 LevelDB 格式位于app_webview/Default/Local Storage/leveldb/因此即使数据存在grep通常也是以匹配二进制文件的形式报出而非输出明文行。四、Frida 挂钩脚本原理追踪清理 API 的调用链script.js 是本演示的动态分析核心。它同时挂钩两个方法deleteAllData清理动作与setDomStorageEnabled启用动作从而完整还原先启用 DOM 存储、后清理全部数据的证据链。4.1 定位 Chromium 内部实现类WebView 的公开 APIandroid.webkit.WebStorage、android.webkit.WebSettings在运行时实际由 Chromium 实现类承载类名模式为com.android.webview.chromium.*。脚本首先用Java.enumerateMethods在该命名空间下枚举目标方法function enumerateDeleteAllDataMethod() { const res Java.enumerateMethods(com.android.webview.chromium.*!deleteAllData); return res res[0]; }Java.enumerateMethods(pattern!methodName)返回所有匹配类与方法的描述符。取第一个结果即可拿到真实实现类及其 class loader——这是后续 hook 的关键因为 Chromium 的实现类位于 WebView 的独立 class loader 中直接Java.use可能失败。4.2 确保目标类被加载一个常见的坑如果应用尚未真正使用过 WebStorage其内部实现类可能还没有被加载到内存enumerateMethods会返回undefined。脚本的处理是主动触发加载if (enumerateDeleteAllDataMethod() undefined) { console.log(Bring WebStorage to memory so we can hook its deleteAllData method.); Java.use(android.webkit.WebStorage).getInstance(); }调用WebStorage.getInstance()会迫使 Chromium 初始化 WebStorage 的实现类从而让后续枚举能够命中。同理对WebView与WebSettings也通过ensureClassLoaded主动Java.use一次确保其内部类进入内存。4.3 挂钩 deleteAllData 并打印调用栈找到方法描述符后切换到正确的 class loader 并替换实现const deleteAllDataMethod enumerateDeleteAllDataMethod(); if (deleteAllDataMethod ! undefined) { Java.classFactory.loader deleteAllDataMethod.loader; // 切换到 Chromium 类加载器 const WebStorageAdapter Java.use(deleteAllDataMethod.classes[0].name); WebStorageAdapter.deleteAllData.implementation function () { console.log(WebStorage.deleteAllData called.); printBacktrace(); // 打印 Java 调用栈 return this.deleteAllData(); // 调用原实现不改变行为 }; }Java.classFactory.loader ...将后续Java.use的解析上下文切换到该类的真实 loader避免类加载器不匹配导致的 hook 失败。printBacktrace()用java.lang.Exception的堆栈快照还原调用来源让测试人员能确认清理动作确实由应用自己的代码触发。4.4 挂钩 setDomStorageEnabled同样的思路用于捕获存储区域启用动作且遍历所有重载逐一挂钩ContentSettingsAdapter.setDomStorageEnabled.overloads.forEach(function (ov) { ov.implementation function () { const enabled arguments.length 0 ? arguments[0] : undefined; console.log(ContentSettingsAdapter.setDomStorageEnabled called, enabled is enabled .); printBacktrace(); return ov.apply(this, arguments); }; });这条 hook 的作用是证明应用确实启用了 DOM 存储与随后调用了deleteAllData构成一对完整的证据正好对应 MASTG-TEST-0320 中启用 API 列表 清理 API 列表的观察要求。五、运行结果解读从日志到磁盘取证5.1 Frida 输出output.jsonoutput.json 记录了完整调用序列按时间顺序解读Enumerating chromium. WebStorage.deleteAllData hooked. ContentSettingsAdapter.setDomStorageEnabled hooked. ContentSettingsAdapter.setDomStorageEnabled called, enabled is true.第一条setDomStorageEnabled called, enabled is true的调用栈直指应用代码com.android.webview.chromium.ContentSettingsAdapter.setDomStorageEnabled(Native Method) org.owasp.mastestapp.MastgTestWebView.mastgTest(MastgTestWebView.kt:20) ← 启用 DOM 存储 org.owasp.mastestapp.MainActivityWebViewKt$WebViewScreen$3.invoke$lambda$1(MainActivityWebView.kt:81)这与源码完全对应MastgTestWebView.kt 第 20 行 的domStorageEnabled true经由 Compose 的AndroidViewfactoryMainActivityWebView.kt 第 81 行 调用mastgTest(this)执行。随后捕获到清理动作WebStorage.deleteAllData called. Backtrace: com.android.webview.chromium.e.deleteAllData(Native Method) org.owasp.mastestapp.MainActivityWebView.onStop(MainActivityWebView.kt:41) ← 生命周期回调中的清理 android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1623) android.app.Activity.performStop(Activity.java:8838) ... android.app.servertransaction.TransactionExecutor.performLifecycleSequence(...)这条调用栈完美验证了设计意图页面倒计时结束 → JS 桥Android.closeApp()→activity.finish()→ Activity 进入onStop→ MainActivityWebView.kt 第 41 行 的WebStorage.getInstance().deleteAllData()被执行。5.2 磁盘取证成功场景数据已清理output_adb_deletion_succeeded.txt中同样的 adb 搜索命令没有任何匹配输出adb shell grep -nri -E SECRET_TOKEN_123456|DL-987654321 /data/data/org.owasp.mastestapp/app_webview命令执行后无任何匹配行返回这说明deleteAllData()生效后原先写入 localStorage 的两条敏感字符串在app_webview目录中已不存在数据没有残留在磁盘上。5.3 磁盘取证失败场景数据残留output_adb_deletion_failed.txt展示了清理缺失时的对照结果——这正是演示文档 Evaluation 一节所描述的失败用例adb shell grep -nri -E SECRET_TOKEN_123456|DL-987654321 /data/data/org.owasp.mastestapp/app_webview Binary file /data/data/org.owasp.mastestapp/app_webview/Default/Local Storage/leveldb/000003.log matches Binary file /data/data/org.owasp.mastestapp/app_webview/Default/Local Storage/leveldb/000003.log matchesgrep在 LevelDB 日志文件leveldb/000003.log中两次命中敏感数据。这里需要说明localStorage 在 Chromium 中以 LevelDB 落盘其键值对是二进制编码存储的所以grep报告Binary file ... matches而非输出明文。两条敏感字符串都命中说明 localStorage 内容完整残留。这演示了失败场景——应用关闭后敏感数据仍留在 WebView 存储目录中。六、测试判定通过/失败的标准依据 MASTG-TEST-0320 的 Evaluation 规则测试失败应用关闭后/data/data/app_package/app_webview/目录中仍存在敏感数据——通常是应用启用了相应存储区域DOM 存储、数据库、缓存、Cookie却没有调用配套的清理 API测试通过应用正确调用了与所启用存储区域对应的清理 API关闭后目录中不再有敏感数据残留。本演示默认场景通过Frida 日志证明WebStorage.deleteAllData()在onStop()中被调用adb 取证证明敏感数据已从app_webview目录消失。演示文档还给出了构造失败用例的简单方法注释掉 MainActivityWebView.kt 第 41 行 的WebStorage.getInstance().deleteAllData()并重新运行。此时 Frida 不再捕获到deleteAllData调用adb 搜索则会在leveldb/000003.log中命中两条敏感数据测试判定为失败。七、原理纵深deleteAllData 到底清理了什么、清不掉什么WebStorage.deleteAllData()是对 WebView 存储进行清理时最常用也最容易误用的 API理解它的能力边界至关重要。据 MASTG-KNOW-0018 的说明✅可以清理DOM 存储localStorage/sessionStorage与遗留的 WebSQL 数据库❌不能清理IndexedDB 与 Origin Private File SystemOPFS——它们由 Chromium 内部管理不属于WebStorageAPI 的管辖范围❌不能清理Cookie——需要单独调用CookieManager.removeAllCookies(ValueCallback)❌不能清理HTTP 磁盘缓存——需要WebView.clearCache(includeDiskFiles true)。此外Android没有提供删除整个 Chromium profile即app_webview目录的专用 API应用也不应直接删除该目录唯一的系统级方式是清除应用数据系统设置或ActivityManager.clearApplicationUserData()但这种方式会一并丢弃应用的其他用户数据通常不符合只清理 WebView 残留的需求。一个值得借鉴的完整清理参考实现来自开源项目 Firefox Focus见 MASTG-KNOW-0018 第 259-283 行其cleanup()依次执行clearFormData() clearHistory() clearMatches() clearSslPreferences() clearCache(true) // 清理 HTTP 缓存 CookieManager.getInstance().removeAllCookies(null) // 清理 Cookie WebStorage.getInstance().deleteAllData() // 清理 DOM 存储 / WebSQL可以看出一个严谨的 WebView 清理流程需要针对每一个已启用的存储区域分别调用对应 API。这与 MASTG-TEST-0320 开篇列出的启用 ↔ 清理配对表完全一致。八、最佳实践与测试中的现实挑战MASTG-BEST-0028WebViews Cache Cleanup 对开发与测试双方都提出了明确建议优先从源头禁止缓存对包含敏感数据的 API 响应使用Cache-Control: no-cache等头让 WebView 不缓存这是最省力的控制客户端显式兜底若无法控制服务器可设置WebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE)或在 WebView 使用结束后如 Activity 的onDestroy调用WebView.clearCache(includeDiskFiles true)。同时这类清理方案存在两个已知劣势测试时需留意clearCache(true)会无差别清除全部缓存数据包括图片等本可受益于缓存的大文件清理方法不保证一定被调用——例如应用进程被系统强制杀死时onStop()/onDestroy()可能根本不会执行。因此评估时需要同时考察上次运行是否清理过 本次是否执行了清理两方面的证据例如在下次启动时补做评估。而站在测试人员视角MASTG-KNOW-0018 的 Challenges of Testing WebView Cache Cleanup 一节 总结了 WebView 清理测试的四大难点需要识别应用中 WebView 实例的数量、各自的WebSettings以及实例间的关联确保测试结论只针对被测的那个 WebView对每个实例需要确认各存储区域如何配置、数据基于 HTTP 缓存头与存储配置如何实际落盘需要确定每条敏感数据项的生命周期与预期保留时长需要应对清理方法可能不被调用的场景进程被突杀等并检查是否存在应对这些场景的缓解措施。这也是 MASTG-TEST-0320 建议动态分析挂钩相关 API 检查文件系统残留双管齐下的原因单独看 API 调用日志本演示的 Frida 输出或单独看磁盘残留adb grep都可能产生误判两者互为印证才是可靠结论。若需要在运行期做更细粒度的文件系统追踪可按 MASTG-TECH-0143 对 WebView 存储目录中的open、openat、unlinkat等文件操作进行额外追踪。九、小结MASTG-DEMO-0082 用一整套可复现的工程化样本把WebView 敏感数据清理这一主题从现象到原理完整呈现样本层面一个localStorage写入敏感数据的应用 onStop()中调用WebStorage.deleteAllData()的清理实现MainActivityWebView.kt测试层面Frida 挂钩deleteAllData/setDomStorageEnabled还原调用链script.jsadb 在app_webview目录中取证并通过注释清理代码构造失败对照组理论层面deleteAllData()的能力边界能清 DOM 存储/WebSQL清不掉 IndexedDB/OPFS/Cookie/缓存以及 MASTG-TEST-0320、MASTG-KNOW-0018、MASTG-BEST-0028 构成的完整知识闭环。这套方法可以直接迁移到真实应用的评估中定位其 WebView 实例与存储配置 → 挂钩启用/清理 API → 注入敏感数据并关闭应用 → 在app_webview目录取证即可对WebView 是否妥善清理敏感数据给出有据可依的结论。赞分享文档教程网络安全【免费下载链接】mastgThe 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 实战Android 内部存储明文敏感数据检测MASTG-DEMO-0010 / MASTG-TEST-0207OWASP MASTG 实战Android 内部存储明文敏感数据检测MASTG DEMO 0010 / MASTG TEST 0207 导读 本文以 OW文档教程网络安全Blog.Core 数据库优化终极指南索引设计与查询性能调优Blog.Core 数据库优化终极指南索引设计与查询性能调优 在ASP.NET Core 8.0全家桶开发中数据库性能优化是构建高性能应用的关键环节。文档教程网络安全使用 Frooky 检测 Firebase Analytics 敏感用户数据外发MASTG-DEMO-0081 实战演示使用 Frooky 检测 Firebase Analytics 敏感用户数据外发MASTG DEMO 0081 实战演示 导读 本文以 OWASP Mobil文档教程网络安全上一篇Flink CDC 集成 ClickHouse3 条路径搭通实时数据同步链路下一篇品牌资产组织实战指南用 ui-ux-pro-max-skill 构建可搜索、可校验、可追溯的营销资产体系创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表