先看结论与判断条件

  • 资产不是代码文件清单,而是被窃取、篡改、重放或绕过后会造成具体业务损失的算法、授权决策、数据、身份和发布能力。
  • 移动客户端运行在用户控制的设备上,端侧控制应视为纵深防御;高价值授权和长期秘密仍需由服务端权限、审计和生命周期约束承担。
  • 威胁记录要写清行动者、前置条件、攻击面、目标动作、业务影响和可观察证据,不用“防破解”“防黑产”这样的宽泛标签。
  • 每个控制都要有明确目标和边界,代码变换、运行时检查、平台完整性信号、服务端授权与发布链证据不能互相替代。
  • PoC 应围绕少量高价值资产和可复现滥用场景,使用同一候选、对照包、业务断言、兼容矩阵与证据回执,不以功能开关数量评分。
  • 残余风险必须进入采购与上线决策,说明仍可观察的信息、可能误判、离线边界、平台依赖和未覆盖设备,而不是把加固写成绝对阻断。

先定义要保住的业务结果,再讨论加固功能

软件加固项目最常见的起点错误,是先拿到一张功能清单,再让研发逐项勾选混淆、虚拟化、完整性检查或反调试。功能名称无法回答哪段业务最重要、失败会损失什么、攻击者需要什么条件,也无法决定性能和兼容成本是否值得。正确顺序是先定义业务结果与可接受损失,再选择能缩小风险的控制组合。

资产应使用业务语言命名。例如离线授权判定影响付费权益,交易风控规则影响欺诈损失,端侧模型参数影响研发投入,签名发布身份影响更新渠道,用户凭据和健康数据影响隐私与合规。仅写 core.jar、libnative.so 或 LoginManager 类名不够,因为文件位置会变,业务价值与授权边界才是长期可追踪对象。

每项资产需要 business_owner 和 evidence_owner。前者确认业务影响、可接受停机与降级方式,后者负责准备候选摘要、数据流、验证用例和发布回执。没有所有者的资产通常会变成抽象高风险项,既没人批准残余风险,也没人判断 PoC 是否真正覆盖,最终只能按供应商演示做决定。

把技术对象整理成业务资产的示例
技术对象业务资产表达受损后果优先证据
离线许可证代码付费权益与使用期限决策未授权使用、收入损失或误拒绝决策输入、服务端权威、离线时限与回归
端侧模型文件训练投入、推理能力与模型版本身份知识资产泄露、错误模型替换或输出异常文件摘要、加载链、授权和输出边界
API 调用模块敏感服务访问权限与配额凭据滥用、越权请求或成本失控服务端令牌、scope、有效期和审计
交易风控逻辑交易允许、拒绝与复核决策欺诈放行、正常用户误拒或合规风险服务端最终决策、输入完整性和回放证据
应用签名与发布配置官方版本身份和可持续更新能力伪造分发、更新中断或供应链污染签名身份、构建 provenance 和发布回执
端侧用户数据个人信息、业务状态与恢复能力隐私泄露、状态篡改或不可恢复损失数据分类、存储边界、密钥和恢复用例

画清端侧、服务端和第三方信任边界

威胁模型必须先画数据和决策从哪里进入、经过什么组件、最终由谁授权。移动端设备可能被用户完全控制,包体和运行时状态可能被观察或修改,因此客户端不应被当作永久秘密保险箱。服务端、身份提供方、应用商店、推送服务、第三方 SDK 和离线文件都是独立边界,每次跨界都要记录认证、完整性与失败回退。

边界图不需要复杂工具,最小版本可以列出 process、data store、external entity 和 trust boundary,再为每条流标注数据类别、方向、认证方式、是否可重放和谁做最终决策。尤其要标出“客户端建议、服务端决定”的路径。若交易、授权或高成本 API 最终仍相信客户端布尔值,加固只能增加修改成本,无法替代服务端授权。

第三方组件也要进入模型。分析、支付、地图、广告、客服和端侧 AI SDK 可能读取数据、发起网络请求或引入 Native 库。企业需要知道它们拿到哪些资产、在哪个进程运行、由谁更新、失败时如何降级。只保护自研核心代码而不评估第三方数据流,会留下未被控制的访问路径和供应链变更。

  • 列出 App 进程、扩展进程、服务端和外部服务
  • 为每条数据流标注资产类型、方向和最终决策者
  • 识别客户端可观察、可修改和可重放的输入
  • 长期凭据、短期令牌与平台信号分别建模
  • 第三方 SDK 的数据访问、更新来源和降级路径可追踪
  • 离线模式与联网模式使用不同信任假设

把资产写成可检验的威胁陈述

高质量威胁陈述至少包含行动者、前置条件、攻击面、目标动作、业务影响与可观察证据。例如“获得安装包副本的人在离线环境修改授权分支,使过期权益继续可用,服务端在下次联网前无法复核”。它比“防破解”更有用,因为它明确离线窗口、决策位置、损失对象和可验证结果。

威胁陈述应保持公开安全,不写可运行攻击链、绕过脚本或内部防护细节。攻击面可以描述为包体静态分析、运行时状态修改、重打包分发、接口重放、敏感数据提取或供应链替换;验证计划则使用受控测试桩、完整性对照和授权回执。目标是决定控制边界,而不是提供滥用教程。

同一资产通常有多条威胁。例如端侧模型既可能被复制,也可能被替换导致错误输出;授权逻辑既可能被修改,也可能被重放旧服务端响应。应为每条威胁建立独立 threat_id,避免用一个“防逆向”控制覆盖所有影响。风险排序可以使用定性影响与可行性,但权重和阈值必须由企业风险策略决定。

威胁陈述从模糊到可检验的改写
模糊说法缺失信息可检验表达重点验证输出
防止破解资产、动作和损失均不清楚明确哪项授权决策被修改及有效窗口同候选授权断言与服务端回执
保护核心算法不知道复制还是篡改区分静态理解、模型提取和运行时替换可见性评审、完整性对照与残余信息
阻止重打包分发和身份边界缺失说明签名变化、渠道与服务端识别签名、安装身份和后端决策记录
检测不可信设备信号来源与处置不清指定平台信号、请求绑定和后端策略服务端验证、风险分层与误判边界
避免 API 滥用凭据与权限模型缺失明确长期秘密、短期 scope 和重放窗口令牌签发、资源授权和审计记录
保证代码安全控制域和验收条件缺失拆分存储、认证、平台、质量与韧性目标每个控制域独立取证

控制目标必须说明降低什么风险和不解决什么

OWASP MASVS-RESILIENCE 把抗篡改与抗逆向放在移动端韧性控制中,适合延长分析成本、发现部分完整性异常或保护高价值路径,但它属于纵深防御。服务端授权、短期令牌、签名发布链、数据最小化和审计仍是独立控制。把所有安全目标压给端侧加固,会让不可替代的服务端责任消失。

移动客户端中的静态 API Key 可能被逆向或拦截,敏感服务的长期凭据应留在服务端。客户端可以持有短期、限范围并绑定业务会话的令牌,但仍需资源服务器验证 audience、scope、有效期和用户权限。对密钥字符串做混淆只能提高直接搜索成本,不能把公共客户端变成可信秘密持有者。

平台完整性信号也要放在正确位置。Play Integrity 信号应靠近受保护操作,由后端解密、验证和决策;Apple App Attest 的证明同样需要服务端验证并绑定请求。两者都是风险信号,不是绝对设备可信,也不证明某个 VMP 配置或 Root 状态。模型应写清信号不可用、误判和服务降级时的业务策略。

  • 每个控制目标对应一条明确威胁而非功能名称
  • 端侧韧性、服务端授权和发布链分别承担责任
  • 长期服务凭据不以客户端混淆作为主要保护
  • 短期令牌具有明确用户、资源、scope 与有效期
  • 平台完整性和证明信号在服务端绑定业务请求
  • 信号缺失、误判与离线状态均有降级边界

建立资产、威胁、控制、验证和残余风险矩阵

威胁模型真正服务选型的结构,是每行把 asset_id、threat_id、attack_surface、control_objective、expected_control、verification 和 residual_risk 连起来。某项控制如果无法说明对应哪条威胁,可能只是无关功能;某条高风险威胁如果没有控制或验证,就应暴露为缺口,而不是用“综合防护”一词掩盖。

验证方法必须能产生项目证据。静态可见性评审说明哪些符号、字符串或结构仍可观察;受控篡改用例说明完整性异常如何被发现和处置;服务端测试说明授权是否拒绝无效请求;兼容矩阵说明保护候选是否保持业务语义。功能开启截图、编译成功或供应商口头说明都不能替代候选摘要与真实回执。

残余风险不是采购失败,而是控制边界的正式记录。它应说明仍能观察的元数据、无法在线验证的离线窗口、平台不支持时的策略、兼容性成本、潜在误判和未覆盖设备。业务所有者据此决定接受、转移、降低或避免风险。没有残余风险一栏的模型,往往会把“提高成本”误写成“阻止攻击”。

资产到控制和验证的决策矩阵
资产与威胁控制目标候选控制验证与残余风险
离线授权分支被修改缩短离线信任并增加修改成本服务端权威、限时凭据、重点代码保护离线回归、过期断言;残余离线窗口
端侧模型被复制或替换限制直接提取并识别错误模型资产加密、加载完整性、授权和版本绑定文件与加载对照;残余运行时可观察性
长期 API 凭据被提取客户端不持有长期秘密服务端代理、短期 scope 令牌和审计静态扫描、令牌滥用用例;残余会话令牌风险
应用被重打包分发识别官方身份并限制敏感服务签名验证、渠道身份、后端风险策略重签候选与后端处置;残余离线分发
运行时决策被篡改让关键决策在服务端并增加端侧修改成本服务端授权、运行时完整性与行为审计受控状态对照;残余设备控制权
构建或发布材料被替换绑定源码、构建、签名与产物受控构建、provenance、签名和发布门禁摘要与发布回执;残余权限和供应链风险

PoC 只验证高价值路径和可裁决证据

PoC 不应把全部应用、全部开关和全部设备一次性塞入。先选少量高价值资产,每项选择一个可复现威胁和一个关键兼容路径,建立原始候选与保护候选。固定源码、依赖、变体、签名、测试数据和设备条件,只让控制组合变化。这样才能区分保护效果、业务语义变化和环境噪声。

每个 PoC 都要写 acceptance、rejection 和 inconclusive。acceptance 可能包括目标结构可见性降低、受控异常被检测、服务端拒绝无效授权、候选在目标路径通过;rejection 包括业务语义破坏、签名身份错配、关键设备失败或控制未覆盖目标资产;证据缺失、测试未到达或结果不稳定则是 inconclusive,不能当通过。

比较方案时不要按功能开关数量累计分数。更可靠的问题是:高价值资产是否有控制覆盖,控制是否与威胁机制匹配,证据是否能绑定最终候选,兼容成本是否可接受,残余风险是否由业务所有者签收。某方案功能较少但能关闭关键风险,可能比功能繁多却无法验收的方案更适合。

  • PoC 资产由业务影响和威胁可行性选出
  • 每项资产只有一个清晰的主要验证问题
  • 原始与保护候选固定源码、签名、设备和数据
  • acceptance、rejection 与 inconclusive 预先定义
  • 保护结果和兼容结果使用独立回执
  • 最终候选摘要与 PoC 结论不可分离

用只读脚本检查威胁模型记录是否完整

下面的 Python 脚本读取脱敏威胁模型 JSON,要求每条记录包含 asset_id、business_owner、business_impact、trust_boundary、attack_surface、threat、control_objective、expected_control、verification 和 residual_risk。它不评估控制强度,也不触发任何安全测试,只检查选型材料是否形成从资产到残余风险的完整链。

脚本拒绝空记录、重复 ID、未知影响等级、缺少责任人和验证方法的输入,并检查至少一个 verification evidence_type。记录可以使用公开安全描述,不应包含密钥、内部地址、客户数据或可运行攻击步骤。输出按 impact 汇总缺口和人工复核项,便于采购、研发、安全和业务在同一表上讨论。

完整字段不等于高质量模型。业务所有者仍需确认影响,安全人员需检查威胁机制,研发需评估控制与兼容,测试需把 verification 变成候选回执。代码门禁只能阻止明显遗漏,不能自动给风险打分,更不能证明某项加固能力达到供应商描述的强度。

校验脱敏资产威胁控制记录的完整性
import json
import sys
from collections import Counter
from pathlib import Path

REQUIRED = {
    "asset_id",
    "business_owner",
    "business_impact",
    "trust_boundary",
    "attack_surface",
    "threat",
    "control_objective",
    "expected_control",
    "verification",
    "residual_risk",
}
VALID_IMPACTS = {"critical", "high", "moderate", "low"}

def stop(message):
    raise SystemExit(f"invalid threat model: {message}")

def text_present(value):
    return isinstance(value, str) and bool(value.strip())

if len(sys.argv) != 2:
    raise SystemExit("usage: python threat_model_gate.py MODEL_JSON")
model_path = Path(sys.argv[1]).resolve()
if not model_path.is_file():
    stop(f"file not found: {model_path}")
payload = json.loads(model_path.read_text(encoding="utf-8"))
records = payload.get("records")
if not isinstance(records, list) or not records:
    stop("records must be a non-empty list")
seen = set()
review = []
impact_counts = Counter()
for index, record in enumerate(records):
    if not isinstance(record, dict):
        stop(f"record {index} must be an object")
    missing = sorted(REQUIRED.difference(record))
    if missing:
        stop(f"record {index} missing {missing}")
    asset_id = record["asset_id"]
    if not text_present(asset_id) or asset_id in seen:
        stop(f"record {index} has invalid or duplicate asset_id")
    seen.add(asset_id)
    impact = record["business_impact"]
    if impact not in VALID_IMPACTS:
        stop(f"record {index} has invalid business_impact")
    impact_counts[impact] += 1
    text_fields = REQUIRED.difference({"verification", "business_impact"})
    empty_fields = sorted(field for field in text_fields if not text_present(record[field]))
    verification = record["verification"]
    if not isinstance(verification, dict) or not text_present(verification.get("method")):
        empty_fields.append("verification.method")
    if not isinstance(verification, dict) or not text_present(verification.get("evidence_type")):
        empty_fields.append("verification.evidence_type")
    if empty_fields:
        review.append({"asset_id": asset_id, "missing_or_empty": sorted(empty_fields)})
status = "BLOCK" if review else "READY_FOR_HUMAN_REVIEW"
output = {
    "model_id": payload.get("model_id"),
    "record_count": len(records),
    "impact_counts": dict(sorted(impact_counts.items())),
    "review": review,
    "gate": status,
}
print(json.dumps(output, ensure_ascii=False, indent=2, sort_keys=True))

把威胁模型变成采购、上线和持续维护合同

选型材料应要求方案逐项回答目标资产、控制位置、平台限制、候选产物、验证步骤、兼容边界和残余风险,而不是只提供功能名。商务承诺也要落到证据:谁生成候选、谁保管签名、如何复现配置、失败如何回滚、升级后是否重验。不能绑定最终交付包的演示,不应作为发布结论。

NIST SP 800-218 SSDF 强调来源、构建、验证、变更和供应链风险记录。对加固项目而言,这意味着威胁模型不是一次性文档:业务资产、第三方 SDK、平台接口、签名和加固工具升级后,都要检查原威胁与控制是否仍成立。新增功能若跨越信任边界,应在发布前增加威胁记录和验证用例。

最终决策表应列出已覆盖资产、未覆盖高风险、PoC 回执、兼容矩阵、残余风险所有者和下一次复核条件。需要把实际业务资产转换成加固 PoC 时,可通过御盾中央平台提交脱敏资产清单、信任边界、威胁陈述、候选身份和验证目标,先确定保护范围,再评估具体控制组合与上线门禁。

  • 采购响应逐项对应资产、威胁、控制与验证
  • 候选生成、签名保管、配置复现和回滚责任明确
  • 演示结果必须绑定最终候选才能进入决策
  • 第三方 SDK、平台和业务变化触发模型复核
  • 未覆盖风险具有明确所有者和接受条件
  • 上线门禁引用 PoC 回执与兼容矩阵而非功能清单

事实依据与适用边界

以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。

本文判断事实或工程依据适用限制
移动端抗篡改与抗逆向应作为纵深防御控制,不替代服务端授权和完整发布链。OWASP MASVS-RESILIENCE 把代码和运行时韧性纳入移动安全控制域。控制目录不证明任何候选包达到具体防护强度,也不定义某个加固产品的实现。
移动安全验收应按存储、密码学、认证、平台交互、代码质量和韧性等控制域分别取证。OWASP MASVS overview 说明 MASVS 的移动安全控制域与标准结构。标准给出控制分类,不提供御盾或任何具体方案的验收结论,也不能替代业务威胁模型。
安全软件发布应保留来源、构建、验证和变更证据。NIST SP 800-218 SSDF 把来源追溯、构建完整性、验证、维护与供应链风险纳入安全开发实践。SSDF 是组织级实践框架,不定义 App 加固功能、PoC 强度或企业风险接受阈值。
移动客户端中的静态 API Key 可能被逆向或拦截,长期敏感凭据应保留在服务端。Android insecure API usage 说明静态 API Key 的暴露风险,并建议通过服务端代理保护敏感服务。服务端代理仍需用户认证、最小权限、审计和滥用控制,不能自动阻止所有 API 滥用。
平台完整性信号应靠近受保护操作请求,并由后端解密、验证和决策。Play Integrity overview 说明完整性请求、后端验证与基于业务上下文的处置关系。平台信号不证明 VMP 配置、Root 状态、设备绝对可信或攻击已经被阻断。
App Attest 证明需要在服务端验证并与请求绑定。Apple App Attest server validation 说明服务端验证 attestation、assertion 和请求关联。平台证明是风险信号,不等于用户授权、设备绝对可信或所有运行时状态都未被修改。
加固选型应从业务资产、威胁、控制目标和验证回执出发,而不是按功能数量决定。工程判断:功能名称不能说明它降低哪项业务风险、如何验收或残余风险由谁接受。资产优先级、风险权重与接受条件必须由企业业务、安全、研发和合规共同确认。
每项 PoC 控制都应绑定最终候选、兼容用例与残余风险记录。工程判断:未绑定候选摘要和真实回执的演示无法证明交付包具有相同行为或保护边界。没有项目候选和实测证据时,不能声明任何保护强度、攻击阻断、兼容通过或商业效果。

工程常见问题

已经有加固功能清单,为什么还要先做威胁模型?

功能清单不能说明要保护的业务资产、可接受损失、控制边界和验收方法。威胁模型用于决定哪些能力值得进入 PoC。

哪些代码应该优先进入加固 PoC?

优先选择承载高价值授权、算法、数据或交易决策,且威胁和业务影响可清楚验证的路径,不按类数量或文件大小选择。

把 API Key 混淆后能否继续放在移动客户端?

混淆只能增加直接发现成本。长期敏感凭据应放在服务端,客户端使用短期、限范围并由资源服务器验证的授权。

Play Integrity 或 App Attest 能否替代软件加固?

不能互相替代。平台信号需服务端验证并用于风险决策,端侧韧性提高分析成本,服务端授权仍负责高价值操作。

威胁模型是否需要写具体攻击步骤?

不需要写可运行攻击链。记录行动者、前置条件、攻击面、目标动作、业务影响和安全验证方法即可。

准备加固选型评估最少要提供哪些材料?

准备业务资产、数据流与信任边界、威胁陈述、现有控制、目标候选、验证方法、兼容路径和残余风险所有者。

想用自己的 App 验证?

提交候选包、目标系统和关键业务路径,申请御盾 PoC 与兼容性评估。

继续阅读: 御盾 VMP 接入前准备清单