物联网安全
物联网把"能联网的设备"和"能动手脚的物理世界" 接在一起,于是一处缺口往往同时威胁数据与控制——读到一台电表的读数是隐私问题,篡改一台阀门的指令就是安全事故。这一章按设备、通信、平台、数据四个面,梳理物联网安全的威胁与对策,并说明这套思路在 IoT DC3 里如何落到鉴权、租户隔离与传输加密上。
你在这里:已读完四层参考架构,想理解贯穿四层的安全是怎么回事。读完你能画出一张"威胁—对策"地图,并知道 DC3 在每一层放了哪些防线。
这一层是什么 / 为什么存在
安全不属于感知、网络、平台、应用中的某一层,而是贯穿四层的横切关注点 。原因很直白:攻击者不会按你的分层走,他会找最薄的那一处下手。设备端固件可以被刷写,通信链路可以被监听和重放,平台接口可以被越权调用,数据库里的数据可以被脱库——任何一环失守,前面几环做得再好也白搭。所以谈物联网安全,必须四层一起谈,并且默认" 边界之外皆不可信"。
物联网的安全又比传统 IT 更难,难在三处。其一是设备资源受限:现场的传感器、网关算力小、内存少、可能靠电池供电,跑不动重型加密,也难做频繁的密钥轮换。其二是 物理可达:设备就摆在车间、田间、街头,攻击者能直接拿到手,拆芯片、读 Flash、接调试口,纯软件防护挡不住物理攻击。其三是**规模与异构 **:一个平台可能接入几十种协议、成千上万台设备,统一打补丁、统一轮换证书的成本极高,任何一台老旧设备都可能成为整片网络的入口。
正因为这些约束,物联网安全的目标不是"绝对安全",而是纵深防御:每一层都设一道关,任何单点被攻破都不至于全盘失守。下面按四层逐一展开,再用一张图把威胁与对策对齐。
关键技术与权衡
设备安全:信任从硬件开始
设备是物理可达的一环,防护必须从启动那一刻就建立信任。**安全启动(Secure Boot)**让 Bootloader 逐级校验固件签名,签名不对就拒绝运行,从根上挡住"刷入恶意固件";其信任链的根,是固化在芯片里、不可篡改的根密钥。密钥存储 则决定了私钥会不会被读走——把密钥放在普通 Flash 里等于裸奔,正确做法是用安全元件(SE)或可信执行环境(TEE)隔离存储,让密钥" 可用而不可读"。**固件升级(OTA)**必须验签后再写入,并支持回滚到已知良好版本,否则一次被劫持的升级就能批量沦陷整片设备。
权衡在于成本:带 SE/TEE、支持安全启动的芯片更贵,OTA 通道也要额外的签名与灰度机制。资源极受限的设备往往只能做到"验签升级 + 软件层密钥保护",把更强的硬件信任根留给关键节点。
通信安全:加密、认证与防重放三件套
设备到平台的链路天然暴露在网络上,三件事必须同时做到。加密用 TLS(面向 TCP,如 MQTT over TLS、HTTPS)或 DTLS(面向 UDP,如 CoAP)把链路保护起来,防窃听与篡改。认证要双向:服务端证书防止设备连到假平台(中间人),设备侧用证书或预共享密钥(PSK)证明自己是谁,防止设备伪造。 防重放则要防"录下一条合法报文、稍后原样重放"——靠时间戳、单调递增的序号或一次性随机数(nonce),让旧报文失效。
权衡在于受限设备:完整 TLS 握手的非对称运算和证书链对小设备是负担,于是出现 TLS-PSK、会话复用、用更轻的椭圆曲线算法等折中。再轻也不能省掉"认证 + 防重放"这两条,否则加密只是给攻击者也加了密。
平台安全:认证、授权、租户隔离、审计
设备的数据汇聚到平台,平台就成了高价值目标。认证回答"你是谁"——登录换取令牌,令牌可验证、有时效。授权回答"你能做什么" ——按 RBAC(基于角色的访问控制)把主体、角色、资源绑起来,并坚持最小权限与fail-closed(查不到权限就拒绝,绝不默认放行)。* *多租户隔离**回答"你能碰哪条数据"——它与授权正交:有"读设备"的权限,不代表能读别家租户的设备;隔离做不好,一个租户就能看到甚至操作另一个租户的现场设备。 审计则把"谁在什么时候做了什么"记下来,既用于事后追责,也用于实时发现异常。
数据安全:隐私、脱敏、合规
物联网数据常常关联到个人与现场——一台智能电表的用电曲线能反推出家里有没有人,一段定位轨迹就是行踪。隐私 要求遵循最小采集与目的限定,不该收的别收。脱敏要求在展示、导出、给第三方(包括喂给大模型)之前,把敏感字段做掩码或匿名化。* 合规* 则把这些上升为硬要求:GDPR、个人信息保护法等法规对采集、存储、跨境传输都有约束,违规的代价远高于一次技术故障。数据安全还包括静态加密(落库加密、磁盘加密)与最小留存(过期即删),让" 即使被脱库,拿到的也是密文或残缺数据"。
威胁模型:把攻击面摊开看
把上面四层的对策对齐到具体威胁,安全设计才有靶子。下图按数据流标注五类典型威胁与对应的防线:
- 设备伪造:冒充合法设备上报假数据或骗取指令——靠设备侧强认证(一机一密、证书)破解。
- 固件篡改:刷入带后门的固件——靠安全启动 + 验签 OTA + 回滚机制守住。
- 重放攻击:录下合法报文原样重放——靠时间戳、序号、nonce 让旧报文失效。
- 中间人(MITM):在链路中间窃听或改包——靠双向认证 + 加密,让伪造的对端通不过证书校验。
- DDoS:用海量请求打垮入口——靠把入口收敛到单一网关、配合限流与防火墙。
- 越权 / 跨租户:合法身份越界访问别人的资源——靠 RBAC 的 fail-closed 与租户隔离双重把关。
工程要点
- 默认不可信,边界之外皆需验证:不要假设"内网就是安全的"。后端服务即便不直接对外,也要校验调用方身份,防止有人绕过网关直连。
- 失败要 fail-closed,不要 fail-open:鉴权组件遇到瞬时故障时,宁可把请求当作"无权限"拒掉,也不要"出错就放行" ——后者会把一次抖动变成一道后门。
- 密钥分级、按环境收紧:开发环境可以用弱默认值图方便,但生产必须强制强随机密钥;最好让程序在生产环境发现弱密钥时**直接启动失败 **,把问题挡在上线前。
- 入口越少越好:把对外暴露面收敛到单一网关,现场协议端口(Modbus、裸 TCP/UDP)绝不直接上公网——它们大多没有认证,一旦暴露就是开门揖盗。
- 传输默认加密:消息总线、Broker、HTTP 入口在跨网络时一律走 TLS;明文只在本地自测可接受。
- 审计可追溯:关键操作(登录、改授权、下发命令)都要留痕,且日志里不能出现明文密钥或口令。
在 IoT DC3 中如何落地
DC3 的安全主线集中在鉴权 · 租户 · RBAC,并辅以安全策略 里的部署基线。它把上面四层的思路具体化为下面几条,而且对"已实现"和"设计已规划未实现"严格区分。
平台认证:两步登录与令牌
DC3 对外只有网关 dc3-gateway 一个入口。登录是两步握手,对应通信安全里的"防重放"思路:
POST /api/v3/auth/token/salt:传tenant、name,先确认租户存在,返回一个随机盐。盐是无状态 的——服务端不存储、不做过期校验,仅随下一次登录请求一并核对;"5 分钟"只是接口文案里的建议使用时限,由客户端自律,当前服务端未强制过期。POST /api/v3/auth/token/generate:传tenant、name、salt和用盐哈希后的password,校验通过返回 access token,* 有效期 12 小时*。
盐的作用是避免口令明文或固定哈希在链路上被重放。签发的 JWT 绑定 principal_id + tenant_id(而非用户名),注销时把身份写入 Caffeine 注销名单(denylist),旧令牌即便签名合法也会因签发时间早于注销点而失效。
平台信任传递:网关验签 + HMAC 透传
中心服务各有 HTTP 端口、默认不对外。隐患是:任何能直连后端端口的人,只要伪造一个"我是租户 A 管理员"的请求头,后端若无条件信任就被冒充。DC3 的解法是把认证与信任分开——认证只在网关做一次,信任靠一段 HMAC-SHA256 签名传递:
- 网关
AuthenticGatewayFilter用三个头X-Auth-Tenant/X-Auth-Login/X-Auth-Token去鉴权中心核验,解析出真实 principal,序列化为X-Auth-Principal,再用共享密钥签名得到X-Auth-Sign透传给后端。 - 后端
GatewayJwtConverter用同一密钥重算 HMAC,与X-Auth-Sign做常量时间比对,不符即拒;缺tenantId或principalId一律拒。 - HMAC 未启用时,网关会主动删除入站的
X-Auth-Sign,防止下游被客户端自带的假签名诱骗。
生产 HMAC/密钥 fail-fast(硬约束)
在 pre / pro 环境下,若 AUTH_HMAC_SECRET 为空、或仍等于默认值 io.github.pnoker.dc3,服务启动即失败(抛 IllegalStateException,判定见 HmacAuthConfig.isProtectedEnvironment())。这是有意为之:宁可不启动,也不让生产实例跑在开发密钥上。生产请用强随机值(如 openssl rand -base64 48)通过环境变量注入,绝不硬编码或写进日志。鉴权中心签发令牌用的 DC3_SECURITY_KEY(默认 dc3.security.key.2026.io.github.pnoker)则只做"必须存在"的启动检查——缺失即启动失败,但不做"不得等于默认弱值" 的拒绝;因此仍必须主动替换为强随机值,一旦泄露,攻击者可伪造登录令牌。
平台授权:RBAC 的 fail-closed
验签拿到 principal 后,由 RBAC 决定"能做什么":principal → 角色(租户内)→ 资源码(全局)。权限解析带 5 分钟短缓存(键为 (tenantId:principalId))。最关键的是失败语义:
查不到权限 = 拒绝
权限加载发生瞬时故障时,GatewayJwtConverter 仍创建一个"已认证但权限为空"的令牌,任何 @PreAuthorize 守卫返回 403 。这是有意的 fail-closed——绝不把后端抖动伪装成放行。
多租户隔离:控制器层校验
RBAC 决定"能不能做这类操作",租户隔离决定"能不能碰这条数据",两者正交。隔离落在控制器层:
- 按 ID 查到实体后,
BaseController.requireTenant()比对实体tenantId与调用方租户,不一致(或不存在)抛NotFoundException,返回 404 而非 403——刻意用"不存在"避免泄露"某个跨租户资源是否存在"。批量查询走filterTenant()剔除非本租户条目。
没有数据库层的自动租户兜底
当前实现没有 MyBatis-Plus 租户行拦截器,隔离完全靠控制器层的 requireTenant / filterTenant。新增查询时务必主动带上租户校验,SQL 层不会自动按租户裁剪。
通信与数据安全:部署基线
传输加密与数据保护落在安全策略的生产基线里:RabbitMQ 与 EMQX 默认关闭 TLS,跨网络时必须启用(如 RABBITMQ_SSL_ENABLED=true,走 TLS 端口);网关 HTTP 入口应置于反向代理后终止 HTTPS;现场协议端口绝不直接上公网( DC3_BIND_HOST 默认 127.0.0.1,需显式改为 0.0.0.0 才对外)。
外部身份(IdP)尚未实现
dc3_identity_provider(OIDC/SAML 等外部 IdP 配置)与 dc3_external_identity(外部身份绑定)两张表已在 02-iot-dc3-auth.sql 中建好,principal.source_type 也预留了 EXTERNAL 取值,但对应的登录端点未实现、处于关闭状态 。当前可用的登录路径只有上面的本地凭据两步握手。
面向 AI 调用方的 OAuth 2.1
面向大模型/MCP 客户端的访问,DC3 提供了独立的 OAuth 2.1 授权服务(强制 PKCE、刷新令牌轮换、按 scope 与风险等级过滤工具),详见 Agentic 与 MCP 与 鉴权 · 租户 · RBAC。
延伸阅读
- 数据智能与 AIoT — 数据在安全防线之内如何转化为洞察与自动决策
- 物联网技术总览 — 四层参考架构与安全的横切定位
- 鉴权 · 租户 · RBAC — 登录、HMAC 透传、RBAC 与租户隔离的完整链路
- 安全策略 — 版本维护、漏洞上报与上线前的最小安全基线