返回知识中心
平台

WebHID 设备权限与隐私边界

通过用户操作请求 WebHID,校验集合与报告,处理断开连接,并限制设备元数据的留存。

BotBrowser Team

文档中心

想直接进入 平台 文档吗?

这篇文章属于知识中心的指南库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

WebHID 允许页面请求用户选择的人机接口设备,但获得权限不等于设备清单,也不能证明设备归谁所有。BotBrowser 可以在受控 context 中执行页面自有的权限分支和备用路径,但不会制造实体控制器、绕过浏览器授予权限,也不能证明硬件 I/O。安全契约应保持明确:由用户操作发起,只检查所需集合,限制每条报告,协调断开状态,并让任务在没有 HID 时仍可用。

用户操作、WebHID 权限边界、集合检查、有限报告、断开清理和非 HID 备用路径

TL;DR

  • navigator.hid.requestDevice({ filters: [{ usagePage: 0x01 }] }) 需要安全上下文和短暂的用户激活。
  • 选择器授权会暴露一个 HIDDevice,但不能证明设备已连接、安全、属于某人,或适用于全部集合。
  • 打开前检查 device.collections,并把 inputreport 字节当作不可信数据。
  • disconnect 会结束当前关系;关闭 listeners、保留用户工作,并要求用户明确重试。
  • 保存 granted、unsupported 或 disconnected 等结果,不保存序列号、报告历史或推断身份。

目录

在使用时请求

WebHID 仅限安全上下文,requestDevice() 应在短暂用户激活期间执行。把请求放在名称清晰的控件后面。能力检测只说明方法存在,不会打开选择器或授予访问权;浏览器策略、iframe、操作系统或平台仍可能拒绝请求。

async function connectHid() {
  if (!window.isSecureContext || !navigator.hid) return showHidState('unsupported');
  setHidState('requesting');
  try {
    const devices = await navigator.hid.requestDevice({
      filters: [{ usagePage: 0x01, usage: 0x06 }],
    });
    if (devices.length === 0) return showHidState('no-device');
    await openSelectedHid(devices[0]);
  } catch (error) {
    showHidState(error.name === 'NotAllowedError' ? 'denied' : 'failed');
  }
}

connectButton.addEventListener('click', connectHid);

不要在页面加载时打开选择器,也不要在取消后循环请求。保留草稿,只有新的用户操作才提供下一次请求。WebUSB 设备访问:权限、接口与隐私区分授权、打开、声明接口和清理。Web Bluetooth 权限、设备选择与隐私把同一用户意图边界用于另一种设备模型。

在处理报告前检查集合

选择后,HIDDevice 会暴露元数据和 collections。只打开受支持的设备,并将 usagePage、usage 与报告描述符和目标操作比较。产品名不等于全部报告的授权,也不能证明身份、地点或物理距离。

维护允许的 usage 和报告大小清单。集合不匹配时应停止,而不是扩大访问范围。不要把 productName、vendorId、productId 或 serialNumber 复制到 URL、账户、分析字段或常规支持日志;它们即使不暴露所有者,也可能区分具体设备。

集合映射是动态能力视图。设备可能成功打开后在下一步失败,固件更新后改变报告布局,或在第一条报告前消失。说明准确的支持操作,没有合适集合时保留普通页面路径。

限制报告并协调断开

inputreport 会交付所选设备的字节。改变状态前校验 reportId、长度、取值范围和新鲜度。设置最大载荷,拒绝意外 ID,并在渲染或发送前限制高频输入。

const MAX_REPORT_BYTES = 64;

function acceptInputReport(event) {
  const bytes = new Uint8Array(event.data.buffer);
  if (bytes.length === 0 || bytes.length > MAX_REPORT_BYTES) return;
  if (event.reportId !== 1 || bytes[0] > 100) return;
  updateControllerState({ reportId: event.reportId, value: bytes[0] });
}

device.addEventListener('inputreport', acceptInputReport);

注册 navigator.hid.addEventListener('disconnect', ...),让清理可重复执行。在等待 close() 前先将任务标记为断开,移除报告 listeners,保留已输入数据,并显示明确的重新连接控件。延迟报告不能把断开页面重新标记为就绪。不要自动重连或再次发送上一条命令。

最小化元数据并保留备用路径

把浏览器权限、HID 会话和上传同意分成不同决定。本地读取不代表允许上传服务器;应单独询问,说明离开浏览器的字段,并在用户拒绝上传时让本地任务完成。

运行记录通常只需要 unsupported、denied、no-device、connected、invalid-report 或 disconnected、时间和测试环境。原始报告、稳定标识符、完整集合图和长期连接历史通常没有必要。诊断记录应短期、可见、受控并自动删除。

保留键盘表单、手动值、文件导入或静态配置作为无障碍备用路径。不要让登录、计费、账户恢复或必需内容依赖实体 HID 设备。

用决策表分类结果

观察阶段能证明什么安全下一步
API 缺失、不安全上下文或策略阻止当前无法启动 WebHID保留非 HID 任务并解释环境限制
选择器取消或权限拒绝本次没有可用授权保留草稿,等待新的明确操作
设备已选但集合不支持缺少所需能力关闭会话、显示要求,不扩大过滤器
长度、ID 或范围无效输入未通过应用协议丢弃,记录 invalid-report,继续任务
disconnect 事件当前关系结束移除 listeners、尽力关闭、保留数据并让用户重试
有效且受限的报告页面接受了一个应用值只报告该值,不推断所有者、地点或身份

每一行都应回到可理解的页面状态。权限不是连接,集合不是可信控制器,有效报告也不是实体操作证明。

BotBrowser 的能力与限制

BotBrowser 的受控 context 可以验证连接按钮、能力检测、集合过滤、有限报告、断开清理和无 HID 备用路径。高级能力文档记录了可在该 context 中检查的浏览器能力。结果仍是页面级证据:BotBrowser 不提供 HID 设备、不授予操作系统权限、不保证报告,也不能证明某人拥有或触摸控制器。

{
  "api": "navigator.hid",
  "permission": "denied",
  "collectionsAccepted": 0,
  "reportsAccepted": 0,
  "rawIdentifiersRetained": false,
  "physicalDevice": "not-asserted"
}

改变一个变量后重跑 fixture,例如浏览器版本、安全上下文策略、权限结果、集合过滤器或模拟断开。比较第一个可见状态差异,不要据此承诺通用硬件支持。

可观察状态

测试保留页面可见的状态序列,不把页面结果变成实体硬件主张。

硬件边界

实体验收需要批准的设备,并且应在独立于页面 fixture 的环境中完成。

来源

实践结论

使用明确的选择器操作,只检查支持的集合,校验每条报告,并在断开后关闭 listeners。让核心任务在没有 HID 时仍完整可用,记录失败阶段而不是设备标识符。浏览器、策略、固件或权限变化后重跑 fixture;页面成功不代表实体硬件行为。

#WebHID#权限#设备隐私#浏览器 API#BotBrowser

本文属于指南: Web 平台能力面:一致性复核地图

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。