- 文档
- 教程
- 网络安全
【免费下载链接】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.
证书固定(Certificate Pinning / Identity Pinning)是 Android 应用抵御中间人(MITM)攻击、将信任范围收窄到特定证书或公钥的关键加固手段。本文以 OWASP MASTG(Mobile Application Security Testing Guide)测试用例 MASTG-TEST-0022(Testing Custom Certificate Stores and Certificate Pinning) 为核心骨架,完整覆盖静态分析(Network Security Configuration、TrustManager、网络库与 WebView、Xamarin、Cordova)与动态分析(代理拦截、objection 绕过验证)两条路径,并结合仓库内相关知识文档与源码级证据进行纵深展开。读完本文,你将能够系统性地识别 Android 应用中的各类证书固定实现、判断其是否有效、定位配置缺陷,并用 objection 等工具完成运行时验证。
版本说明:该测试用例对应 MASVS-NETWORK-2(V1 中为 MSTG-NETWORK-4),适用级别 L2,当前在仓库中已标记为
deprecated,由 MASTG V2 中的新用例 MASTG-TEST-0242、MASTG-TEST-0243 和 MASTG-TEST-0244 取代。本文会在相应小节指出新旧用例的承接关系,帮助读者平滑迁移到 V2 测试体系。
为什么需要证书固定:从"信任所有 CA"到"只信任指定身份"
在深入测试方法之前,先理解证书固定的本质。MASTG 网络通信章节(Document/0x04f-Testing-Network-Communication.md)指出:操作系统默认信任所有系统内置 CA,而设备用户还可以自行添加 CA。对金融、健康类等高风险应用而言,即使系统 CA 被攻破是小概率事件,也必须纳入威胁模型——证书固定就是把信任从"所有被信任 CA 签发的证书"收窄为"某一个特定身份(X.509 证书、公钥或其哈希)",只有身份匹配时才建立连接,从而减少攻击面。
MASTG 关于固定(Pinning)的几个关键结论,可直接作为测试评估依据:
- 固定推荐在开发阶段(预加载)进行,固定对象首选证书公钥 SPKI(
subjectPublicKeyInfo)的哈希; - 必须包含备用固定(backup pin):一旦需要更换密钥或 CA,若没有备用 pin,应用将无法恢复连接,只能强制推送客户端更新;
- 对 MAS-L2 应用而言,固定是必须实现的要求;但对未实现固定的应用,不应简单判定为漏洞,需结合威胁模型评估;
- 固定能防御"CA 被攻破"或"设备上被安装了恶意 CA",但无法防御控制了设备的攻击者——攻击者可以轻易禁用固定逻辑,因此固定不能替代服务端安全防护;
- 移动端固定与 Web 的 HTTP Public Key Pinning(HPKP)不同:HPKP 在网站侧已不推荐使用,而移动应用可通过应用商店这一带外渠道更新,不存在"锁死用户"的问题。
静态分析:定位应用中的证书固定实现
静态分析的目标是确认应用"是否"以及"以何种方式"实现了证书固定。Android 上的实现途径多种多样,MASTG 知识库 MASTG-KNOW-0015(Certificate Pinning) 将其归纳为以下几类,本测试的静态分析部分基本按此脉络展开:
| 实现途径 | 适用场景 | 关键检测点 |
|---|---|---|
| Network Security Configuration(NSC) | API 24+ 的推荐方式,声明式配置 | res/xml中的<pin-set>与expiration |
自定义 TrustManager(javax.net.ssl) | 需要更细粒度控制时 | TrustManagerFactory、KeyStore(BKS)、SSLContext.init |
| 第三方网络库(如 OkHttp) | 使用网络库的应用 | CertificatePinner.Builder的add()调用 |
| WebView | 应用内嵌网页场景 | WebViewClient的onLoadResource、shouldInterceptRequest |
| 跨平台框架(Xamarin、Cordova 等) | 混合/跨平台应用 | ServicePointManager、Cordova 插件调用 |
| 原生代码(.so) | 高对抗场景 | 编译进 native 库的证书或哈希校验 |
重要:从源码结构推断的内容(例如某些库"底层基于自定义 TrustManager")仅作辅助判断,测试结论必须以可观察证据为准。
1. Network Security Configuration(NSC):检查<pin-set>与过期时间
NSC 是 Android 7.0(API level 24)起引入的机制,允许应用以 XML 声明式配置网络安全策略,其核心能力包括:明文流量控制、自定义信任锚、证书固定、仅调试用覆盖(MASTG-KNOW-0014(Android Network Security Configuration))。
检查步骤如下:
- 反编译应用(参考 MASTG-TECH-0013),取出
AndroidManifest.xml,查找<application>标签上的android:networkSecurityConfig属性,定位配置文件(通常位于res/xml/network_security_config.xml); - 检查配置中是否存在
<pin-set>元素,记录其覆盖的<domain>; - 检查
expiration日期:如果 pin 已过期,Android 将不再对该域名强制执行证书固定,连接的认证会回退到配置的信任锚(trust anchors)——此时应用可能接受它本不该信任的 CA 签发的证书。这一检查点正是 V2 新用例 MASTG-TEST-0243(Expired Certificate Pins in the Network Security Configuration) 的核心评估内容:只要面向相关一方(first-party)域名的 pin 过期时间在过去,测试即判定失败。
一个完整的 NSC 固定配置示例(摘自 MASTG-KNOW-0015,包含备用 pin):
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <!-- 对 owasp.org 及其子域名启用证书固定 --> <domain includeSubdomains="true">owasp.org</domain> <pin-set expiration="2028-12-31"> <!-- 服务器证书的中间 CA 公钥(X.509 证书的 SubjectPublicKeyInfo)哈希 --> <pin digest="SHA-256">YLh1dUR9y6Kja30rRAn7JKnbQG/uEtLMkBgFF2Fuihg=</pin> <!-- 服务器证书的根 CA 公钥哈希(作为备用 pin) --> <pin digest="SHA-256">Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=</pin> </pin-set> </domain-config> </network-security-config>理解 NSC 固定生效的底层流程有助于判断配置是否有效(依据 MASTG-KNOW-0015):当应用连接远程端点时,系统会取出传入的证书、提取其公钥、对公钥计算摘要,并将摘要与本地 pin 集合比对;只要至少一个 pin 的摘要匹配,证书链即视为有效,连接继续建立。此外还应注意:
- 适用范围:NSC 只作用于 Android 框架托管的网络流量(基于
HttpsURLConnection的连接以及 WebView 请求,除非使用了自定义 TrustManager);原生代码发起的连接不受 NSC 约束,需要其他机制; - 优先级:
base-config作用于应用所有连接,domain-config对指定域名覆盖base-config(MASTG-KNOW-0014)。Android 9(API 28)及以上目标应用的默认配置为base-config cleartextTrafficPermitted="false"且仅信任系统 CA; - 验证 NSC 是否被加载:如果配置存在,系统日志中应出现
D/NetworkSecurityConfig: Using Network Security Config from resource network_security_config。
系统日志提示:当证书固定校验失败时,系统日志(logcat,参考 MASTG-TECH-0009)会记录以下事件,这是动态测试中最直观的判定信号:
I/X509Util: Failed to validate the certificate chain, error: Pin verification failedV2 新用例 MASTG-TEST-0242(Missing Certificate Pinning in Network Security Configuration) 专门评估"NSC 中是否对相关一方域名配置了固定":若应用连接了相关一方域名但未设置
networkSecurityConfig,或已设置却未对该域名启用固定,测试即失败;但不应因为无关的第三方域名未固定而报错。若同一域名存在其他固定实现(如自定义 TrustManager 或第三方库),应视为"未由 NSC 覆盖"而非"确认缺失固定"。
2. TrustManager:自定义证书库的经典实现
在 NSC 出现之前,Android 上实现证书固定的推荐方式是基于javax.net.ssl编写自定义TrustManager。虽然 NSC 已是推荐做法,现代应用出于灵活性仍会使用该方案(MASTG-KNOW-0015),因此测试者必须掌握其检查方法。
实现证书固定主要包含三步:
- 获取目标主机(们)的证书;
- 确保证书为
.bks(BouncyCastle)格式; - 将该证书固定到默认 Apache Httpclient 的实例上。
分析时,应确认 HTTP 客户端是否正确加载了 KeyStore。正确的加载方式如下(JAVA 代码,完整保留自原测试用例):
InputStream in = resources.openRawResource(certificateRawResource); keyStore = KeyStore.getInstance("BKS"); keyStore.load(resourceStream, password);KeyStore 加载完成后,即可使用只信任该 KeyStore 中 CA 的 TrustManager:
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); // Create an SSLContext that uses the TrustManager // SSLContext context = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null);分析要点:应用的具体实现可能各不相同——可能只固定证书的公钥、固定整个证书,或固定整条证书链。测试者需结合代码逐一定位固定粒度。与此同时,自定义 TrustManager 属于底层方案,极易出错(MASTG-KNOW-0015),静态分析时应警惕以下反模式:
SSLSocket不会自动校验主机名,必须配合安全的HostnameVerifier实现,并显式检查verify()的返回值;- 绝不使用"信任一切"(trust-all)的 TrustManager——它会静默接受所有证书,攻击者几乎不费吹灰之力即可解密和篡改用户数据。这类实现正是姊妹测试 MASTG-TEST-0021(Testing Endpoint Identify Verification) 重点排查的对象(如重写
checkClientTrusted、checkServerTrusted、getAcceptedIssuers为空实现的代码片段)。
3. 网络库与 WebView:OkHttp 与 WebViewClient
OkHttp 等第三方网络库通常自带固定能力。例如 OkHttp 的CertificatePinner可通过链式 Builder 配置(JAVA 代码,完整保留自原测试用例):
OkHttpClient client = new OkHttpClient.Builder() .certificatePinner(new CertificatePinner.Builder() .add("example.com", "sha256/UwQAapahrjCOjYI3oLUx5AQxPBR02Jz6/E2pt0IeLXA=") .build()) .build();注意add()的第一个参数是域名,第二个参数是 SPKI 公钥的 SHA-256 摘要(sha256/<base64>格式)。从实现原理看,OkHttp 的固定底层同样借助自定义 TrustManager 强制校验规则(MASTG-KNOW-0015)。
WebView 场景:使用 WebView 组件的应用可能通过WebViewClient的事件处理器,在目标资源加载前对每次请求执行某种"证书固定"。以下是典型的验证实现(JAVA 代码,完整保留自原测试用例):
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new WebViewClient(){ private String expectedIssuerDN = "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US;"; @Override public void onLoadResource(WebView view, String url) { //From Android API documentation about "WebView.getCertificate()": //Gets the SSL certificate for the main top-level page //or null if there is no certificate (the site is not secure). // //Available information on SslCertificate class are "Issuer DN", "Subject DN" and validity date helpers SslCertificate serverCert = view.getCertificate(); if(serverCert != null){ //apply either certificate or public key pinning comparison here //Throw exception to cancel resource loading... } } } });更推荐的替代方案:配置带固定规则的 OkHttpClient,让其作为代理并覆写WebViewClient的shouldInterceptRequest来承载请求,从而复用 OkHttp 的固定能力。另外,从 Android 平台行为看,NSC 的固定规则会自动作用于同应用内 WebView 加载的资源,因此大多数 WebView 场景直接用 NSC 即可(MASTG-KNOW-0015)。
4. Xamarin 应用(旧版,已停止支持)
Xamarin 自 2024 年 5 月 1 日起已停止支持(End of Support),不再接收安全补丁与更新,新项目应改用 .NET MAUI。但存量 Xamarin 应用仍可能出现,其典型固定实现方式是使用System.Net.ServicePointManager。
通常应用会创建一个校验证书的函数,并将返回值交给ServerCertificateValidationCallback方法(C# 代码,完整保留自原测试用例):
[Activity(Label = "XamarinPinning", MainLauncher = true)] public class MainActivity : Activity { // SupportedPublicKey - Hexadecimal value of the public key. // Use GetPublicKeyString() method to determine the public key of the certificate we want to pin. Uncomment the debug code in the ValidateServerCertificate function a first time to determine the value to pin. private const string SupportedPublicKey = "3082010A02820101009CD30CF05AE52E47B7725D3783B..."; // Shortened for readability private static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors ) { //Log.Debug("Xamarin Pinning",chain.ChainElements[X].Certificate.GetPublicKeyString()); //return true; return SupportedPublicKey == chain.ChainElements[1].Certificate.GetPublicKeyString(); } protected override void OnCreate(Bundle savedInstanceState) { System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate; base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Main); TesteAsync("https://security.claudio.pt"); }该示例固定的是证书链中的中间 CA,HTTP 响应输出可在系统日志中查看。仓库中提供了对应的样例 APK:Samples/Android/02_CertificatePinning/certificatePinningXamarin.apk(目录说明见 Samples/Android/02_CertificatePinning/readme.md)。
分析方法:解压 APK 后,用 .NET 反编译器(如 dotPeek、ILSpy 或 dnSpy)反编译Assemblies文件夹内的程序集 DLL,确认ServicePointManager的使用情况。这里的关键取证点是:ValidateServerCertificate是否对固定值做了严格的字符串比较,以及是否存在注释掉的return true;调试捷径。
5. Cordova 应用:混合应用的插件方案
基于 Cordova 的混合应用原生不支持证书固定,通常依赖插件实现,最常用的是 PhoneGap SSL Certificate Checker 插件。插件通过check方法校验指纹,由回调函数决定后续流程(JavaScript 代码,完整保留自原测试用例):
// Endpoint to verify against certificate pinning. var server = "https://www.owasp.org"; // SHA256 Fingerprint (Can be obtained via "openssl s_client -connect hostname:443 | openssl x509 -noout -fingerprint -sha256" var fingerprint = "D8 EF 3C DF 7E F6 44 BA 04 EC D5 97 14 BB 00 4A 7A F5 26 63 53 87 4E 76 67 77 F0 F4 CC ED 67 B9"; window.plugins.sslCertificateChecker.check( successCallback, errorCallback, server, fingerprint); function successCallback(message) { alert(message); // Message is always: CONNECTION_SECURE. // Now do something with the trusted server. } function errorCallback(message) { alert(message); if (message === "CONNECTION_NOT_SECURE") { // There is likely a MITM attack going on, be careful! } else if (message.indexOf("CONNECTION_FAILED") >- 1) { // There was no connection (yet). Internet may be down. Try again (a few times) after a little timeout. } }分析方法:解压 APK 后,Cordova/PhoneGap 文件位于/assets/www目录;plugins文件夹会显示应用使用了哪些插件;随后在应用 JavaScript 代码中搜索sslCertificateChecker(或check方法)的调用,确认其是否真正执行了固定校验。
动态分析:代理拦截与固定绕过验证
第一步:按端点身份验证用例搭建代理
动态分析的第一步是遵循 MASTG-TEST-0021(Testing Endpoint Identify Verification) 的流程配置拦截代理(如 Burp Suite)并接管 HTTPS 流量。关键判定逻辑:
- 如果流量可以被正常代理解密:说明应用没有实现证书固定(或实现存在缺陷),可继续常规的流量分析;
- 如果代理配置正确却始终看不到解密流量:很可能应用确实实现了证书固定且安全措施到位。此时应继续验证:所有域名都如此吗?只对部分域名固定、其他域名可被拦截,本身就是一个值得深挖的评估点;
- 应用目标版本低于 API 24 时,会默认接受用户安装的证书,此时即使有固定也容易被绕过,需结合静态分析结果判断。
V2 将这一动态验证过程正式化为 MASTG-TEST-0244(Missing Certificate Pinning in Network Traffic):该测试与实现方式无关,只要 MITM 拦截能成功,即说明相关一方域名要么未固定、要么固定实现错误,测试判定失败。与静态取向的 MASTG-TEST-0242 形成互补,尤其适用于存在混淆或动态加载代码、难以通过静态分析识别固定实现的场景。测试期间同样建议监控系统日志,出现I/X509Util: Failed to validate the certificate chain, error: Pin verification failed即表明应用检测到了 MITM 并拒绝建连。
第二步:objection 快速冒烟测试
作为快速冒烟测试,可以尝试用 objection(MASTG-TOOL-0038)绕过证书固定,方法详见 MASTG-TECH-0012(Bypassing Certificate Pinning)。在已 root 的设备上安装 frida-server 后,执行:
android sslpinning disable若应用使用的固定相关 API 被 objection 挂钩,相关输出会出现在 objection 的会话输出中:
第三步:解读冒烟测试结果(重要注意事项)
解读 objection 的输出时务必保持谨慎,依据原测试用例与 MASTG-TECH-0012,存在两种易误判的情形:
- API 覆盖可能不完整:objection 内置的挂钩清单未必覆盖应用所用的全部固定 API;
- 没有输出不意味着没有固定:如果没有任何 API 被挂钩,并不能推导出"应用未实现固定"的结论。
在以上两种情况下,应用或其部分组件可能以 objection 支持的方式之外的自定义方式实现了固定。因此:
- 回到本文的静态分析部分,针对性地查找固定指示器(
<pin-set>、TrustManagerFactory、CertificatePinner、ServicePointManager、Cordova 插件调用等),做更深入的验证; - 若静态手段仍无法突破(例如固定逻辑被混淆或位于原生代码中),可考虑 MASTG-TECH-0012 中的系统性绕过思路:
- 静态绕过:解包后在 smali 中
grep -ri "sha256\|sha1" ./smali替换固定哈希,或在assets/res中查找并替换.cer/.crt证书文件与.jks/.bks信任库(用keytool -importcert ... -storetype BKS注入代理证书后重新打包签名); - 动态绕过:识别应用使用的网络库(OkHttp3 等),用 Frida 挂钩
CertificatePinner.Builder.add之类的关键方法并修改参数,从而让固定失效。这类绕过更快捷,且无需处理完整性校验。
- 静态绕过:解包后在 smali 中
一个完整的绕过示例在 MASTG-TECH-0012 中有详细展开(含 BKS 信任库的 keytool 命令与 OkHttp 方法签名搜索示例),本文不再赘述。
从 MASTG V1 到 V2:本测试的演进路径
本测试用例已标注deprecated,V2 将其拆分为三个更精细、可独立评估的新用例,测试者可据此组织更现代、更可复现的测试流程:
| 旧用例 | V2 替代用例 | 侧重 |
|---|---|---|
| MASTG-TEST-0022(本用例) | MASTG-TEST-0242 | 静态:NSC 是否对相关一方域名配置固定 |
| MASTG-TEST-0243 | 静态:NSC 中固定 pin 是否已过期 | |
| MASTG-TEST-0244 | 动态:运行时能否成功拦截相关一方域名的 HTTPS 流量 |
三个新用例共享同一前置条件"识别一方域名(first-party domains)"(见 prerequisites/identify-first-party-domains.md),且都强调:只有开发者控制下、支撑应用核心或安全敏感功能的一方域名才应作为评估对象,第三方域名不应仅因出现在流量中或可被拦截而触发报错。判定一方域名通常需要二进制之外的信息,必要时应与开发者确认。
小结
测试 Android 应用的自定义证书库与证书固定,核心是回答三个问题:应用是否实现了固定?以何种机制实现?固定是否仍有效?静态分析阶段沿 NSC、TrustManager、网络库/WebView、Xamarin、Cordova 五条主线逐一排查(本用例 + MASTG-KNOW-0015 提供了完整路线图);动态分析阶段先用 MASTG-TEST-0021 的代理流程做基线,再用 objection(MASTG-TOOL-0038)冒烟验证,并以系统日志中的X509Util事件作为关键佐证。最后切记:固定只防御 CA 妥协与恶意 CA,不防御控制设备的攻击者;同时务必检查备用 pin 与过期时间,避免应用在不知不觉中失去固定保护——这正是 MASTG-TEST-0243 所针对的隐蔽风险。
- 文档
- 教程
- 网络安全
【免费下载链接】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.
相关推荐
Android 证书固定(Certificate Pinning)完全指南:基于 OWASP MASTG 的实现、测试与绕过
Android 证书固定(Certificate Pinning)完全指南:基于 OWASP MASTG 的实现、测试与绕过 本文基于 OWASP Mobile
文档教程网络安全绕过 Android 应用证书固定(Certificate Pinning):MASTG 黑盒测试实用指南
绕过 Android 应用证书固定(Certificate Pinning):MASTG 黑盒测试实用指南 本指南聚焦 OWASP Mobile Applica
文档教程网络安全OWASP MASTG:iOS 证书固定(Certificate Pinning)绕过技术实战
OWASP MASTG:iOS 证书固定(Certificate Pinning)绕过技术实战 本篇基于 OWASP MASTG(Mobile Applicat
文档教程网络安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考