HarmonyOS 6.1 智能窥屏防护实战:实时感知窥屏风险,敏感页自动防护

本文基于 Device Security Kit 防窥保护(dlpAntiPeep)的官方资料与华为开发者联盟最佳实践整理。文中代码是为说明问题自写的示例,不是官方示例的搬运;API 名称、权限与版本号等事实性信息均标注出处;涉及真机表现的部分已明确标注,未做任何实测数据编造。


引子:地铁上那一眼,挡不住也看不见

V哥认识一个做银行应用的朋友,安全评审年年过,密码键盘、防截屏、登录二次认证一样不少。有次V哥坐地铁,正好看见旁边一位乘客打开这类应用查账单,手机斜对着车门方向,车厢里人挤人------那一眼里能看到什么,只有天知道。

事后V哥问他:你们应用管得了这个吗?他苦笑:管不了。密码键盘防的是"机器偷",防不了"人看"。用户登进来了,手机摆在那儿,旁边谁瞟了一眼、瞟走了多少信息,应用层既感知不到,也没法响应。

这事在 HarmonyOS 6.1 上有解了:Device Security Kit 提供防窥保护能力(dlpAntiPeep),系统借助前置摄像头和人脸识别判断"屏幕前是不是只有机主一个人",检测到非机主在窥视时通知应用,应用可以选择拉起系统级蒙层把整个窗口盖住(参见开发者联盟防窥保护最佳实践)。这期V哥把这条链路拆开讲:定位、接口、代码、坑,最后给一份接入自检清单。


一、先定位准:它防的是"登录之后"的问题

很多人第一反应拿它当登录安全做,这就用错了。官方的定位很清楚------防窥保护解决的不是"谁能进入 App"(那是身份验证的事),而是**"进入之后,旁边有没有人在看"**(华为开发者联盟实战分享)。

两个能力是互补关系,不是替代关系:

能力 防什么 失效场景
身份验证(密码/人脸登录) 谁能打开应用 登录之后,手机被旁人看到
防窥保护(dlpAntiPeep) 打开之后,谁在窥视屏幕 ------正是上面那个空档

系统怎么判断"有人在看"?官方的机制是:把长期通过人脸解锁的机主人脸作为基准,通过前置摄像头实时检测注视状态------只有机主一个人看屏幕,状态是 PASS;检测到机主和非机主同时注视屏幕,状态变为 HIDE。应用订阅这个状态变化,收到 HIDE 就做自己的保护动作。

V哥把整条"感知---状态---响应"链路画成一张图,系统管上面两层,应用只管最下面一层:

这里有个V哥认为很聪明的设计:系统只负责感知,不替应用决定怎么防。HIDE 到了,你可以模糊余额数字、暂停视频、遮盖聊天内容,也可以直接拉系统级蒙层------感知和响应分层,各应用按自己的业务形态接。


二、接入解剖:一个模块、两道前提、六个接口

先看物理形态。所有能力都收在 @kit.DeviceSecurityKitdlpAntiPeep 模块里,接口不多,每个职责都清楚:

接口 职责 版本口径
isDlpAntiPeepSwitchOn() 查系统级防窥开关是否已开 API 20 起
requestAntiPeepOptions(context) 拉起系统弹窗,引导用户为当前应用开启防窥保护 API 23 起
on('dlpAntiPeep', callback) 订阅窥视状态变化(PASS/HIDE) API 20 起
getDlpAntiPeepInfo() 同步获取当前状态快照 API 20 起
setAntiPeepMaskLayer(windowId) 在指定窗口拉起系统级蒙层 API 20 起
off('dlpAntiPeep') 释放订阅 API 20 起

版本口径来自官方最佳实践页的标注(参考),能力随 HarmonyOS 6.0 Beta 起逐步开放,建议在 6.1 及以上机型上使用,以实际支持机型为准。另外当前仅支持 Phone 设备,模拟器上会直接报不支持------别在模拟器上白折腾。

两道前提比接口本身容易漏:

第一道:设备侧条件。 用户必须已录入人脸数据(系统拿它做机主基准)、设备支持人脸识别,且用户在「设置 > 隐私与安全 > 防窥保护」里打开了系统开关。前置校验可以用 userAuth.getAvailableStatus 判断:错误码 12500005 表示设备不支持人脸识别,12500010 表示人脸没录入------这两个码建议做成用户引导,而不是直接报错。

第二道:受限权限。 应用要声明 ohos.permission.DLP_GET_HIDE_STATUS,这是受限权限,不是声明了就能用------上架前要走 AGC 的 ACL 申请流程,并在隐私政策里说明用途。V哥把这条放坑里单独讲。


三、动手:给余额页加一层"有人看就蒙上"

V哥的示例是账单详情页,策略选了最省心的一种:感知交给系统,响应就是拉蒙层。完整思路是"进页面查快照 + 订阅增量,收 HIDE 拉蒙层,出页面释放":

typescript 复制代码
// BalancePage.ets ------ 敏感页防窥接入:订阅状态 + 拉系统蒙层
// 前提:module.json5 已声明 ohos.permission.DLP_GET_HIDE_STATUS(受限权限)
import { dlpAntiPeep } from '@kit.DeviceSecurityKit';
import { window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct BalancePage {
  @State masked: boolean = false;
  private watching: boolean = false;

  aboutToAppear(): void {
    // V哥的习惯:先查快照拿"现在",再订阅拿"变化"------回调只报增量,不报存量
    this.applyStatus(dlpAntiPeep.getDlpAntiPeepInfo());
    dlpAntiPeep.on('dlpAntiPeep', (status: dlpAntiPeep.DlpAntiPeepStatus) => {
      this.applyStatus(status);
    });
    this.watching = true;
  }

  aboutToDisappear(): void {
    // 离开敏感页必须释放订阅;蒙层由系统在状态恢复后自动撤
    dlpAntiPeep.off('dlpAntiPeep');
    this.watching = false;
  }

  private applyStatus(status: dlpAntiPeep.DlpAntiPeepStatus): void {
    this.masked = (status === dlpAntiPeep.DlpAntiPeepStatus.HIDE);
    if (this.masked) {
      this.maskThisWindow();   // 被窥视:拉系统级蒙层
    }
  }

  private async maskThisWindow(): Promise<void> {
    try {
      // 参数是窗口 id,从窗口模块取当前页所属窗口(取值细节以官方 SDK 为准)
      const win = await window.getLastWindow(getContext(this) as common.UIAbilityContext);
      await dlpAntiPeep.setAntiPeepMaskLayer(win.getWindowProperties().id);
    } catch (e) {
      // 1020600001~4 是窗口未就绪类错误:页面刚切入时可能触发,做有限重试
      console.error(`setAntiPeepMaskLayer failed: ${(e as Error).message}`);
    }
  }
}

三个写法上的讲究:

① 快照和订阅要成对出现。 on 回调只在状态变化时触发,用户进页面时恰好已经处于 HIDE(比如窥视者早就在旁边),没有快照兜底就漏了第一次。getDlpAntiPeepInfo() 就是这个兜底。

② 释放点写死在 aboutToDisappear 订阅泄漏的后果不是内存问题,是语义问题:用户已经退出余额页,蒙层逻辑还在响应 HIDE,把别的页面也蒙了。防窥是页面级能力,生命周期就得按页面级管。

③ 窗口未就绪的错误要重试。 官方错误码 1020600001~4 都指向窗口状态异常,典型时机是页面刚切入、窗口还没就绪。V哥建议做最多三次的退避重试,别一次失败就放弃。


四、三个坑,V哥替你踩过了

坑一:受限权限当成普通权限声明完事。 DLP_GET_HIDE_STATUS 属于 ACL 受限权限,本地调试用自动签名能跑通,一到上架审核就过不去。正确顺序是:module.json5 声明(带用途文案)→ AGC 提交 ACL 申请 → 隐私政策对齐。别把申请留到提审前夜。

坑二:系统开关没开,应用干瞪眼。 防窥开关默认可能没开,应用侧 isDlpAntiPeepSwitchOn() 查到 false 时,别只弹一句"请去设置里打开"------用 requestAntiPeepOptions(context) 直接拉起系统弹窗,用户在弹窗里就能为当前应用打开开关(API 23 起)。一步引导和一步跳设置,转化率差着一个量级。

坑三:把它当百分百可靠的安防系统。 人脸感知有物理边界:人脸要在有效距离内、无遮挡、光线充足(官方约束)。所以别把资金操作安全压在蒙层上------防窥是"降低肩窥暴露面"的体验增强,指纹密码那一层照旧要上。


五、接入前自检清单

# 检查项 挂了会怎样
1 设备支持人脸识别且用户已录入?(12500005/12500010 有引导) 功能静默不可用
2 DLP_GET_HIDE_STATUS 已声明且 ACL 已申请? 本机能跑、上架被驳
3 快照 + 订阅成对出现? 进页面时的存量 HIDE 漏判
4 订阅在 aboutToDisappear 释放? 蒙层响应串页
5 窗口未就绪错误码有重试? 页面刚切入时蒙层偶发失败
6 开关未开时用 requestAntiPeepOptions 引导? 用户找不到入口,功能白接
7 模拟器不报错才上传? 801 设备不支持,模拟器测不出

六、V哥的收尾判断:防护边界出了屏幕

回看这套能力,V哥认为它的意义不只是多一个 Kit:HarmonyOS 的安全边界第一次从系统内部延伸到了物理环境。沙箱管数据、权限管访问、身份验证管入口,防窥管的是"屏幕和围观者之间"那段真空地带------这是以往任何应用层方案都够不着的。

代价是它把一部分信任交给了感知系统:误判会蒙住不该蒙的界面,漏判会放过窥视。所以官方才把"感知 + 响应"分层------应用可以按页面敏感度选响应强度,登录页模糊数字、相册暂停轮播、账单页直接蒙层。别一刀切,敏感度分级的活儿得应用自己做。

第一期的智感握姿那篇V哥写过:系统能感知的,应用别自己造轮子。这篇补上隐私方向的同款结论------环境感知交给系统,响应策略留给自己。


参考与出处

本文涉及的机制、接口与约束来自以下官方及开发者联盟文档:


最后一句:密码防的是"谁知道",防窥防的是"谁看见"------感知交给系统的前置摄像头,响应留给你的业务分级,地铁上那一眼,从此一无所获。

相关推荐
威哥爱编程1 小时前
HarmonyOS 7 文搜图实战:自然语言检索本地图片,全流程端侧闭环
华为·harmonyos·arkts
贾伟康1 小时前
【HarmonyOS 7新能力|041】弱网直播优化工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·音视频开发·直播
lqj_本人14 小时前
Flutter_Rust_Bridge:让 Flutter 稳定调用 Rust 的跨语言桥梁
harmonyos
贾伟康14 小时前
【HarmonyOS 7新能力|040】QUIC长连接工程封装:把接入逻辑放进可维护的分层结构
网络编程·harmonyos·arkts·quic·软件架构
hqzing14 小时前
Harmonybrew 仓库中的 gcc(GCC 16)和 llvm(LLVM 23)已经可用
harmonyos
昇腾知识体系15 小时前
昇腾 torchrec_npu Docker 镜像选择:CANN/PyTorch/torchrec 版本矩阵与启动参数
人工智能·华为·知识图谱
昇腾知识体系15 小时前
K8s 调度昇腾 NPU:device-plugin 部署、Volcano 与 vNPU 切分
人工智能·华为·知识图谱
菜鸟~noob23318 小时前
【Bonjour】华为Peerium架构深度解析:从冯·诺依曼到百万处理器“一台计算机”,附MATLAB性能仿真【含matlab代码,可直接运行】
开发语言·matlab·华为·peerium
万物智能信息科技20 小时前
PWM散热风扇设置—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
人工智能·华为·开源·harmonyos·鸿蒙