
摘要
这几年随着鸿蒙分布式能力越来越成熟,设备之间直接通信已经变成了很常见的开发场景,比如手机和手表互联、手机控制平板、智能家居联动等。但设备一多、通信一复杂,安全问题就绕不开了,其中最典型、也最容易被忽视的就是中间人攻击(MITM)。
简单来说,就是你的设备以为自己在和"可信设备"通信,实际上中间被人截胡了,数据被偷看、被篡改,甚至被伪造指令。本文会结合鸿蒙的真实开发场景,用偏口语、偏实战的方式,讲清楚鸿蒙设备间是怎么一步步防中间人攻击的,并配上可以直接理解和复用的 Demo 代码模块。
引言
在传统单设备应用时代,开发者更多关心的是本地数据安全。但在鸿蒙生态下,应用天生就是"多设备协同"的:
- 手机给手表下发数据
- 平板远程控制大屏
- 智能设备通过局域网或软总线通信
这些场景一旦走上网络,就一定会面对攻击面扩大的问题。尤其是设备发现、身份认证、数据同步这几个阶段,都是中间人攻击最爱下手的地方。
所以这篇文章不讲抽象理论,重点放在三个问题上:
- 鸿蒙里中间人攻击一般是怎么发生的
- 官方能力能帮我们挡住哪些风险
- 作为开发者,代码层面还能再补哪些安全措施
鸿蒙设备间中间人攻击到底发生在哪
在实际项目中,中间人攻击通常集中在下面几个阶段:
- 设备发现阶段:攻击者伪装成"可用设备"
- 建立连接阶段:通信过程被监听或劫持
- 数据传输阶段:数据被篡改或重放
如果你只是简单用分布式接口把数据一发,很容易在不知不觉中留下隐患。
第一道防线:设备身份可信校验
为什么设备信任关系这么重要
在鸿蒙里,分布式通信并不是谁都能连。系统层面已经帮我们做了一件很关键的事:只有建立过信任关系的设备,才能算"可信设备"。
作为开发者,千万不要跳过这一步。
使用 DeviceManager 获取可信设备列表
下面这个 Demo 可以直接在 Stage 模型中使用,用来获取当前应用下的可信设备。
ts
import deviceManager from '@ohos.distributedDeviceManager';
const dm = deviceManager.createDeviceManager('com.example.securedemo');
function getTrustedDevices() {
try {
const list = dm.getTrustedDeviceListSync();
list.forEach(device => {
console.info('可信设备ID: ' + device.deviceId);
});
return list;
} catch (err) {
console.error('获取可信设备失败', JSON.stringify(err));
return [];
}
}
这段代码的实际意义是:
- 系统已经帮你过滤掉了不可信设备
- 攻击者就算在同一个局域网里,也拿不到合法 deviceId
第二道防线:通信全程加密
明文通信基本等于"裸奔"
很多安全事故,其实不是被高级攻击打穿的,而是开发阶段为了图方便:
- 用了 HTTP
- 用了明文 Socket
- 局域网里觉得"没事"
在鸿蒙中,只要涉及网络通信,就默认走 TLS。
使用 HTTPS 进行安全请求示例
ts
import http from '@ohos.net.http';
const httpRequest = http.createHttp();
httpRequest.request(
'https://example.com/device/sync',
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: JSON.stringify({ data: 'sync-info' })
},
(err, data) => {
if (!err) {
console.info('加密通信成功: ' + JSON.stringify(data.result));
} else {
console.error('请求失败', JSON.stringify(err));
}
}
);
这里并没有什么花活,但它解决了两个最基础的问题:
- 数据不会被随便监听
- 数据被改了,TLS 会直接报错
核心防御点:证书校验与证书绑定
为什么只用 HTTPS 还不够
现实情况是:
- 有些攻击者能安装伪造 CA
- 在测试设备、Root 环境下更常见
这时候就要靠**证书绑定(Pinning)**来兜底。
简化版证书指纹校验示例
下面是一个逻辑 Demo,用来说明校验思路:
ts
const LOCAL_FINGERPRINT = '12:34:56:AA:BB:CC';
function checkServerCert(fingerprint: string) {
if (fingerprint !== LOCAL_FINGERPRINT) {
throw new Error('证书不匹配,终止通信');
}
}
在真实项目中,一般做法是:
- 预置服务器或设备证书指纹
- 建立连接后先校验
- 不通过就直接断开
数据完整性:签名和校验不能省
为什么要做签名
即使通信是加密的,也不能假设数据一定没被动过。特别是在:
- 分布式任务下发
- 远程控制设备
这些场景中,一条被篡改的指令,后果可能很严重。
使用签名校验的基本流程
ts
function signData(data: string, privateKey: string): string {
// 示例逻辑
return 'signed_' + data;
}
function verifyData(data: string, signature: string, publicKey: string): boolean {
return signature === 'signed_' + data;
}
真实项目中一般会结合 HUKS,把密钥托管给系统,避免私钥暴露。
结合真实场景的应用示例
场景一:手机控制平板播放内容
风险点:
- 假设备伪造控制指令
防护方式:
- 校验 deviceId 是否在可信列表
- 指令加签名
ts
if (!isTrustedDevice(targetDeviceId)) {
return;
}
const cmd = 'PLAY_VIDEO';
const sign = signData(cmd, privateKey);
场景二:智能家居设备状态同步
风险点:
- 状态被篡改
- 重放旧数据
防护方式:
- 数据加时间戳
- 校验签名
ts
const payload = {
status: 'ON',
timestamp: Date.now()
};
场景三:分布式数据同步
风险点:
- 非法设备注入脏数据
防护方式:
- 权限控制
- 来源设备校验
ts
if (!trustedDevices.includes(callerDeviceId)) {
throw new Error('非法来源');
}
常见问题 QA
Q1:局域网环境下还需要这么多安全措施吗?
需要。局域网并不等于安全,很多攻击正是发生在"以为很安全"的环境里。
Q2:证书绑定会不会影响调试?
会有一点成本,但可以区分 Debug 和 Release 配置,不建议线上关闭。
Q3:这些防护会不会影响性能?
相比安全风险,这点性能损耗是完全可以接受的。
总结
在鸿蒙分布式开发中,防中间人攻击并不是靠某一个 API,而是一整套组合拳:
- 设备层面先做信任校验
- 通信层面全程加密
- 关键数据加签名、做校验
- 权限和来源控制兜底
只要在设计阶段把这些点考虑进去,大多数中间人攻击其实根本进不了你的系统。