USB 设备管控实战:usbguard 白名单配置

USB 设备管控之所以难做,是因为 USB 协议在设计上默认信任对端:插上就枚举,枚举完就驱动,全程没有身份认证环节。攻击者把一块单片机做成键盘,插上后自动敲出 Win+R → PowerShell 下载执行 的序列,几十秒即可完成植入,这就是 BadUSB 的常见形态。本文给出的 USB 设备管控方案分两层:Linux 侧用 usbguard 在内核设备授权阶段做白名单,Windows 侧用设备安装限制策略阻断驱动加载,两侧都以「默认拒绝 + 显式放行」为原则。

适用场景

  • 办公终端区、生产机房跳板机、财务与人事专用机,需要禁止私人 U 盘接入。
  • 发生过「外来 U 盘带入勒索病毒」或「可疑键盘设备自动执行命令」的事件。
  • 等保或行业监管要求「对移动存储介质实行准入管理并留存审计记录」。
  • 需要区分「只允许公司配发的加密盘」与「任意存储设备」两种策略粒度。

前置条件

  • Linux 终端:内核 5.4 及以上,usbguard 0.7.8+(Debian/Ubuntu 包名 usbguard,RHEL 系在 EPEL)。
  • Windows 终端:Windows 10/11 专业版或企业版(家庭版无组策略编辑器,只能改注册表)。
  • 一台「干净基线机」,只插入允许使用的设备,用于一次性生成白名单。
  • 终端管理通道可用(SSH、RMM 或组策略下发),避免逐台手工操作。
  • 已准备应急放行方式:本地控制台或带外管理,防止白名单误配后键盘鼠标全部失效。

原理说明

USB 设备的身份由三层信息组成:VID/PID(厂商与产品 ID,可被随意伪造)、序列号(部分设备不提供,或全批次相同)、接口类(HID 键盘为 03:01:01,大容量存储为 08:06:50)。只看 VID/PID 的白名单挡不住「同型号设备被替换固件」,因此生产环境应尽量叠加序列号与接口类约束。

usbguard 工作在 Linux 的 uevent 层:设备插入后、驱动绑定前,内核把设备授权状态置为未授权,usbguard 依据规则给出 allow(授权并允许驱动绑定)、block(不授权,设备存在但不可用)、reject(直接逻辑断开,设备从总线消失)三种结果。ImplicitPolicyTarget 决定规则未命中时的默认动作,设为 block 即为白名单模式。相比 udev 的 RUN+= 脚本,usbguard 的判定发生在设备可用之前,不存在「先挂载再卸载」的时间窗。

Windows 侧没有等价的内核钩子,但设备安装限制策略可以在驱动安装阶段拦截:策略命中后系统不会加载驱动,设备管理器显示黄色感叹号,事件日志留痕。两层策略的差异在于 Windows 侧对「已安装过的设备」需要额外清理,所以首次部署必须在设备未插入的状态下完成。

操作步骤

第一步:采集允许设备的指纹

在基线机上逐个插入合规设备,记录完整属性。--attribute-walk 会输出整条设备树,重点看 idVendor、idProduct、serial、bInterfaceClass。

# 列出当前所有 USB 设备
lsusb

# 查看某设备的完整属性(插拔前后对比可定位新增节点)
udevadm info --attribute-walk --name=/dev/bus/usb/001/004 | \
  grep -E "idVendor|idProduct|serial|bInterfaceClass|bInterfaceSubClass|bInterfaceProtocol"

# 实时观察插拔事件,确认设备节点与事件顺序
udevadm monitor --udev --property --subsystem-match=usb

如果 serial 为空,说明该型号不提供序列号,此时白名单只能退化到 VID/PID + 端口绑定,需在规则里用 via-port 锁定物理口,避免同型号设备在任意口都被放行。

第二步:生成初始白名单

generate-policy 以「当前已插入的设备」为样本生成规则,所以基线机上只能插合规设备。

sudo apt install -y usbguard
sudo systemctl stop usbguard

# 以当前插入设备生成规则
sudo usbguard generate-policy > /tmp/rules.conf
sudo cp /tmp/rules.conf /etc/usbguard/rules.conf
sudo chmod 0600 /etc/usbguard/rules.conf
sudo wc -l /etc/usbguard/rules.conf

生成的规则形如 allow id 046d:c52b serial "1234ABCD" name "USB Receiver" via-port "1-3" with-interface { 03:01:01 03:00:00 }。规则是顺序匹配、首次命中即生效,所以显式 deny 规则必须写在 allow 之前,否则会被前面的宽泛 allow 吃掉。

第三步:改写为「默认拒绝 + 精确放行」

自动生成的规则通常过于宽松(常带 with-interface all)。手工整理成下面的结构,从上到下依次是:拒绝存储类、拒绝带 HID 键盘的未知复合设备、放行公司加密盘、放行指定键鼠。

# /etc/usbguard/rules.conf
# 1) 任何带大容量存储接口的设备一律拒绝(无序列号约束时用接口类兜底)
reject with-interface 08:06:50

# 2) 明确拒绝已知的 BadUSB 测试设备(示例 VID/PID)
reject id 1d6b:0104 name "BadUSB Test"

# 3) 放行公司配发的加密 U 盘(VID/PID + 序列号双约束)
allow id 0951:1666 serial "A1B2C3D4E5F6" name "CompanyKey" with-interface { 08:06:50 }

# 4) 放行指定型号键鼠,仅允许 HID 接口
allow id 046d:c52b serial "1234ABCD" name "USB Receiver" with-interface { 03:01:01 03:00:00 }
allow id 046d:c077 with-interface { 03:01:02 }

把默认动作改为拒绝,并开启审计与 IPC 权限控制:

# /etc/usbguard/usbguard-daemon.conf
ImplicitPolicyTarget=block
PresentDevicePolicy=apply-policy
InsertedDevicePolicy=apply-policy
RestoreControllerDeviceState=false
DeviceRulesWithPort=false
AuditBackend=LinuxAudit
AuditFilePath=/var/log/usbguard/usbguard-audit.log
sudo mkdir -p /var/log/usbguard
sudo systemctl enable --now usbguard
sudo systemctl status usbguard --no-pager
sudo usbguard list-rules | head -20

第四步:交互授权与临时放行

白名单之外偶尔需要临时接入设备(如客户送检的硬盘),用 IPC 接口授权并设定有效期,避免长期留口子。

# 查看当前设备与授权状态
sudo usbguard list-devices

# 按设备编号放行,并绑定当前端口
sudo usbguard allow-device 12 --permanent
sudo usbguard append-rule 'allow id 0781:5581 via-port "1-2"'

# 撤销授权
sudo usbguard block-device 12
sudo usbguard remove-rule 7

# 实时观察新设备接入
sudo usbguard watch

--permanent 会把规则写入 rules.conf,不加则仅在本次守护进程生命周期内有效,适合临时场景。

第五步:Windows 侧设备安装限制

组策略路径:「计算机配置 → 管理模板 → 系统 → 设备安装 → 设备安装限制」。先启用「禁止安装未由其他策略设置描述的设备」,再按需添加允许项。等价的注册表写法便于批量下发:

# 禁止安装所有未授权设备(Deny_All)
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceInstall\Restrictions" /v DenyUnspecified /t REG_DWORD /d 1 /f

# 允许指定 VID 的设备安装(编号从 1 开始,可多条)
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceInstall\Restrictions\AllowDeviceIDs" /v "1" /t REG_SZ /d "USB\VID_0951&PID_1666" /f

# 禁止可移动存储类(WPD 与 Mass Storage)
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}" /v Deny_All /t REG_DWORD /d 1 /f

策略生效后需要 gpupdate /force。注意 Deny_All 不会卸载已安装的设备驱动,历史上插过的 U 盘在策略生效后仍可能工作,必须清理 USBSTOR 键值并重新枚举:

# 查看历史接入记录
reg query "HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR" /s | findstr /i "Disk"

# 清理后重新触发设备枚举
pnputil /scan-devices
Get-PnpDevice -Class USB | Where-Object Status -eq "OK" | Select-Object FriendlyName, InstanceId

配置验证

  • 插入未在白名单的 U 盘,sudo usbguard list-devices 中该设备状态应为 block,lsblk 看不到对应分区。
  • 插入白名单内的加密盘,应能正常挂载;journalctl -u usbguard -n 30 有 allow 记录。
  • 规则语法自检:sudo usbguard generate-policy 输出与 rules.conf 比对,差异应只包含时序性字段(如 via-port 变化)。
  • Windows 侧:插入测试 U 盘,设备管理器出现「已被策略阻止安装」提示,事件日志 20001/20003 有记录。
  • 回归检查:键盘鼠标在重启后仍可用,说明规则未误伤 HID。

常见问题 FAQ

FAQ 1:白名单配错导致键盘鼠标失效、机器无法操作怎么办?

这是最常见的翻车场景,部署前必须准备好两条回退路径。第一条是本地控制台或带外管理(iDRAC/iLO/IPMI),登录后执行 systemctl stop usbguard 恢复即插即用。第二条是内核参数 usbguard.daemon_bypass 或单用户模式挂载后清空 rules.conf。建议先在 2 台非关键机器上跑满一周,观察 usbguard-audit.log 中的拒绝记录,把误伤的设备补进白名单后再批量推送。

FAQ 2:只拦 mass storage、不拦 HID 键盘,是不是就够了?

不够。BadUSB 的核心手法就是伪装成 HID 键盘或网卡,这类设备不带存储接口,只拦 08:06:50 完全无效。正确口径是白名单制:HID 也要按 VID/PID + 序列号放行,只允许公司采购的型号。如果业务上确实需要放开未知 HID,至少加一层补偿控制,例如通过 usbguard watch 联动脚本,检测到新 HID 设备时立即锁定会话并告警。

FAQ 3:设备更换、员工离职后白名单怎么维护?

把 rules.conf 纳入配置管理(Ansible/Git),不要手工逐台改。规则文件按「组织级公共段 + 站点级差异段」拆分,公共段由安全团队维护,站点段由本地 IT 维护。每季度做一次规则清理:导出 usbguard list-rules,与资产台账比对,删除已报废设备的允许项。序列号白名单的规模一旦超过 200 条,应改为「序列号前缀 + 型号」的组合规则,否则维护成本会失控。

总结

USB 设备管控的关键是把「默认允许」翻转成「默认拒绝」,并且让拒绝发生在驱动加载之前。Linux 侧 usbguard 的 ImplicitPolicyTarget=block 配合接口类与序列号约束,可以同时挡住 mass storage 传播和 BadUSB 伪装;Windows 侧用设备安装限制策略加注册表清理补齐。真正的风险不在技术,而在误配导致业务中断——所以部署顺序永远是:先审计(只记录不拦截)、再灰度(小范围拦截)、最后全量,每一步都保留带外回退通道。