鸿蒙和Android需配READ_PASTEBOARD权限,H5端无权限控制但须HTTPS+手势触发;轮询监听扩大风险,应避免敏感信息入剪贴板,采用动态绘制、水印、长度过滤等策略降低泄露风险。

鸿蒙和 Android 上必须配 READ_PASTEBOARD 权限
鸿蒙系统从 HBuilderX 4.23 起支持 uni.getClipboardData,但读取剪贴板前必须显式声明 ohos.permission.READ_PASTEBOARD。不配的话,调用直接静默失败,连 error 都不抛——你根本不知道它没权限。
配置位置在 harmony-configs/entry/src/main/module.json5,不是 manifest.json,也不是 app.json:
{"module":{"requestPermissions":[{"name":"ohos.permission.READ_PASTEBOARD","reason":"$string:clipboard_reason","usedScene":{"when":"inuse"}}]}}
Android 端虽不要求显式申请该权限(系统默认开放),但 Android 12+ 会在首次调用 uni.getClipboardData 时弹出“此应用想要读取剪贴板”提示,用户点拒绝后,后续调用就返回空字符串。别指望后台偷偷读——系统真会拦。
App 端轮询监听剪贴板 = 主动暴露风险窗口
很多开发者用 800ms–1500ms 定时器轮询 uni.getClipboardData 实现“监听”,这本身就在扩大攻击面:只要你的页面处于前台,剪贴板内容就持续被你自己的逻辑读取、比对、解析——哪怕只匹配链接或手机号,也意味着你在内存里反复搬运敏感数据。
- 轮询期间,如果用户刚复制了银行卡号或验证码,这段内容会在 JS 堆里明文存在至少一个周期
-
onHide里没清除定时器?切到后台还在读——iOS 可能直接杀进程,但 Android 某些定制 ROM 仍可能执行几轮 - 正则白名单别写太宽,
/\d{16,19}/这种会把所有长数字都当卡号抓出来,包括身份证、订单号、甚至 base64 片段
H5 端复制不触发权限弹窗,但读取完全不可控
H5 页面调用 navigator.clipboard.readText() 必须满足两个硬条件:HTTPS + 用户手势触发。但它不等于“安全”——一旦用户点了复制按钮,你就能读;而用户根本不知道你读了什么。
更麻烦的是:navigator.clipboard 在 H5 里是可读可写的,且无系统级访问记录。微信内嵌浏览器、部分安卓 WebView 还不支持该 API,你得 fallback 到 document.execCommand,而这个老接口连基本的权限提示都没有。
结论很现实:H5 端无法防止自身读取剪贴板,只能靠代码自律——比如读完立刻 res.data = '' 清空变量,不缓存、不上传、不打日志。
真正防泄露,得从“不放进去”和“放了也白读”入手
与其纠结怎么阻止 App 读剪贴板,不如让敏感信息根本不在剪贴板上出现,或者出现也无效:
- 登录态 token、支付密钥这类绝不走复制粘贴流程,改用扫码、一键登录、设备绑定等通道
- 用户需要复制的敏感字段(如订单号、手机号)用 canvas 动态绘制,而非 DOM 文本节点——截图可存,但复制出来的只是乱码或空格
- 关键页面叠加动态水印:
userId + timestamp + 设备指纹,水印随滚动偏移,截图后文字错位,复制内容失去上下文意义 - 剪贴板内容比对逻辑里加长度阈值,
if (newText.length > 200) return;——大段文本大概率是文章或代码,不是敏感凭证
剪贴板不是保险箱,它是系统级共享缓冲区。任何“防读取”的方案,本质都是拖延或混淆;最省心的做法,是让它没东西可读。


















