查询 25 次,耗时 0.2325 秒

从零工程化一个可复用 AI Skill:以本地 APK 配置风险审计为例

bbyyai

New member

bbyyai Rep
0
0
0
Rep
0
bbyyai Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
bbyyai 获得
0
0
0
获得
0
bbyyai 凭证
0
0
0
凭证
0
主题
8
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
一、背景:为什么 AI Skill 不能只是一段提示词

在实际项目中,一个可长期维护的 AI Skill,通常不只是“让模型检查一下文件”的提示词,而是由输入契约、工具调用、确定性逻辑、模型推理、输出格式、权限边界、测试用例和版本管理共同组成的能力单元。

以移动应用安全为例,我们希望实现一个“APK 配置风险审计 Skill”:调用者提供本地实验 APK 或已经解包的 AndroidManifest.xml,Skill 检查 exported 组件、明文流量配置、可调试标记和备份策略,并生成结构化报告。这里的重点不是让模型凭经验猜测,而是先通过本地工具获得证据,再让模型负责归纳、解释和给出修复建议。

这种设计可以避免三个常见问题:第一,纯提示词输出不稳定;第二,模型无法可靠解析二进制 APK;第三,Skill 在不同 Agent、工作流和 CI 环境中难以复用。

本文所有示例只面向自有应用、本地实验文件或已获授权的测试环境,不涉及对真实第三方目标的扫描。

二、核心原理:把 Skill 设计成有边界的函数

工程上可以把 Skill 抽象为:

Skill = 明确输入 + 受控工具 + 确定性处理 + 可选模型推理 + 结构化输出

一个合格的 Skill 至少要明确以下内容:

1. 输入是什么:本地文件路径、文本、URL,还是上游步骤产生的 JSON。
2. 输出是什么:自然语言、固定 JSON Schema,还是可供下游消费的事件。
3. 哪些步骤必须确定:例如 XML 属性提取、哈希计算、规则匹配不应交给模型猜测。
4. 哪些步骤适合模型:例如风险解释、修复建议改写、多个发现的优先级归纳。
5. 权限边界是什么:能否联网、能否执行命令、允许读取哪些目录、文件大小上限是多少。
6. 失败如何表达:参数错误、工具缺失、解析失败和模型超时应使用不同错误码。

本例采用“规则引擎负责发现,模型负责解释”的混合架构。即使模型不可用,Skill 也能返回基础扫描结果;模型可用时,再补充更易理解的影响分析和修复说明。

三、前置条件

建议准备以下环境:

1. Python 3.11 或更高版本。
2. 本地安装 apktool,用于解包授权 APK;如果直接输入已解包目录,则可以不安装。
3. pytest,用于单元测试与契约测试。
4. pydantic,用于输入输出校验。
5. 可选的模型 API。不要把密钥写入代码仓库,应通过环境变量或密钥管理系统注入。

初始化项目:

mkdir manifest-audit-skill
cd manifest-audit-skill
python -m venv .venv
source .venv/bin/activate
pip install pydantic pytest

Windows PowerShell 激活命令可使用:

.venv\Scripts\Activate.ps1

推荐目录结构:

manifest-audit-skill/
skill.yaml
src/
main.py
models.py
scanner.py
summarizer.py
tests/
fixtures/
test_contract.py
test_scanner.py
README.md

四、先定义 Skill 契约

不要先写提示词,先确定输入输出。输入可以定义为:

{
"input_path": "./samples/demo.apk",
"input_type": "apk",
"use_llm": false,
"max_findings": 100
}

建议的输出结构如下:

{
"skill_version": "1.0.0",
"status": "success",
"target_sha256": "文件摘要",
"findings": [
{
"rule_id": "ANDROID_DEBUGGABLE",
"severity": "high",
"evidence": "application android:debuggable=true",
"description": "发布包启用了调试能力",
"remediation": "在 release 构建中关闭 debuggable,并检查构建变体配置"
}
],
"summary": "共发现 1 项高风险配置",
"errors": []
}

契约设计有两个关键点。其一,evidence 必须来自工具或规则提取,不能由模型生成;其二,status 与 errors 要保留机器可读形式,不能只返回一句“执行失败”。这样下游 CI 才能根据严重级别决定是否阻断发布。

skill.yaml 可以记录元数据:

name: android-manifest-audit
version: 1.0.0
description: 审计本地 APK 或解包目录中的 Android Manifest 配置
entrypoint: python -m src.main
network: optional
input_schema: schemas/input.json
output_schema: schemas/output.json

不同 Skill 平台的清单格式可能不同,但名称、版本、入口、权限和输入输出 Schema 这几类信息应尽量保留。

五、分步骤实现

步骤 1:校验输入并限制访问范围

使用 Pydantic 定义输入模型。除了检查文件是否存在,还应限制扩展名、文件大小和允许访问的根目录。不要直接接受任意 shell 字符串,也不要通过字符串拼接执行 apktool。

伪代码如下:

class SkillInput(BaseModel):
input_path: str
input_type: Literal["apk", "decoded_dir"]
use_llm: bool = False
max_findings: int = Field(default=100, ge=1, le=500)

路径校验时先执行 resolve,再检查目标路径是否位于配置的 workspace 下。这样可以降低调用者利用相对路径读取系统文件的风险。

步骤 2:安全调用本地工具

处理 APK 时,为每次任务创建独立临时目录,并使用参数数组调用命令:

subprocess.run(
["apktool", "d", "-f", input_path, "-o", output_dir],
check=True,
timeout=120,
capture_output=True,
text=True,
shell=False
)

不要使用 shell=True,也不要构造类似“apktool d ”加用户输入的命令字符串。任务结束后清理临时目录,同时为并发任务分配唯一 ID,避免不同请求覆盖同一输出目录。

步骤 3:用确定性规则提取发现

解析 Manifest 时应使用 XML 解析器,而不是正则表达式。首批规则可以保持少而清晰:

1. ANDROID_DEBUGGABLE:application 的 android:debuggable 是否为 true。
2. CLEARTEXT_TRAFFIC:android:usesCleartextTraffic 是否为 true,并提示继续核对 Network Security Config。
3. EXPORTED_COMPONENT:组件是否显式导出,以及是否存在 intent-filter、权限保护等上下文。
4. BACKUP_ENABLED:android:allowBackup 的取值及目标系统版本相关策略。

这里需要特别注意:发现 exported=true 不等于组件必然存在漏洞。还要结合组件类型、调用权限、参数校验和实际业务能力判断。因此规则结果应表达为“待验证的攻击面”或“配置风险”,不要直接断言可被利用。

每条规则建议返回固定字段:rule_id、severity、location、evidence、description、remediation 和 references。severity 应由规则配置决定,不应让模型每次自由判断,否则同一输入可能得到不同级别。

步骤 4:将模型限制在解释层

可以将规则结果交给模型生成摘要,但提示词中应明确:

你是移动应用安全审计助手。只能依据提供的 findings 进行归纳,不得补充未经验证的组件、接口或漏洞。保留 rule_id 和 severity,不得修改 evidence。修复建议应优先给出 Android 官方配置与代码层面的防护方向。如果信息不足,应明确写“需要进一步验证”。

传给模型的数据要最小化。通常只需发送规则 ID、必要证据和少量上下文,不要上传完整 APK、签名材料、业务源码、令牌或用户数据。对于敏感项目,可以完全关闭模型调用,只使用本地模板生成报告。

步骤 5:提供统一调用入口

最简单的复用方式是让 Skill 从标准输入读取 JSON,并向标准输出写 JSON:

echo '{"input_path":"./samples/demo.apk","input_type":"apk","use_llm":false}' | python -m src.main

需要注意,日志应输出到标准错误,标准输出只保留最终 JSON,否则上游 Agent 可能无法解析结果。

如果要封装为 HTTP 服务,可以增加 POST /v1/skills/manifest-audit 接口,但仍应复用同一个 run_skill 函数,避免 CLI 与 API 各自实现一套扫描逻辑。

六、测试方法:不仅测试提示词

1. 单元测试

为每条规则准备最小化 Manifest 样本。例如一个样本只包含 debuggable=true,断言返回 ANDROID_DEBUGGABLE,且 evidence 与 severity 完全匹配。

pytest -q tests/test_scanner.py

2. 契约测试

验证所有成功和失败结果都符合输出 Schema。例如文件不存在时,status 应为 error,errors 中应包含 INPUT_NOT_FOUND,而不是抛出未处理异常。

3. 回归测试

保存一组已脱敏的固定输入及期望 findings。规则升级后运行:

pytest -q

如果输出变化,应明确判断是规则改进还是兼容性破坏。不要把模型生成的整段自然语言作为严格快照,因为措辞可能变化;应重点断言 rule_id、severity、evidence 和状态码。

4. 对抗性输入测试

至少覆盖超大文件、损坏 APK、畸形 XML、路径穿越、符号链接、重复组件名、超时和工具不存在等情况。此处测试目标是 Skill 自身的健壮性,不是攻击外部目标。

5. 模型评测

准备一组固定 findings,检查模型是否出现以下问题:凭空增加漏洞、修改证据、遗漏高风险项、给出无法执行的修复建议、输出不符合 JSON。生产环境可将 temperature 调低,并在模型输出后再次进行 Schema 校验。

七、版本化、复用与发布

建议采用语义化版本:新增兼容规则可升级次版本,删除字段或改变字段含义应升级主版本。规则本身也可以带 rule_version,便于追踪历史报告。

为了提高复用性,将实现拆成三层:scanner 只负责证据提取;policy 负责严重级别和阻断标准;presenter 负责自然语言或 JSON 报告。这样同一个扫描器可以被本地 CLI、CI 流水线、聊天 Agent 和批量审计平台调用。

在 CI 中可以配置策略:存在 critical 时退出码为 2,存在 high 时退出码为 1,只有中低风险时退出码为 0。是否阻断发布应由团队策略决定,不能把所有配置问题都一律视为发布失败。

发布包中应包含 skill.yaml、Schema、规则说明、测试样本说明和变更日志。不要把真实客户 APK、内部证书、API 密钥或完整扫描报告打包进 Skill。

八、风险与注意事项

1. 命令执行风险:所有外部工具都使用参数数组、超时和资源限制,禁止直接拼接用户输入。
2. 文件解析风险:APK 与 XML 都是不可信输入,建议在低权限用户、容器或隔离沙箱中执行。
3. 数据泄露风险:默认不开启远程模型;开启前应做脱敏、最小化传输和数据保留评估。
4. 提示注入风险:Manifest 的 label、meta-data 等文本可能包含诱导内容。它们只能作为不可信证据数据,不能覆盖系统指令或改变工具权限。
5. 误报风险:配置发现不代表漏洞成立。尤其是 exported 组件,需要结合权限、调用链和业务校验进一步确认。
6. 供应链风险:固定 apktool、Python 依赖和容器镜像版本,生成锁文件,并定期更新依赖。
7. 资源消耗风险:限制 APK 大小、解包后文件总量、递归深度、执行时间和并发数,防止压缩炸弹或异常样本拖垮服务。
8. 可审计性:记录 Skill 版本、规则版本、输入文件哈希、执行时间和工具版本,但不要在日志中记录敏感业务数据。

九、常见问题

问题 1:为什么不直接把 APK 发给大模型分析?

答:二进制解析、资源解包和 XML 属性提取更适合确定性工具。直接交给模型不仅结果难验证,还可能产生数据合规问题。模型应主要用于解释已有证据。

问题 2:Skill 与普通脚本有什么区别?

答:脚本通常只关注“能运行”,Skill 还需要明确契约、权限、错误语义、版本、测试与可组合性,使 Agent 或工作流能够稳定调用。

问题 3:如何避免模型输出破坏下游流程?

答:使用固定 JSON Schema,限制枚举字段,对模型输出进行二次校验。校验失败时返回规则引擎的基础结果,不要让整个 Skill 因摘要失败而丢失扫描证据。

问题 4:规则越多越好吗?

答:不是。优先实现证据明确、修复路径清晰的规则。模糊规则会制造大量误报,反而降低使用者对 Skill 的信任。

问题 5:怎样让其他 Skill 复用结果?

答:保持 findings 为稳定的结构化数组。例如后续可以接入“修复工单生成 Skill”或“发布风险汇总 Skill”,通过 rule_id、severity 和 remediation 消费结果,而不必重新解析自然语言报告。

十、总结

一个可靠的 AI Skill,本质上是可测试、可约束、可组合的软件能力,而不是一段包装精美的提示词。以本地 APK 配置审计为例,正确的工程路径是:先定义输入输出契约,再用受控工具提取证据,用规则引擎稳定判断,最后让模型在证据边界内解释结果。

当 Skill 具备最小权限、结构化输出、失败降级、契约测试、回归样本、版本管理和审计日志后,它才真正适合被 Agent、CI 或其他 Skill 反复调用。对于安全类 Skill,还应始终坚持授权范围、数据最小化和“发现不等于漏洞”的原则,这比单纯追求更长的模型回答更重要。
 
顶部