ONVIF 摄像头加固这件事,多数团队是在被通报之后才开始做的。视频监控设备长期贴着「内网设备」的标签,等保测评时也只查口令强度,结果一台设备的 554 端口被映射到公网、ONVIF 接口允许匿名读取码流,就成了整个专网最省事的跳板。本文给出一套可复现的 ONVIF 摄像头加固流程,从暴露面测绘一直到 WS-Discovery 收敛与 ACL 隔离,命令可以直接粘贴执行。
适用场景
- 园区、门店、厂区的 IP 摄像头(海康、大华、宇视等)与 NVR 混部,设备型号杂、固件版本不统一。
- 摄像头所在网段与办公网互通,或历史上做过端口映射,554、80、8000 存在公网暴露风险。
- 视频专网需要通过等保 2.0 三级测评,被要求提供「设备身份鉴别」与「访问控制」证据。
- 安全团队发现内网存在对 3702/UDP 的组播探测,或流量中出现异常的 RTSP DESCRIBE 请求。
前置条件
- 一台与摄像头同网段或可路由的 Linux 管理机,已安装 nmap、curl、ffprobe(ffmpeg 套件)。
- 摄像头管理员账号(具备修改用户、网络、服务配置的权限),并已确认设备当前的 ONVIF 服务状态。
- NVR 或视频平台的固定 IP 清单,后续 ACL 只放行这些地址。
- 变更窗口:修改鉴权方式会导致平台短暂掉线,建议在非高峰时段操作。
原理说明
ONVIF 本身是一组 SOAP over HTTP 的接口规范,设备侧通常暴露在 /onvif/device_service 路径上。它的两个设计特点直接决定了风险面:一是 WS-Discovery,设备会监听 239.255.255.250:3702 的组播探测,只要收到 Probe 就回包告知自己的服务地址,任何同网段主机都能在几十秒内枚举出全部设备;二是 媒体服务默认宽松,部分固件在创建用户时会把 Media 服务的读权限一并授予,甚至保留匿名 Profile,导致拿到 GetStreamUri 就能直接拉流。
攻击链条通常是这样走的:组播探测拿设备清单 → 尝试厂商默认口令或弱口令 → 调用 GetProfiles 取 ProfileToken → 调用 GetStreamUri 得到带凭据的 RTSP 地址 → 长期静默拉流,或在设备上开一个反向通道。整个过程中设备日志几乎不留痕,这也是摄像头被入侵后很难定位时间点的原因。
因此加固要围绕三个动作展开:收敛发现面(谁都不能随便知道自己有几台设备)、收紧鉴权(没有匿名、没有共享账号、RTSP 强制 Digest)、限制可达性(只有 NVR 能访问 554)。
操作步骤
第一步:测绘暴露面与 ONVIF 服务
先在管理机上扫描目标网段,确认哪些设备开放了 ONVIF 与 RTSP 端口。3702 是 UDP,需要单独扫,用 TCP 扫描会漏掉。
# TCP 侧:设备 Web、ONVIF、RTSP、私有 SDK 端口
nmap -Pn -sT -p 80,443,554,8000,8080,2020,37777 192.168.10.0/24 -oG onvif_tcp.txt
# UDP 侧:WS-Discovery 组播监听
nmap -Pn -sU -p 3702 192.168.10.0/24 -oG onvif_udp.txt
grep -i "3702/open" onvif_udp.txt
结果里同时出现 554 与 3702 的主机,就是优先处理对象。把清单落到表格里,记录 IP、型号、固件版本、所属区域,后续 ACL 与固件升级都以这张表为准。
第二步:核对 ONVIF 用户与匿名权限
不带任何凭据直接请求设备信息服务,如果返回 200 并带出厂商与固件信息,说明服务端未强制鉴权。下面的 SOAP 请求在绝大多数 ONVIF Profile S 设备上通用:
curl -s -m 8 -o /dev/null -w "no-auth HTTP: %{http_code}\n" \
-X POST "http://192.168.10.51/onvif/device_service" \
-H "Content-Type: application/soap+xml; charset=utf-8" \
--data-binary '<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Body xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
<tds:GetDeviceInformation/>
</s:Body>
</s:Envelope>'
正常加固后的设备应返回 401 或 SOAP Fault(NotAuthorized)。若返回 200 且含 Manufacturer/Model,立即进入设备后台关闭「允许匿名访问」「ONVIF 匿名登录」之类的开关,并把 ONVIF 用户与 Web 用户分离:Web 管理账号只给运维,ONVIF 侧为每台 NVR 建独立只读账号,禁止多台平台共用一个账号——共号会让事后溯源彻底失效。
排查是否存在多账号时,可用带 WS-Security UsernameToken 的 GetUsers 请求枚举,重点关注创建时间早于设备入网时间的账号:
curl -s -m 8 -X POST "http://192.168.10.51/onvif/device_service" \
-H "Content-Type: application/soap+xml; charset=utf-8" \
--data-binary '<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<s:Header><wsse:Security><wsse:UsernameToken>
<wsse:Username>audit_ro</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">BASE64_DIGEST</wsse:Password>
<wsse:Nonce>BASE64_NONCE</wsse:Nonce>
</wsse:UsernameToken></wsse:Security></s:Header>
<s:Body><tds:GetUsers/></s:Body>
</s:Envelope>'
PasswordDigest 的计算方式是 Base64(SHA1(nonce + 创建时间 + 明文口令)),创建时间需与 Nonce 同批生成,直接手搓容易出错。实践里更快的路径是登录设备 Web 后台的用户管理页导出账号列表,ONVIF 接口只用来做交叉验证。
第三步:收敛 WS-Discovery 与 UPnP
发现协议是横向渗透的起点。设备后台通常有「ONVIF 发现」「UPnP」「即插即用」开关,全部关闭后,还需在网络侧兜底,防止固件升级又把开关打开。下面的规则在摄像头所在网关上执行,只允许 NVR 网段发起 3702 探测,其余全部丢弃,同时阻断设备主动向外做 UPnP 通告。
# 只保留 NVR 网段对 3702 的访问,其余丢弃
iptables -I INPUT -p udp --dport 3702 -s 192.168.10.20/32 -j ACCEPT
iptables -I INPUT -p udp --dport 3702 -j DROP
# 阻断设备侧的 SSDP 通告与 UPnP 端口映射
iptables -I FORWARD -p udp --dport 1900 -j DROP
iptables -I FORWARD -p tcp --dport 5000 -j DROP
# 固化规则
iptables-save > /etc/iptables/rules.v4
如果网关是 nftables,等价写法为 nft add rule inet filter input udp dport 3702 ip saddr != 192.168.10.20 drop。规则生效后再跑一次 UDP 扫描,应该完全看不到 3702 响应。
第四步:RTSP 鉴权与访问控制
关掉发现并不意味着码流安全。RTSP 的鉴权方式由设备决定,需要在后台把「RTSP 认证方式」从 Basic 改为 Digest,并关闭「允许匿名 RTSP」。Basic 认证的用户名口令在网络上等价于明文,抓一次包就能复用。
随后在网络侧把 554 的可达性收到最小集合,只允许 NVR 与运维跳板机:
# 建独立链,避免直接清空 INPUT 影响业务
iptables -N RTSP_GUARD
iptables -A INPUT -p tcp --dport 554 -j RTSP_GUARD
# 仅 NVR 与跳板机可访问 RTSP,其余丢弃并记日志
iptables -A RTSP_GUARD -p tcp --dport 554 -s 192.168.10.20 -j ACCEPT
iptables -A RTSP_GUARD -p tcp --dport 554 -s 192.168.10.5 -j ACCEPT
iptables -A RTSP_GUARD -p tcp --dport 554 -j LOG --log-prefix "RTSP_DENY: " --log-level 4
iptables -A RTSP_GUARD -p tcp --dport 554 -j DROP
iptables-save > /etc/iptables/rules.v4
如果设备支持,把 RTSP 端口从 554 改成非标准端口只能降低被扫描概率,不能替代鉴权,这一点在方案评审时要说清楚,否则容易被当成已完成的控制项。
第五步:固件与配置基线固化
摄像头固件极少签名,升级包必须从厂商官网下载并核对哈希。把每台设备的固件包 SHA-256 与当前配置导出一起归档,形成可回溯的基线。
# 校验固件包完整性,与官网公布值比对
sha256sum IPC_R6_2_1_15.bin
# 导出设备配置作为变更前基线(路径随厂商而异)
curl -s -u admin:****** "http://192.168.10.51/ISAPI/System/configurationData" -o cfg_10_51.xml
ls -lh cfg_10_51.xml
海康走 ISAPI,大华走 RPC2,宇视走 LAPI,导出接口不统一,但共同点是:配置导出前先确认走了 HTTPS 且关闭了调试口。部分老固件保留 23 端口的 telnet 调试入口,必须显式关闭。
配置验证
四项验证全部通过,才算加固完成,缺一项都不能结项。
# 1. 匿名 ONVIF 请求应返回 401
curl -s -o /dev/null -w "%{http_code}\n" -X POST "http://192.168.10.51/onvif/device_service" \
-H "Content-Type: application/soap+xml" --data-binary '<?xml version="1.0"?><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body/></s:Envelope>'
# 2. 组播发现应无响应
nmap -Pn -sU -p 3702 192.168.10.51
# 3. 未带凭据拉流应被拒绝
ffprobe -v error -rtsp_transport tcp -timeout 5000000 "rtsp://192.168.10.51:554/Streaming/Channels/101"
# 4. 非授权源访问 554 应被记录丢弃
dmesg | grep RTSP_DENY | tail -5
第 3 步预期返回 401 Unauthorized,若直接输出流信息说明匿名拉流仍然开放。第 4 步的日志是等保评审里最有效的「访问控制已生效」证据,建议接入日志平台做周度统计。
常见问题
Q1:关闭 WS-Discovery 后,视频平台搜不到设备了怎么办?
这是预期行为。平台依赖组播发现自动添加设备,关闭后必须改为手动添加:在平台侧填写设备固定 IP、ONVIF 端口(通常 80)、前面创建的只读账号与口令。建议先把设备 IP 从 DHCP 改成静态或做 DHCP 保留,否则重启后地址漂移会导致批量掉线。若平台不支持手动添加,可在网关上保留一条仅针对平台服务器 IP 的 3702 放通规则,其余仍丢弃。
Q2:修改 RTSP 为 Digest 鉴权后,NVR 录像中断怎么回滚?
先确认 NVR 侧填写的地址是否带了用户名口令,Digest 模式下部分老 NVR 不接受 URL 内嵌凭据,需要在通道配置里单独填账号。回滚顺序是:网络 ACL 先放通 → 鉴权改回 Basic → 平台恢复取流 → 再逐台切换。不要一次性对全部设备改鉴权,按区域分批,每批观察 30 分钟录像完整性再继续。
Q3:设备本身不支持 HTTPS,Web 管理口令会不会被嗅探?
会。这类设备的正确做法不是「凑合用」,而是把它当成不可信终端:管理面只允许运维跳板机访问,且走 SSH 隧道转发,禁止直接暴露到办公网。ssh -L 8080:192.168.10.51:80 ops@jump 之后本地访问 127.0.0.1:8080 即可,口令不再经过共享网段。同时在采购环节把「支持 HTTPS 与固件签名」写进技术参数,比事后加固有效得多。
总结
ONVIF 摄像头加固的收益不在单点配置,而在把「可发现、可匿名、可直连」三件事同时掐掉:关闭发现协议与 UPnP 让设备从资产列表里隐身,回收匿名与共号让凭据可追溯,RTSP 改 Digest 加 ACL 收口让码流只有 NVR 能拿。三步做完,一台被拿下的摄像头就不再是进入内网的跳板。建议把上述命令封装成巡检脚本,按季度跑一次,重点核对固件版本与 3702 的响应状态——固件升级把开关改回默认值,是这类设备最常见的「加固回退」。