先看结论与判断条件
- 每项能力声明必须绑定明确的 APK、AAB、IPA 或 SO 摘要;演示包、旧版本与通用报告不能代替采购候选。
- 保护范围要说明处理对象、未处理对象、运行时暴露、服务端边界和失败条件,不能只列功能名称。
- 兼容性证据要给出真实设备、系统、ABI、场景、结果与失败记录,单个截图和总体通过率都不足以复核。
- 供应链证明应把产物 subject 摘要、构建者、构建类型、参数与材料绑定,并验证声明类型和签发者身份。
- Android 与 Apple 的签名链必须分别验收;签名有效证明身份和完整性,不自动证明业务安全或加固强度。
- 采购问卷应把缺失、过期、错配和不可复核证据直接标为阻塞,而不是用供应商排名或营销承诺补齐。
把能力询问改写成证据问题
采购常见问法是是否支持代码混淆、防篡改、VMP、反调试或全机型兼容,供应商很容易回答支持,却没有说明支持对象、配置、版本、边界和验证方法。可核验证据问卷要把每个名词改写成一条可失败的陈述,并要求对应候选、证据类型、复核步骤与限制。
例如不要问是否兼容 Android,而要问:哪一个候选摘要在什么型号、系统、ABI、业务场景和加固配置下完成了什么测试,失败用例如何记录,未覆盖哪些组合。不要问防逆向强不强,而要问保护了哪些代码、运行时何处仍可能出现明文、测试者使用什么授权方法、结果能证明什么与不能证明什么。
问卷本身不是评分游戏。没有事实依据时,不应根据回答篇幅、术语数量或承诺强度给供应商排位。评审只判断证据是否存在、是否绑定当前候选、是否在有效期内、是否可由买方复核以及结论是否越过证据边界。
| 宣传问法 | 证据问法 | 必须绑定 | 拒绝条件 |
|---|---|---|---|
| 是否防逆向 | 哪些对象经过何种验证 | 候选与保护范围 | 只给功能列表 |
| 是否全兼容 | 哪些矩阵和路径通过 | 设备、系统、ABI 与场景 | 只给总体口号 |
| 是否安全 | 针对哪类威胁与边界 | 威胁模型和失败条件 | 没有边界 |
| 是否不影响性能 | 同条件基线如何比较 | 原始样本与方法 | 只给单个数字 |
| 是否可信构建 | provenance 指向哪个产物 | subject 摘要和签发者 | 摘要错配 |
| 是否签名完整 | 交付后由谁签名验证 | 平台签名身份 | 混用平台规则 |
第一组问题锁定交付候选身份
要求供应商列出输入与输出产物的文件名、SHA-256、大小、平台、版本、架构、处理时间和配置标识。APK 与 AAB 还要记录 applicationId、versionCode、签名证书身份;IPA 记录 bundle identifier、版本和 Apple 签名链相关身份;独立 SO 则记录 ABI、SONAME 和 build ID。
输入输出摘要建立了加固转换关系。若供应商展示的报告只写某版本应用,却没有文件摘要,买方无法确认报告属于当前采购候选。相同版本号也可能因重新构建、依赖变化、渠道资源或加固参数不同而产生新字节,旧报告不得自动继承。
还要问交付物由谁保存、如何传输、保留多久、如何删除,以及日志和符号是否包含客户代码或敏感数据。供应商可以用脱敏与受控访问保护材料,但不能因保密而省略证据身份。买方至少要拿到可验证摘要、回执索引和在争议时调阅完整证据的责任人。
| 对象 | 身份字段 | 验证动作 | 不能证明 |
|---|---|---|---|
| APK | 摘要、包名、版本、证书 | 解析并验签 | 业务安全 |
| AAB | 摘要、模块、版本、签名者 | 核对 bundle 身份 | 最终每台设备 APK |
| IPA | 摘要、bundle id、证书链 | 平台签名检查 | 运行路径正确 |
| SO | 摘要、ABI、SONAME、build ID | ELF 身份检查 | 动态装载成功 |
| 报告 | 摘要、生成时间、工具版本 | 与候选索引对应 | 报告内容真实 |
| 配置 | 配置摘要和审批 | 绑定输入输出 | 保护效果已验证 |
第二组问题要求公开保护边界
OWASP MASVS-RESILIENCE 将抗篡改与抗逆向放在移动端韧性控制中,但控制目录不证明某个候选达到任何强度。供应商应说明处理哪些 DEX 类、Native 函数、资源、配置和完整性检查点,哪些内容因反射、框架、动态加载、性能或合规要求被排除。
问清攻击面和信任边界:客户端代码在合法设备运行时何处必须解密或执行,密钥是否由服务端授权,离线场景如何限制,篡改发现后采取什么业务动作。加固属于纵深防御,不能替代服务端权限、风控、发布签名和漏洞修复。把所有风险都归给客户端保护会制造错误采购预期。
每项保护还要给出失败条件和可观测性。完整性检查可能因环境、分发重签或系统差异触发;虚拟化范围可能受性能与兼容边界限制;反调试可能影响合法诊断。供应商应列出支持、限制、例外和回滚方式,而不是承诺无法绕过或绝对安全。
| 字段 | 采购问题 | 合格回答 | 风险回答 |
|---|---|---|---|
| 保护对象 | 哪些类、函数或资源处理 | 范围可枚举并绑定配置 | 全部保护 |
| 排除对象 | 为什么未处理 | 原因与影响明确 | 没有例外 |
| 运行时边界 | 何时出现可执行明文 | 场景与限制明确 | 永不暴露 |
| 服务端职责 | 哪些授权不在客户端 | 接口和失败语义明确 | 客户端独立解决 |
| 失败动作 | 检测后如何处理 | 可测试且可回滚 | 自动绝对阻断 |
| 诊断影响 | 崩溃和符号如何还原 | 有受控映射链 | 不需要调试 |
第三组问题审查兼容与性能证据
兼容报告必须给出设备型号、系统版本、ABI、芯片、安装来源、应用场景、前置状态、操作步骤和实际结果。测试入口至少覆盖冷启动、登录或授权、核心路径、Native 调用、前后台、多进程、异常和升级。只给设备数量或通过率,买方无法判断关键用户路径是否真正执行。
性能证据要同时提供基线候选和加固候选,保持设备、数据、步骤、冷暖状态、采样工具与统计口径一致。启动、内存、包体、CPU 和耗电是不同指标,不能用一个平均数字代表全部影响。供应商需要交付原始样本摘要、汇总方法、异常样本处理和置信边界。
失败记录比全绿截图更有价值。问卷应要求列出失败设备、失败步骤、错误类型、复现率、根因状态、临时规避和未解决限制。若供应商声称没有失败,应提供测试总集与原始回执,使买方能验证分母和排除规则,而不是把未执行用例当作通过。
| 证据 | 必须包含 | 可复核方式 | 常见缺陷 |
|---|---|---|---|
| 设备矩阵 | 型号、OS、ABI 和实际结果 | 按用例抽查 | 只列设备名 |
| 场景回执 | 步骤、断言和时间 | 重放关键路径 | 只看启动 |
| 崩溃材料 | 日志、tombstone 和候选身份 | 匹配符号与摘要 | 缺少同构建材料 |
| 性能基线 | 同条件双候选 | 核对原始样本 | 比较条件变化 |
| 失败台账 | 未解决项和边界 | 复现与责任人 | 只给全绿汇总 |
| 有效期 | 平台与工具版本 | 到期重新验证 | 永久有效 |
第四组问题追问测试方法与复核责任
每项结论都应回答谁测试、何时测试、使用什么工具版本、输入是什么、通过条件是什么、失败时保存什么以及谁批准。自动化 exit code、编译通过或静态扫描不能替代设备端业务验收。买方应能抽取关键用例,在自己的候选和设备上重复执行。
测试方法要区分静态证据、动态证据和人工判断。静态证据可以确认结构、签名、符号与配置;动态证据确认装载、路径和设备行为;人工判断解释保护范围和商业限制。三者混在一段文字里,容易把配置存在误写成运行通过。
复核责任必须落到角色,而不是写双方确认。供应商负责生成和解释加固回执,买方负责提供真实业务路径与接受标准,独立测试人员负责复现指定证据,发布负责人根据缺口作决定。证据过期、候选变化或平台升级时,由谁触发重验也要写入合同附件。
第五组问题核对构建证明与声明主体
SLSA Provenance v1.1 要求构建证明把产物 subject、构建者、构建类型、外部参数和依赖材料组织起来。采购方先检查 subject digest 是否等于交付候选;摘要不一致时,这份 provenance 属于另一个产物,后续构建信息不能用于当前验收。
in-toto Attestation Statement v1 用 subject、predicateType 和 predicate 表达有类型的声明。格式正确只说明可按预定结构读取,不保证内容真实。还要验证签发主体、签名、证书或密钥信任范围、撤销状态、签发时间以及 predicate 类型是否在采购策略中允许。
无法提供完整构建证明时,供应商可以提交较低等级的来源和处理回执,但必须诚实标注证据类型。接收记录只能证明某人收到某摘要,处理日志只能证明某工具声称执行某步骤,都不能冒充可复现构建。买方可按风险决定阻塞、限制范围或要求补证。
| 层级 | 检查项 | 失败含义 | 采购动作 |
|---|---|---|---|
| Subject | 摘要匹配交付物 | 报告指向其他候选 | 直接阻塞 |
| Predicate type | 声明类型受支持 | 语义未知或错用 | 阻塞或人工复核 |
| Signer | 签发者在信任范围 | 声明可被任意伪造 | 直接阻塞 |
| Builder | 构建者和环境可识别 | 构建来源不清 | 要求补证 |
| Materials | 输入和依赖可追溯 | 供应链存在断点 | 限制接入 |
| Validity | 时间、撤销和策略有效 | 证据过期 | 重新签发或重验 |
Android 与 Apple 签名证据要分别检查
AOSP app signing 说明 Android 使用应用签名建立更新身份,不同 APK 签名方案覆盖不同文件区域和平台版本。问卷要说明输入由谁签名、加固处理是否保留或移除签名、输出由谁签名、使用哪些方案验证,以及应用商店或企业分发如何完成最终签名。
Apple app code signing process 说明 Apple 平台通过代码签名、证书与运行验证建立 App 身份。iOS 交付需要单独说明证书、provisioning、entitlements、bundle 身份和重签责任。不能拿 Android 的 v2、v3 等术语解释 IPA,也不能把 Apple 验签截图当成 Android 更新身份回执。
两种平台上,签名有效都不等于代码没有漏洞、保护强度足够或业务逻辑安全。签名证据回答是谁为哪些字节背书以及内容是否在覆盖范围内变化;保护证据回答处理与验证;兼容证据回答运行路径。问卷必须保留这三类结论的独立性。
| 平台 | 身份对象 | 主要问题 | 禁止混淆 |
|---|---|---|---|
| Android APK | 证书与签名方案 | 输入输出由谁签名 | 不套用 Apple 证书流程 |
| Android AAB | bundle 签名和商店流程 | 最终 APK 签名责任 | 不等同本地 APK |
| Apple IPA | 证书、provisioning 与代码签名 | 重签和 entitlements | 不使用 APK scheme 术语 |
| Native 库 | 随容器签名覆盖 | 处理后容器如何签名 | 不把 build ID 当签名 |
| 测试包 | 测试身份 | 与生产差异 | 不继承生产结论 |
| 验签回执 | 工具、平台和候选 | 是否绑定当前字节 | 不证明业务安全 |
用本地校验器检查答卷证据完整性
下面的 Python 脚本读取 JSON 答卷,要求每个 claim 包含 id、statement、evidence_type、artifact_sha256、valid_until、boundary 和 reviewer。它校验摘要格式、日期、允许的证据类型、重复 id 与空字段,并把过期或证据类型为 declaration-only 的项标为阻塞。
脚本不判断供应商声明真假,也不下载报告或验证签名;这些动作需要买方信任策略和真实附件。它的作用是防止内容完整的营销段落因为缺少候选、边界和责任人而进入评审。生产流程还应校验证据文件摘要、attestation subject、签发者和候选实际身份。
答卷不得包含私钥、令牌、客户源代码或内部地址。附件可存放在受控系统,问卷只保存不可变摘要和访问索引。校验失败应返回具体 claim 和字段,供应商只补缺失字段或替换证据,不需要重写整份答卷,便于保留修订历史。
import datetime as dt
import json
import re
import sys
from pathlib import Path
if len(sys.argv) != 2:
raise SystemExit('usage: validate_vendor_answers.py questionnaire.json')
input_path = Path(sys.argv[1])
if not input_path.is_file():
raise SystemExit('questionnaire file is missing')
data = json.loads(input_path.read_text(encoding='utf-8'))
claims = data.get('claims')
if not isinstance(claims, list) or not claims:
raise SystemExit('claims array is missing')
allowed_types = {'static-report', 'device-receipt', 'provenance', 'attestation', 'signature-receipt', 'declaration-only'}
digest_pattern = re.compile(r'^[a-f0-9]{64}$')
today = dt.date.today()
seen = set()
blocked = []
for index, claim in enumerate(claims):
claim_id = str(claim.get('id', '')).strip()
if not claim_id or claim_id in seen:
raise SystemExit(f'invalid claim id at index {index}')
seen.add(claim_id)
for field in ('statement', 'evidence_type', 'artifact_sha256', 'valid_until', 'boundary', 'reviewer'):
if not isinstance(claim.get(field), str) or not claim[field].strip():
raise SystemExit(f'{claim_id}: missing {field}')
if claim['evidence_type'] not in allowed_types:
raise SystemExit(f'{claim_id}: unsupported evidence type')
if not digest_pattern.fullmatch(claim['artifact_sha256'].lower()):
raise SystemExit(f'{claim_id}: invalid artifact digest')
try:
valid_until = dt.date.fromisoformat(claim['valid_until'])
except ValueError:
raise SystemExit(f'{claim_id}: invalid validity date')
reasons = []
if valid_until < today:
reasons.append('evidence-expired')
if claim['evidence_type'] == 'declaration-only':
reasons.append('no-independent-evidence')
if reasons:
blocked.append({'id': claim_id, 'reasons': reasons})
result = {'claim_count': len(claims), 'blocked_count': len(blocked), 'blocked': blocked, 'status': 'pass' if not blocked else 'blocked'}
print(json.dumps(result, ensure_ascii=False, indent=2))第六组问题写清限制、到期和争议处理
每份证据都要有适用平台、候选、配置、设备范围和有效期。Android 或 iOS 大版本、NDK、Xcode、签名流程、加固工具、业务依赖或候选摘要变化时,哪些证据必须重验应预先约定。写永久有效会把历史测试错误扩张到未来环境。
合同验收应按 claim 列出 required evidence、通过标准、允许限制、阻塞条件和修复时限。一个能力阻塞不应被其他项平均成总体合格;可接受限制也必须由买方明确批准,并说明影响范围和到期日期。供应商不能用保密、行业惯例或客户很多替代当前候选证据。
准备采购评估时,可提交候选和配置摘要、保护边界、设备与场景矩阵、原始测试回执、provenance、attestation、平台签名证据、限制清单和责任人。申请入口由御盾中央平台统一承接。没有真实附件和复核结果时,只能登记待验证,不能写供应商已通过、攻击已阻断或兼容性已确认。
事实依据与适用边界
以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。
| 本文判断 | 事实或工程依据 | 适用限制 |
|---|---|---|
| 移动端抗篡改与抗逆向属于纵深防御控制。 | OWASP MASVS-RESILIENCE 给出移动端韧性控制的验证方向。 | 控制目录不证明当前候选已经实施控制或达到任何防护强度。 |
| 安全发布需要保留来源、构建、验证和变更证据。 | NIST SP 800-218 SSDF 将安全软件开发与供应链风险纳入组织实践。 | 组织级框架不定义某个加固产品的功能、等级或采购通过结果。 |
| 构建证明应绑定产物主体、构建者、构建类型、参数和依赖材料。 | SLSA Provenance v1.1 定义构建 provenance 的字段和语义。 | provenance 只证明记录的构建过程,不单独证明运行时安全和兼容。 |
| 供应链声明应把产物摘要和有类型的负载绑定。 | in-toto Attestation Statement v1 定义 subject、predicateType 和 predicate 结构。 | 格式正确不保证内容真实,仍需可信签发者、签名和门禁验证。 |
| Android 使用应用签名建立更新身份,并有不同签名方案覆盖范围。 | AOSP app signing 说明 Android 应用签名和 APK 签名方案。 | 签名有效只证明覆盖范围内完整性和签名者身份,不证明业务代码安全。 |
| Apple 平台通过代码签名、证书和运行验证建立 App 身份。 | Apple app code signing process 说明 Apple 应用代码签名流程。 | Apple 签名链不能与 Android APK 签名方案混为同一证据。 |
| 供应商每项能力声明都应绑定候选、证据、有效期、限制和复核人。 | 工程判断:缺少这些字段时,买方无法确认报告对象、适用范围和责任。 | 字段完整只允许进入复核,不自动证明声明内容真实。 |
| 供应商比较不能用无数据的排名替代逐项证据门禁。 | 工程判断:术语数量、承诺强度和材料篇幅都不能替代当前候选的可复核事实。 | 证据门禁帮助采购决策,但最终风险接受仍由买方结合业务场景决定。 |
工程常见问题
供应商提供客户名单和案例,能否替代当前候选测试?
不能。其他客户的应用、配置、设备和业务路径不同,应要求当前候选摘要绑定的保护、兼容和签名回执。
加固报告写明功能已开启,是否就是保护有效?
不是。配置存在属于静态证据,还需说明保护对象、运行边界、测试方法、失败条件和同一候选的动态回执。
设备兼容通过率很高,为什么仍要看失败明细?
总体比例可能掩盖关键设备和业务路径,也可能把未执行项放进分母。失败明细才能复现问题并判断影响范围。
有 SLSA provenance 是否就能证明加固服务安全?
不能。先核对 subject 和签发者;它证明记录的构建过程,不替代保护强度、漏洞、运行兼容和业务测试。
Android 和 iOS 能否共用一份签名验收表?
可以共用采购框架,但平台字段和验证方法必须分开。APK 签名方案与 Apple 证书、provisioning、entitlements 不能混用。
申请软件加固供应商证据评估要准备什么?
准备候选与配置摘要、保护边界、兼容矩阵、测试回执、provenance、attestation、平台签名证据、限制和责任人,再通过御盾中央平台提交。