Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← C++ 编程 / C++ Programming

插件系统 / Plugin Systems

1. 插件工程:可演进的模块边界 / Plugin Engineering and Evolvable Module Boundaries

2. 运行时动态加载:LoadLibrary 与 dlopen —— 打开插件的大门 / Runtime Dynamic Loading with LoadLibrary and Dlopen

3. 插件接口设计:C ABI、函数表与受控 C++ 接口 / Plugin Interface Design with C ABI, Function Tables, and Controlled C++ Interfaces

4. CMake 构建完整插件项目 / Building a Complete Plugin Project with CMake

5. 插件架构设计模式:发现、生命周期、依赖与通信 / Plugin Architecture Patterns for Discovery, Lifecycle, Dependencies, and Communication

6. 跨平台插件开发:Windows / Linux / macOS 统一策略

7. 插件热加载与版本管理 / Plugin Hot Reloading and Version Management

8. 插件安全:沙箱、进程隔离与权限控制 / Plugin Security with Sandboxing, Process Isolation, and Permissions

9. 工业软件插件系统案例分析 / Industrial Software Plugin System Case Study

10. 综合实战:版本化 C ABI 插件系统 / Full Project: Versioned C ABI Plugin System

本页目录

插件安全:沙箱、进程隔离与权限控制 / Plugin Security with Sandboxing, Process Isolation, and Permissions ​

📅 创建时间:2026-07-13 🏷️ 标签:#插件安全 #沙箱 #进程隔离 #seccomp #代码签名 📚 前置知识:runtime dynamic loading, plugin architecture patterns


📋 本章目标 ​

  • 全面认识第三方插件的安全风险
  • 理解同进程内防护的局限性
  • 掌握进程隔离方案:subprocess + IPC
  • 了解 Linux 沙箱技术:seccomp、Landlock、cgroups
  • 理解代码签名与插件验证机制

第1部分:风险全景 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│              第三方插件的六大安全风险                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  风险1:恶意代码执行                                                         │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ 插件 = 可以执行任意代码 → 理论上可以做任何事                     │         │
│  │ dlopen 之后,插件的代码运行在宿主的进程空间内                    │         │
│  │ • 读取宿主内存中的敏感数据(密码、密钥、用户数据)               │         │
│  │ • 修改宿主的函数指针/虚函数表(hook 宿主逻辑)                  │         │
│  │ • 调用 system("rm -rf /")                                      │         │
│  │ • 网络连接:向外发送数据                                        │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  风险2:崩溃传播                                                              │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ 插件中的 segfault / null deref / stack overflow               │         │
│  │ → 同进程内 → 杀死整个进程(包括宿主和其他插件)                  │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  风险3:内存泄漏                                                              │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ 插件反复分配内存不释放 → 宿主内存逐渐耗尽 → OOM                 │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  风险4:资源滥用                                                              │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ CPU 100% 死循环 / 磁盘写满 / 网络带宽占满                       │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  风险5:符号劫持                                                              │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ 恶意插件导出和宿主内部函数同名的符号                             │         │
│  │ 由于动态链接器的符号介入规则 → 恶意的版本可能被优先调用!        │         │
│  │ → 这也是为什么插件要用 RTLD_LOCAL 加载                          │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  风险6:供应链攻击                                                            │
│  ┌───────────────────────────────────────────────────────────────┐         │
│  │ 插件本身没问题,但依赖了有漏洞的第三方库                         │         │
│  │ 或者发布渠道被篡改(下载站点的 .dll 被替换)                    │         │
│  └───────────────────────────────────────────────────────────────┘         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

第2部分:防御策略分层 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│              安全的洋葱模型——多层防御                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│                        ┌─────────────┐                                      │
│                        │ 代码签名+验证│ ← 第4层:来源可信                     │
│                        ├─────────────┤                                      │
│                        │  权限声明   │ ← 第3层:最小权限                      │
│                        ├─────────────┤                                      │
│                        │  进程隔离   │ ← 第2层:爆炸半径控制                  │
│                        ├─────────────┤                                      │
│                        │  代码审查   │ ← 第1层:信任但验证                    │
│                        └─────────────┘                                      │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

2.1 同进程内防护(轻量但有限) ​

cpp
class PluginHost {
    bool loadPlugin(const std::string& path) {
        // 1. 加载前验证签名(如果可以)
        if (!verifySignature(path)) return false;

        // 2. 用 RTLD_LOCAL 隔离符号
        void* handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);

        // 3. init 时设置超时
        auto future = std::async([&] { return plugin->initialize(); });
        if (future.wait_for(5s) == std::future_status::timeout) {
            // 初始化超时 → 卸载
        }
    }

    // 4. 每个调用都用 try-catch(虽然跨 ABI catch 不保证有效)
    int safeCall(IPlugin* plugin, const std::function<int()>& fn) {
        // 注意:segfault 无法被 try-catch 捕获!
        signal(SIGSEGV, segfault_handler);   // 只能捕获,不能恢复
        return fn();
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

同进程防护的本质局限:segfault 和死循环无法被优雅处理——它们直接作用于进程本身。

2.2 进程隔离 —— 真正的安全方案 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│              进程隔离方案架构                                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  宿主进程                              插件进程                             │
│  (plugin_host)                        (plugin_sandbox)                      │
│  ┌─────────────────────┐             ┌─────────────────────┐              │
│  │                     │             │                     │              │
│  │  PluginManager      │    IPC      │  PluginRunner       │              │
│  │                     │◄───────────►│                     │              │
│  │  • 发现插件         │   pipe/     │  • dlopen 插件      │              │
│  │  • 管理进程生命周期  │   socket/   │  • 调用插件         │              │
│  │  • 超时检测         │   shm       │  • 返回结果         │              │
│  │                     │             │                     │              │
│  │  plugin_host        │             │  plugin_sandbox     │              │
│  └─────────────────────┘             └─────────────────────┘              │
│                                                │                            │
│                                                │ seccomp / Landlock        │
│                                                │ 资源限制 (cgroups)         │
│                                                                             │
│  优势:                                                                      │
│  • 插件崩溃 → 只杀死沙箱进程 → 宿主不受影响                                   │
│  • 插件 OOM → 只触发沙箱进程的 OOM killer                                     │
│  • 插件 CPU 100% → 只占用沙箱进程 → 宿主仍然响应                              │
│                                                                             │
│  代价:                                                                      │
│  • IPC 序列化/反序列化开销                                                   │
│  • 延迟增加                                                                 │
│  • 架构复杂度显著上升                                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

第3部分:Linux 沙箱技术 ​

3.1 seccomp —— 限制系统调用 ​

c
#include <seccomp.h>

// 在沙箱进程中设置 seccomp 过滤器
void setup_seccomp() {
    scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);  // 默认:杀死进程

    // 白名单:只允许这些系统调用
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
    // 注意:没有 open、socket、fork、exec —— 插件无法访问外部

    seccomp_load(ctx);
    seccomp_release(ctx);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

3.2 Landlock —— 限制文件系统访问 ​

c
#include <linux/landlock.h>

void setup_landlock(const char* plugin_dir) {
    struct landlock_ruleset_attr ruleset_attr = {
        .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
                             LANDLOCK_ACCESS_FS_WRITE_FILE,
    };
    int ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);

    // 只允许读取插件目录
    struct landlock_path_beneath_attr path_attr = {
        .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE,
        .parent_fd = open(plugin_dir, O_RDONLY),
    };
    landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_attr, 0);

    landlock_restrict_self(ruleset_fd, 0);
    close(ruleset_fd);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

第4部分:代码签名与验证 ​

4.1 加载前验证 ​

cpp
// 简单的 GPG 签名验证流程(Linux)
bool verifyPluginSignature(const std::string& plugin_path) {
    // 期望存在 plugin.so.sig 签名文件
    std::string sig_path = plugin_path + ".sig";

    // 用 GPG 验证
    std::string cmd = "gpg --verify " + sig_path + " " + plugin_path;
    int result = system(cmd.c_str());
    return result == 0;
}

// 生产环境中可以用 libgpgme 编程接口替代 system() 调用
1
2
3
4
5
6
7
8
9
10
11
12

4.2 权限声明模型 ​

json
// plugin_manifest.json(随插件分发)
{
    "name": "Math Plugin",
    "version": "1.0.0",
    "signature": "sha256:abc123...",
    "permissions": {
        "filesystem": {
            "read": ["$PLUGIN_DATA/*"],
            "write": ["$PLUGIN_DATA/cache/*"]
        },
        "network": {
            "domains": []           // 不需要网络
        },
        "system": {
            "max_memory_mb": 512,
            "max_cpu_percent": 50
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

核心总结 ​

┌─────────────────────────────────────────────────────────────────────────────┐
│              插件安全速查                                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  六大风险:恶意代码 / 崩溃传播 / 内存泄漏 / 资源滥用 / 符号劫持 / 供应链攻击   │
│                                                                             │
│  防御分层:代码审查 → 进程隔离 → 权限声明 → 代码签名                          │
│                                                                             │
│  进程隔离 = 最有效方案(VS Code 就是这样做的)                                │
│                                                                             │
│  Linux 沙箱三件套:                                                           │
│    seccomp —— 限制系统调用                                                   │
│    Landlock —— 限制文件访问                                                  │
│    cgroups —— 限制资源(CPU/内存)                                           │
│                                                                             │
│  代码签名 + manifest 权限声明 = 工业级方案                                    │
│                                                                             │
│  同进程 = 方便但脆弱(适合信任的插件和内部工具)                                │
│  进程隔离 = 安全但复杂(适合不信任的第三方插件)                               │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

章节测试 ​

测试1:信任等级 ​

哪些插件可以安全地运行在同进程中?哪些应该用进程隔离?

测试2:seccomp 的作用 ​

seccomp 是如何保护系统的?它和 Landlock 分别限制什么?

测试3:RTLD_LOCAL 和安全 ​

为什么 RTLD_LOCAL 是安全加载插件的必要条件?


参考答案 ​

测试1答案 ​

答案:同进程中:自己团队开发的、代码审查过的、来源可信的内部插件。进程隔离:从第三方市场下载的、来源不明的、不能审查源码的外部插件。关键判断标准是"你是否完全信任插件的作者"。

测试2答案 ​

答案:seccomp 限制的是系统调用——控制进程能调用哪些内核功能(不能 open 文件、不能 socket、不能 fork 等)。Landlock 限制的是文件系统访问——控制进程能读/写哪些目录和文件。两者互补:seccomp 控制"能力",Landlock 控制"数据访问范围"。

测试3答案 ​

答案:RTLD_LOCAL 确保插件的符号只对它自己可见,不会污染全局符号表。如果不用 RTLD_LOCAL(或用 RTLD_GLOBAL),恶意插件可以导出和宿主内部函数同名的符号。由于 ELF 动态链接器的符号介入(symbol interposition)规则,后加载的符号可能覆盖先加载的——插件导出的"假" validate_token() 可能被宿主的其他模块调用到。


相关笔记 ​

  • runtime dynamic loading - dlopen flags 详解
  • plugin architecture patterns - 插件发现与生命周期
  • hot reload versioning - 热加载

下一步学习 ​

  • [ ] 阅读 13 - 工业软件插件系统案例分析

学习状态:🟡 开始学习

工程深化:把本篇知识落到项目里 ​

这一节不是为了凑篇幅,而是把《插件安全:沙箱、进程隔离与权限控制 / Plugin Security with Sandboxing, Process Isolation, and Permissions》从“知道概念”推进到“能在项目里稳定使用”。 阅读时可以把每个知识点都追问成四件事:它保护什么边界,失败时有什么现象,怎样最小复现,怎样写进团队流程。

text
concept -> boundary -> failure signal -> minimal proof -> project rule
1

工程切片 1:最小可复现样例 ​

**场景。**围绕 信任边界 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。

**边界。**先判断这里讨论的是 信任边界、签名 还是 沙箱 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 信任边界 -> 签名 -> 沙箱 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 2:接口边界 ​

**场景。**围绕 签名 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。

**边界。**先判断这里讨论的是 签名、沙箱 还是 权限 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 签名 -> 沙箱 -> 权限 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 3:失败注入 ​

**场景。**围绕 沙箱 建一个很小的案例,不要一开始就放进完整业务系统。故意制造一个常见错误,让日志、断言或测试先失败,再用修复后的证据说明规则生效。

**边界。**先判断这里讨论的是 沙箱、权限 还是 输入校验 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 沙箱 -> 权限 -> 输入校验 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 4:跨平台差异 ​

**场景。**围绕 权限 建一个很小的案例,不要一开始就放进完整业务系统。至少比较 Windows、Linux 或不同编译器下的一个差异,记录差异属于标准、实现还是平台约定。

**边界。**先判断这里讨论的是 权限、输入校验 还是 审计日志 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 权限 -> 输入校验 -> 审计日志 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 5:性能观察 ​

**场景。**围绕 输入校验 建一个很小的案例,不要一开始就放进完整业务系统。用小规模和压力规模各跑一次,区分算法成本、同步成本、I/O 成本和工具链配置成本。

**边界。**先判断这里讨论的是 输入校验、审计日志 还是 信任边界 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 输入校验 -> 审计日志 -> 信任边界 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 6:生命周期 ​

**场景。**围绕 审计日志 建一个很小的案例,不要一开始就放进完整业务系统。标出资源创建、转移、共享、停止和销毁的顺序,特别关注错误返回和提前退出路径。

**边界。**先判断这里讨论的是 审计日志、信任边界 还是 签名 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 审计日志 -> 信任边界 -> 签名 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 7:诊断证据 ​

**场景。**围绕 信任边界 建一个很小的案例,不要一开始就放进完整业务系统。保留命令、日志、符号、栈、测试输出或截图,让结论可以被另一个环境重新验证。

**边界。**先判断这里讨论的是 信任边界、签名 还是 沙箱 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 信任边界 -> 签名 -> 沙箱 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 8:维护策略 ​

**场景。**围绕 签名 建一个很小的案例,不要一开始就放进完整业务系统。把一次性经验沉淀到 README、CI、脚本、示例工程或检查表里,避免只存在个人记忆中。

**边界。**先判断这里讨论的是 签名、沙箱 还是 权限 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 签名 -> 沙箱 -> 权限 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 9:版本演进 ​

**场景。**围绕 沙箱 建一个很小的案例,不要一开始就放进完整业务系统。为未来变更预留兼容策略:版本号、特性位、弃用窗口、迁移脚本和回滚入口。

**边界。**先判断这里讨论的是 沙箱、权限 还是 输入校验 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 沙箱 -> 权限 -> 输入校验 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 10:最小消费者 ​

**场景。**围绕 权限 建一个很小的案例,不要一开始就放进完整业务系统。从使用者角度写一个小程序或小工程,只依赖公开接口,验证安装包、头文件和运行时行为。

**边界。**先判断这里讨论的是 权限、输入校验 还是 审计日志 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 权限 -> 输入校验 -> 审计日志 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 11:边界复盘 ​

**场景。**围绕 输入校验 建一个很小的案例,不要一开始就放进完整业务系统。用一张表说明问题发生在源码、编译、链接、加载、运行、关闭或发布中的哪一层。

**边界。**先判断这里讨论的是 输入校验、审计日志 还是 信任边界 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 输入校验 -> 审计日志 -> 信任边界 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 12:反例训练 ​

**场景。**围绕 审计日志 建一个很小的案例,不要一开始就放进完整业务系统。写出一个看似能工作但不可维护的方案,再说明它在规模、团队协作或发布时会怎样失败。

**边界。**先判断这里讨论的是 审计日志、信任边界 还是 签名 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 审计日志 -> 信任边界 -> 签名 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 13:最小可复现样例 ​

**场景。**围绕 信任边界 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。

**边界。**先判断这里讨论的是 信任边界、签名 还是 沙箱 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 信任边界 -> 签名 -> 沙箱 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 14:接口边界 ​

**场景。**围绕 签名 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。

**边界。**先判断这里讨论的是 签名、沙箱 还是 权限 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 签名 -> 沙箱 -> 权限 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

本篇收束 ​

掌握《插件安全:沙箱、进程隔离与权限控制 / Plugin Security with Sandboxing, Process Isolation, and Permissions》的标志,不是记住所有名词,而是能把 信任边界、签名、沙箱、权限、输入校验、审计日志 放进一条可验证的工程链路。 先用最小样例建立判断,再用测试和脚本固定判断,最后把失败证据留给未来的自己和团队。

最后更新于:

Pager
上一篇7. 插件热加载与版本管理 / Plugin Hot Reloading and Version Management
下一篇9. 工业软件插件系统案例分析 / Industrial Software Plugin System Case Study

持续记录,持续成长

Copyright © Tidenflow