关于 openharmony-security-review
openharmony-security-review 是用于 OpenHarmony C++ 系统服务的结构化安全审查 Skill,面向代码审查人员。它重点检查 IPC 与网络输入、并发、敏感数据日志及权限验证风险。
主要功能
- 01检查 IPC 反序列化与边界
- 02审查共享状态锁与竞态
- 03识别死锁和 TOCTOU 风险
- 04检查日志中的敏感数据泄露
- 05审查权限验证
适用场景
- 01审查处理 MessageParcel 数据的 OpenHarmony 服务
- 02审计服务状态的并发访问
- 03检查服务日志是否暴露隐私数据
- 04评估特权操作的权限检查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill openharmony-security-review安装后在 Claude Code 中输入/openharmony-security-review确认已加载。
详细介绍
OpenHarmony 安全审查
概述
OpenHarmony 系统服务以高权限运行,并通过 IPC 和网络接口处理不可信输入。本技能提供了一套结构化方法,用于识别四个关键领域中的严重安全漏洞:外部输入处理、多线程竞态条件、敏感信息泄露和权限校验。
适用场景
digraph when_to_use {
"Reviewing OpenHarmony code?" [shape=diamond];
"Is it C++ system service?" [shape=diamond];
"Handles IPC/network data?" [shape=diamond];
"Has shared state?" [shape=diamond];
"Logs data?" [shape=diamond];
"Use this skill" [shape=box];
"Different skill needed" [shape=box];
"Reviewing OpenHarmony code?" -> "Different skill needed" [label="no"];
"Reviewing OpenHarmony code?" -> "Is it C++ system service?" [label="yes"];
"Is it C++ system service?" -> "Different skill needed" [label="no"];
"Is it C++ system service?" -> "Handles IPC/network data?" [label="yes"];
"Handles IPC/network data?" -> "Use this skill" [label="yes"];
"Handles IPC/network data?" -> "Has shared state?" [label="no"];
"Has shared state?" -> "Use this skill" [label="yes"];
"Has shared state?" -> "Logs data?" [label="no"];
"Logs data?" -> "Use this skill" [label="yes"];
"Logs data?" -> "Different skill needed" [label="no"];
}
在以下场景中使用本技能:
- 审查 OpenHarmony C++ 系统服务代码(xxxService、xxxStub 实现)
- 代码处理 IPC(MessageParcel)或网络数据(JSON/XML/Protobuf)
- 代码以多线程方式访问共享状态
- 代码会记录用户数据或指针
- 代码会校验权限或访问受保护资源
请勿用于:
- 应用层代码(请改用标准安全编码实践)
- 非 OpenHarmony C++ 代码(请改用通用安全审查技能)
- 性能优化(请改用其他技能)
代码遍历策略
输入为头文件(.h/.hpp): 分析对应的 xxxService.cpp 和 xxxStub.cpp 输入为 Stub 文件(xxxStub.cpp): 将分析范围扩展到 xxxService.cpp(核心逻辑和共享状态) 外部调用: 标记跨组件并发风险,供单独审查
快速参考:严重漏洞检查清单
| 类别 | 关键检查项 | 严重性 |
|---|---|---|
| IPC 反序列化 | 检查所有 MessageParcel 读取操作是否成功 | HIGH |
| 逻辑校验 | 反序列化后校验数组长度/索引 | HIGH |
| 整数边界 | 大小变量:0 <= size <= MAX_ALLOWED_BUFFER | HIGH |
| 对象生命周期 | 使用前校验 RemoteObjects/fd(检查 nullptr) | HIGH |
| 解析器安全 | 网络解析器拒绝格式错误的输入,并防止递归攻击 | HIGH |
| 容器线程安全 | 保护所有容器操作(读/写、写/写) | HIGH |
| 迭代器失效** | 遍历时不得修改容器 | HIGH |
| 锁一致性 | 通过互斥锁保护所有共享状态访问 | HIGH |
| 死锁风险 | 按一致顺序获取嵌套锁 | HIGH |
| TOCTOU | 状态检查后立即执行依赖该状态的操作 | HIGH |
| 日志中的个人身份信息 | 日志中不得包含电话号码、联系人、短信、生物识别信息 | HIGH |
| 日志中的输入事件** | 日志中不得包含原始 KeyEvents、触摸坐标、屏幕边界 | HIGH |
| 指针地址 | 日志中不得包含 %p 或 &variable(可能绕过 ASLR) | HIGH |
| 权限检查 | 所有特权操作都必须校验调用方权限 | HIGH |
1. 外部输入处理(IPC 和网络)
1.1 IPC 反序列化完整性
规则: 每个 MessageParcel 读取操作都必须检查返回值。
反例:
// ❌ VULNERABLE: No validation
parcel.ReadInt32(val);
int32_t size = parcel.ReadInt32();
必需模式:
// ✅ SECURE: Always check return value
if (!parcel.ReadInt32(val)) {
HILOG_ERROR("Failed to read value");
return ERR_INVALID_DATA;
}
if (!parcel.ReadInt32(size)) {
HILOG_ERROR("Failed to read size");
return ERR_INVALID_DATA;
}
验证: 确认读取的数据大小与预期类型的大小一致。读取失败时立即停止处理。
1.2 反序列化后的逻辑校验
规则: 反序列化后、使用前,校验值是否处于合理范围内。
攻击向量: 攻击者发送 size = 0xFFFFFFFF,导致内存耗尽,或在 new char[size] 中引发整数溢出。
反例:
// ❌ VULNERABLE: No bounds validation
int32_t size = parcel.ReadInt32();
std::vector<char> buffer(size); // May allocate gigabytes or overflow
必需模式:
// ✅ SECURE: Validate bounds immediately
int32_t size = 0;
if (!parcel.ReadInt32(size)) {
return ERR_INVALID_DATA;
}
constexpr int32_t MAX_ALLOWED_BUFFER = 1024 * 1024; // 1MB
if (size < 0 || size > MAX_ALLOWED_BUFFER) {
HILOG_ERROR("Invalid size: %{public}d", size);
return ERR_INVALID_DATA;
}
std::vector<char> buffer(size);
校验目标: 数组长度、索引、循环计数器、缓冲区大小
1.3 对象生命周期与所有权
规则: 使用 RemoteObjects 和文件描述符前,必须对其进行校验。
必需模式:
// ✅ SECURE: Validate before use
if (remoteObject == nullptr) {
HILOG_ERROR("Received null RemoteObject");
return ERR_NULL_OBJECT;
}
if (fd < 0) {
HILOG_ERROR("Invalid file descriptor");
return ERR_INVALID_FD;
}
1.4 外部网络数据
规则: 网络解析器必须拒绝格式错误的输入,并防止递归攻击。
检查项:
- 配置 JSON 解析器以拒绝格式错误的输入
- 防范“Zip Bomb”攻击
- 限制深层递归
2. 多线程与并发
2.1 容器线程安全(最高优先级)
规则: 所有并发容器操作都必须使用锁保护。
关键风险:
- 读/写: 一个线程读取时,另一个线程写入
- 写/写: 多个线程同时修改
- 迭代器失效: 一个线程修改时,另一个线程进行迭代
反模式:
// ❌ VULNERABLE: Unprotected concurrent access
std::vector<int> items_;
void AddItem(int item) {
items_.push_back(item); // Unsafe if called concurrently
}
void ProcessItems() {
for (auto& item : items_) { // Iteration
// If AddItem called here, iterator invalidates → CRASH
}
}
必需模式:
// ✅ SECURE: All access protected
std::vector<int> items_;
std::mutex itemsMutex_;
void AddItem(int item) {
std::lock_guard<std::mutex> lock(itemsMutex_);
items_.push_back(item);
}
void ProcessItems() {
std::lock_guard<std::mutex> lock(itemsMutex_);
for (auto& item : items_) {
// Safe - lock held during iteration
}
}
需要仔细检查的容器类型: std::vector、std::map、std::list、std::unordered_map、std::string
需要仔细检查的操作: push_back、insert、erase、operator[]、at、迭代
2.2 锁定机制
规则: 所有共享资源都必须始终受到保护。
需要保护的共享资源:
- 全局/静态变量
- 类成员变量
- 在线程间共享的堆分配对象
锁类型: std::mutex、std::shared_mutex、SpinLock
反模式:
// ❌ VULNERABLE: Inconsistent protection
class Service {
std::map<int, Data> dataMap_;
std::mutex mutex_;
void Update(int key, const Data& data) {
std::lock_guard<std::mutex> lock(mutex_);
dataMap_[key] = data;
}
Data Lookup(int key) {
// ❌ NO LOCK - race condition with Update
return dataMap_[key];
}
};
必需模式:
// ✅ SECURE: Consistent protection
class Service {
std::map<int, Data> dataMap_;
std::mutex mutex_;
void Update(int key, const Data& data) {
std::lock_guard<std::mutex> lock(mutex_);
dataMap_[key] = data;
}
Data Lookup(int key) {
std::lock_guard<std::mutex> lock(mutex_);
return dataMap_[key];
}
};
2.3 死锁预防
规则: 评估嵌套锁场景中的死锁风险。
死锁条件:
- 不同代码路径以不同顺序获取多个锁
- 持有锁时调用可能获取锁的外部函数
反模式:
// ❌ VULNERABLE: Deadlock risk
void Path1() {
std::lock_guard<std::mutex> lock1(mutex1_);
std::lock_guard<std::mutex> lock2(mutex2_); // Order: 1 then 2
}
void Path2() {
std::lock_guard<std::mutex> lock2(mutex2_);
std::lock_guard<std::mutex> lock1(mutex1_); // Order: 2 then 1 → DEADLOCK
}
必需模式:
// ✅ SECURE: Consistent lock order
void Path1() {
std::lock_guard<std::mutex> lock1(mutex1_);
std::lock_guard<std::mutex> lock2(mutex2_); // Order: 1 then 2
}
void Path2() {
std::lock_guard<std::mutex> lock1(mutex1_); // Same order: 1 then 2
std::lock_guard<std::mutex> lock2(mutex2_);
}
2.4 TOCTOU(检查时与使用时)
规则: 状态检查后必须立即执行依赖该状态的操作,中间不能有间隔。
反模式:
// ❌ VULNERABLE: TOCTOU window
if (fileExists(path)) {
// Attacker can delete/replace file here
file = openFile(path); // May open different file
}
必需模式:
// ✅ SECURE: Atomic check-and-use
file = openFile(path);
if (file.isValid()) {
// Use file
}
3. 敏感信息保护
3.1 严格清除个人身份信息
规则: 日志必须清除所有个人身份信息(PII)。
需要清除的 PII:
- 用户隐私: 电话号码、联系人、SMS 内容、生物识别数据
- 输入事件: 原始 KeyEvents、触摸坐标(x、y)、屏幕位置边界(Rect)
反模式:
// ❌ VULNERABLE: Logs PII
HILOG_INFO("Phone: %{public}s", phoneNumber.c_str());
HILOG_ERROR("Touch at (%{public}d, %{public}d)", x, y);
必需模式:
// ✅ SECURE: Redact or suppress
HILOG_INFO("Phone: %{private}s", phoneNumber.c_str()); // Redacted
// Better: Don't log PII at all
HILOG_INFO("Processing phone number");
策略: 在发布版本中优先完全禁用相关日志。仅在调试确有必要时使用 %{private} 格式说明符。
3.2 内存布局泄露(绕过 ASLR)
规则: 绝不记录原始指针地址。
反模式:
// ❌ VULNERABLE: Leaks addresses for ASLR bypass
HILOG_INFO("Object at %p", &object);
HILOG_DEBUG("Buffer address: %{public}p", buffer);
必需模式:
// ✅ SECURE: No address logging
HILOG_INFO("Object created");
// Use opaque IDs instead of pointers
HILOG_INFO("Object ID: %{public}d", object.id_);
原因: 泄露堆/栈地址会帮助攻击者绕过 ASLR(地址空间布局随机化)。
4. 权限验证
规则: 所有特权操作都必须验证调用方权限。
反模式:
// ❌ VULNERABLE: No permission check
int32_t Service::DeleteFile(const std::string& path) {
// Any caller can delete any file!
return unlink(path.c_str());
}
必需模式:
// ✅ SECURE: Validate permissions
int32_t Service::DeleteFile(const std::string& path) {
// Verify caller has permission to access this path
if (!HasPermission(callerToken_, path, Permission::DELETE)) {
HILOG_ERROR("Permission denied for path: %{private}s", path.c_str());
return ERR_PERMISSION_DENIED;
}
// Verify path is within allowed sandbox
if (!IsPathInSandbox(path)) {
HILOG_ERROR("Path outside sandbox: %{private}s", path.c_str());
return ERR_INVALID_PATH;
}
return unlink(path.c_str());
}
以下操作必须检查权限:
- 文件系统操作(读取、写入、删除)
- 系统设置修改
- 硬件访问(摄像头、麦克风、位置)
- 进程间通信
- 网络操作
常见错误
| 错误 | 后果 | 修复方法 |
|---|---|---|
| 忘记检查 MessageParcel 返回值 | 使用未初始化数据、崩溃 | 始终检查返回值 |
| 验证大小但未检查下限(负数) | 负数大小通过验证 | 检查 0 <= size <= MAX |
| 保护共享容器的写入操作,却不保护读取操作 | 读取时发生竞态条件 | 保护所有访问 |
| 容器修改后继续使用迭代器 | 迭代器失效、崩溃 | 迭代期间持有锁 |
使用 %{public} 记录 PII | 信息泄露 | 使用 %{private} 或不记录 |
| 为调试打印指针地址 | 绕过 ASLR | 使用不透明 ID |
| 以“这是内部调用”为由跳过权限检查 | 被外部调用时可能导致权限提升 | 始终进行验证 |
审查输出格式
按以下格式标记违规:
**[HIGH SECURITY RISK] <Category>**
Location: <file_path>:<line_number>
Issue: <description>
Anti-pattern:
```cpp
<code>
必需的修复:
<code>
影响:<利用后攻击者可实施的操作>
## Real-World Impact
**Container race conditions:** Use-after-free crashes, privilege escalation through corrupted state
**IPC validation failures:** Remote code execution via deserialization exploits, memory exhaustion DoS
**PII leakage:** Privacy violations, GDPR compliance failures
**ASLR bypass:** Enables exploitation of memory corruption vulnerabilities
**Missing permission checks:** Unauthorized access to sensitive data, system modification