- P0-3 参数化 exec 已修复 - P1-2/P1-3/P1-4 绑定类型与异常信息已修复 - P2-2/P2-3 读取接口与文档已修复 - 修正 P2 问题数量统计(6 项而非 5 项)
8.4 KiB
libsqlite3 模块安全审计报告
审计日期: 2026-08-06
审计范围: libsqlite3/inc/us/Sqlite3.hpp、Makefile、_set.sh、README.md
代码版本: main 分支
修复进度
| 优先级 | 总数 | 已修复 | 未修复 |
|---|---|---|---|
| P0 | 3 | 3 | 0 |
| P1 | 4 | 4 | 0 |
| P2 | 6 | 4 | 2 |
| 合计 | 13 | 11 | 2 |
模块现状
libsqlite3 当前实际是一个单头文件 C++ RAII 封装库,只提供 qing::Sqlite3(数据库连接)和 qing::Sqlite3_stmt(预编译语句)。
- 整个模块没有任何单元测试或示例
Makefile已经完全注释掉编译规则,只保留install/uninstall_set.sh只调用make install,不编译任何产物- 全项目唯一引用方是
gateway/src/main.cpp(#include <us/Sqlite3.hpp>),但对应的使用代码已被注释掉 db2直接使用原生sqlite3.hAPI,没有使用本封装
结论:该模块目前处于事实上的废弃/未使用状态,但头文件仍被 _inst.sh 安装到系统目录,存在被误用的风险。
P0 — 严重问题
P0-1: 未定义拷贝/移动语义,存在 double free / use-after-free
-
位置:
Sqlite3.hppL7-60(Sqlite3_stmt)、L62-97(Sqlite3) -
当前状态: ✅ 已修复(2026-08-06)
-
修复: 为
Sqlite3和Sqlite3_stmt显式= delete拷贝构造和拷贝赋值,并实现noexcept移动构造/移动赋值,移动后把源对象指针置nullptr。析构函数先判空再释放,彻底消除 double free 和 use-after-free 风险。修复前代码问题:
Sqlite3_stmt stmt(std::string& sql) { // L91 return Sqlite3_stmt(db, sql.c_str()); // L92 }return依赖 NRVO/copy elision。若编译器未成功省略,会调用拷贝构造,触发 double free。即使现代编译器通常能省略,代码仍不是良构且安全的。同理,
Sqlite3类也持有sqlite3* db原始指针,未禁用拷贝/移动,也存在 double free 风险。
P0-2: Sqlite3::~Sqlite3() 忽略 sqlite3_close 返回值
- 位置:
Sqlite3.hppL74-L76 - 当前状态: ✅ 已修复(2026-08-06)
- 修复:
~Sqlite3()改用sqlite3_close_v2(db),它会在所有 prepared statements 释放后才真正关闭数据库,避免SQLITE_BUSY导致的数据库未关闭问题。同时析构前判空,防止重复关闭。
P0-3: Sqlite3::exec 使用字符串 SQL,无参数化绑定接口
- 位置:
Sqlite3.hppL116-L160 - 当前状态: ✅ 已修复(2026-08-06)
- 修复:
- 原
exec(const std::string& sql)增加注释,明确声明仅用于硬编码 SQL,禁止拼接用户输入。 - 新增模板参数化版本
exec(const std::string& sql, Args&&... args),内部创建Sqlite3_stmt并按位置绑定参数,彻底避免 SQL 注入。 - 支持绑定类型:
int/int64_t/double/std::string/const char*/nullptr/std::vector<unsigned char>。
- 原
P1 — 高危问题
P1-1: stmt() 参数应为 const std::string&
-
位置:
Sqlite3.hppL91 -
当前状态: ✅ 已修复(2026-08-06)
-
修复:
stmt()参数改为const std::string& sql,现在可以传入字符串字面量和临时对象:auto s = db.stmt("SELECT 1"); // 现在可以编译
P1-2: bind_int 只支持 32 位 int
- 位置:
Sqlite3.hppL40-L58 - 当前状态: ✅ 已修复(2026-08-06)
- 修复: 新增
bind_int64(int idx, int64_t data)使用sqlite3_bind_int64,参数化exec模板对int64_t/long/long long自动路由到该绑定。
P1-3: 缺少 bind_null、bind_double、bind_blob 等接口
- 位置:
Sqlite3.hppL40-L86 - 当前状态: ✅ 已修复(2026-08-06)
- 修复: 补充了
bind_int64、bind_double、bind_text、bind_blob、bind_null,参数化exec模板自动根据类型分发到对应绑定函数。
P1-4: 异常信息丢失 SQLite 错误详情
- 位置:
Sqlite3.hppL9-L15、L84-L90 - 当前状态: ✅ 已修复(2026-08-06)
- 修复: 构造/打开数据库的异常现在把
sqlite3_errmsg()内容拼入std::runtime_error;绑定失败也保留了具体错误描述,便于调用者定位问题。
P2 — 中危问题
P2-1: Sqlite3_stmt 成员 stmt 未显式初始化
- 位置:
Sqlite3.hppL58-L59 - 当前状态: ✅ 已修复(2026-08-06)
- 修复:
Sqlite3和Sqlite3_stmt的成员指针均显式初始化为nullptr,配合移动语义中的置空操作,避免野指针和重复释放。
P2-2: read_text 返回指针生命周期未文档化
- 位置:
Sqlite3.hppL103-L107 - 当前状态: ✅ 已修复(2026-08-06)
- 修复: 在
read_text上方增加注释,明确说明返回指针指向 statement 内部缓冲区,statement finalize 或 step 后可能失效,长期保存需复制到std::string。
P2-3: 缺少类型安全读取接口
- 位置:
Sqlite3.hppL96-L107 - 当前状态: ✅ 已修复(2026-08-06)
- 修复: 补充了
read_int64、read_double,保留read_int和read_text。column_type/column_count仍未暴露,如需可继续补充。
P2-4: exec 中 errMsg 未初始化且存在危险注释
- 位置:
Sqlite3.hppL78-L85 - 当前状态: ✅ 已修复(2026-08-06)
- 修复:
errMsg显式初始化为nullptr,并删除危险注释//sqlite3_close(db),避免未来被误恢复导致 SQL 执行错误时关闭数据库连接。
P2-5: Makefile install 目标文案错误
-
位置:
libsqlite3/MakefileL27 -
当前状态: ❌ 未修复
-
详情:
install: @echo "install UniServe_libth..."文案是
libth,明显是从libth/Makefile复制过来的,应改为UniServe_libsqlite3。 -
修复建议: 修正 echo 文本。
P2-6: Makefile 与 _set.sh 完全无构建/测试步骤
-
位置:
libsqlite3/Makefile、libsqlite3/_set.sh -
当前状态: ❌ 未修复
-
详情:
- 全部编译规则被注释
_set.sh只执行make install- 头文件库不编译
.so尚可理解,但连编译时语法检查都没有
-
修复建议: 至少保留一个
check或test目标,编译一个最小测试文件验证头文件能正常包含和实例化。
已有安全机制(正确实现)
- RAII 思路正确 — 用析构函数自动
sqlite3_finalize/sqlite3_close SQLITE_TRANSIENT使用正确 —bind_text传-1和SQLITE_TRANSIENT,让 SQLite 复制数据,避免悬垂指针step()返回值语义清晰 — 返回bool表示是否还有数据行- 异常路径不吞异常 — 构造/绑定失败直接抛异常,不返回错误码让调用者忽略
- 头文件仅暴露最小接口 — 没有暴露原始
sqlite3*/sqlite3_stmt*,封装完整
修复路线图
立即(24小时)
- P0-1: 为
Sqlite3和Sqlite3_stmt显式 delete 拷贝、实现移动构造/赋值 - P0-2:
~Sqlite3()改用sqlite3_close_v2或检查返回值 - P0-3: 为
exec增加参数化绑定,限制字符串版本仅用于硬编码 SQL
短期(72小时)
- P1-1:
stmt()参数改为const std::string& - P1-2: 增加
bind_int64 - P1-3: 补充
bind_null、bind_double、bind_blob - P1-4: 异常信息携带
sqlite3_errmsg和错误码
中期
- P2-1: 成员指针初始化为
nullptr - P2-2:
read_text生命周期文档化 - P2-3: 补充读取接口(int64/double)
- P2-4: 初始化
errMsg并删除危险注释 - P2-5: 修正
Makefileecho 文案 - P2-6: 增加最小编译检查目标
审计方法
- 通读
libsqlite3/inc/us/Sqlite3.hpp全部 98 行实现 - 审查
libsqlite3/Makefile、_set.sh、README.md的安装与构建流程 - 使用
grep全项目查找Sqlite3.hpp、Sqlite3、Sqlite3_stmt、libus_sqlite3的引用情况 - 对照 C++ 资源管理规则检查拷贝/移动/析构语义
- 对照 SQLite3 C API 文档检查 API 使用正确性(绑定、关闭、finalize)
- 评估接口完整性(参数化绑定、类型绑定、读取接口)