IoT-For-Beginners 智能农场安全加固:从对称密钥到 X.509 证书保护你的土壤湿度设备
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
导读
本篇技术指南源自 IoT-For-Beginners 课程第二项目《智能农场》的收官课程,讲解如何为已经接入 Azure IoT Hub 的土壤监测设备建立完整的安全防线:先剖析 IoT 设备面临的真实威胁与密码学基础,再深入讲解连接字符串背后的对称密钥(SAS Token)认证机制,最后给出基于 X.509 证书的非对称认证方案,并介绍 Azure CLI 的实操命令与 Python SDK 的完整接入代码。学完本篇,你将掌握"为什么 IoT 设备会被攻破"“对称与非对称加密在设备认证中如何分工”以及"如何用一条 CLI 命令生成证书并用其替换连接字符串"的完整实战能力。
为什么需要保护 IoT 设备?
在前几课中,你已经搭建了土壤湿度监测设备并将其接入云。但假设竞争对手雇佣的黑客夺取了你的 IoT 设备控制权:他们可以持续上报"土壤湿度充足"的假读数,让灌溉系统永远不启动,植物因缺水枯死;也可以强制开启水泵让系统不停浇水,植物因涝死,水费暴涨。这正是本课要解决的场景——IoT 安全。
IoT 安全的目标有两层:只允许预期的设备连接云端 IoT 服务并发送遥测,以及只有你的云服务能向设备发送命令。同时 IoT 数据可能涉及医疗或私密信息,整个应用都需要把安全纳入考虑,防止数据泄露。
如果应用不安全,将面临以下风险:
- 伪造设备发送错误数据,导致应用做出错误响应(例如持续上报高湿度,灌溉系统永不启动);
- 未授权用户读取 IoT 设备上的个人或商业关键数据;
- 黑客向设备发送控制命令,损坏设备或与其相连的硬件;
- 通过攻破 IoT 设备进入更多网络,访问私有系统;
- 恶意用户窃取个人数据用于敲诈勒索。
这些并非理论假设,而是真实发生过的事件:
- 2018 年,黑客利用水族箱恒温器上的开放 WiFi 接入点,侵入赌场网络窃取数据;
- 2016 年,Mirai 僵尸网络利用使用默认用户名/密码的 DVR 和摄像头等 IoT 设备发起分布式拒绝服务攻击(DDoS),导致大范围网络中断;
- Spiral Toys 公司的 CloudPets 联网玩具用户数据库在互联网上公开暴露,儿童的语音消息被泄露并被勒索;
- 健身应用 Strava 公开了用户跑步时经过的其他用户位置与路线,陌生人可以借此推断你的住址。
💁 安全是一个宏大的主题,本课只涉及"设备连接云端"的基础部分。设备端数据防篡改、设备被直接入侵、设备配置被篡改等不在本课范围内。IoT 攻击威胁之大,催生了类似电脑杀毒软件、专为低功耗小型 IoT 设备设计的防护工具。
密码学基础:加密、解密与密钥
设备连接 IoT 服务时,用设备 ID 标识自己。但 ID 可以被克隆——黑客可以伪造一台使用相同 ID 的设备发送假数据。
解决办法是把要发送的数据转换成乱码格式,用只有设备和云知道的某个值来打乱数据。这一过程称为加密(encryption),用于加密数据的值称为加密密钥(encryption key)。
云服务随后使用相同或配对的密钥把数据恢复为可读格式,这一过程称为解密(decryption)。如果密文无法用密钥解开,说明设备已被入侵,消息会被拒绝。这套加密/解密技术统称为密码学(cryptography)。
早期密码学
最早的密码类型是替换密码(substitution cipher),可追溯到 3500 年前,其思想是"用一个字母替换另一个字母"。例如凯撒密码(Caesar cipher)按固定位数平移字母表,只有发送方和接收方知道平移位数。维吉尼亚密码(Vigenère cipher)更进一步,用单词来加密文本,使原文中每个字母被平移不同的位数,而非统一平移相同数量。
历史上密码学用途广泛:保护古代美索不达米亚陶工的釉料配方、在印度书写秘密情书、为古埃及魔法咒语保密等。
现代密码学
现代密码学建立在复杂数学之上,可用密钥数量多到让暴力破解在事实上不可行。现代加密应用在生活各处:HTTPS(HyperText Transfer ProtocolSecure)即加密了浏览器与 Web 服务器之间的通信,即使有人截获流量也无法读取内容;你的电脑还可能对整个硬盘加密,设备被盗时没有密码就无法读取数据。
💁 尽管现代密码学声称破解加密需要数十亿年,量子计算的兴起可能让现有加密在极短时间内被破解——这也是后量子密码学受到关注的原因。
不幸的是并非所有设备都安全:有些设备完全没有防护,有些使用极易被破解的弱密钥,甚至同一型号的所有设备共用同一个密钥。曾有非常私密的 IoT 设备全部使用相同的 WiFi/蓝牙连接密码——如果你能连上自己的设备,就能连上别人的,进而访问私密数据或控制设备。
对称密钥与非对称密钥
加密分两种类型:对称加密和非对称加密。
对称加密使用同一个密钥完成加密和解密,发送方与接收方都需要持有这把钥匙,安全性相对最低,因为密钥必须以某种方式共享——发送方必须先告知接收方密钥:
如果密钥在传输中被窃取,或发送方/接收方被入侵后密钥泄露,加密即被破解:
非对称加密使用两把密钥——加密密钥与解密密钥,即公钥/私钥对。公钥用于加密消息但不能解密,私钥用于解密消息但不能加密:
接收方公开分享公钥,发送方用其加密消息,接收方用私钥解密。私钥从不分享,因此非对称加密更安全;任何人都可以持有公钥,因为它只能用于加密。
两种方案各有取舍:对称加密更快,非对称加密更安全。混合方案也常见——先用非对称加密安全地交换对称密钥,再用对称密钥加密所有数据,兼顾安全性与速度。
保护 IoT 设备:两种认证路径
IoT 设备可以用对称或非对称加密保护。对称方案更简单但安全性较低。
对称密钥:连接字符串与 SAS Token
你在把设备接入 IoT Hub 时使用了连接字符串,其典型形态为:
HostName=soil-moisture-sensor.azure-devices.net;DeviceId=soil-moisture-sensor;SharedAccessKey=Bhry+ind7kKEIDxubK61RiEHHRTrPl7HUow8cEm/mU0=连接字符串由分号分隔的三个"键=值"段组成:
| 键 | 值 | 描述 |
|---|---|---|
| HostName | soil-moisture-sensor.azure-devices.net | IoT Hub 的 URL |
| DeviceId | soil-moisture-sensor | 设备的唯一 ID |
| SharedAccessKey | Bhry+ind7kKEIDxubK61RiEHHRTrPl7HUow8cEm/mU0= | 设备与 IoT Hub 共知的对称密钥 |
最后一段SharedAccessKey就是设备与 IoT Hub 共同持有的对称密钥,它永远不会在设备与云之间传输,只用于加密收发的数据。
✅ 实验:修改连接字符串中的
SharedAccessKey段再连接设备,观察会发生什么——连接将被拒绝。
SAS Token 的握手原理
设备首次连接时,会发送一个共享访问签名(SAS)Token,包含三部分:IoT Hub 的 URL、签名过期时间戳(通常为当前时间起 1 天)和签名。签名是"URL + 过期时间"用连接字符串中的共享访问密钥加密后的结果。
IoT Hub 用共享访问密钥解密该签名,若解密值与 URL 和过期时间匹配,则允许设备连接;同时校验当前时间早于过期时间,防止恶意设备捕获真机的 SAS Token 后重放攻击。
这是一种优雅的身份验证方式:发送方同时给出已知数据的明文与密文,服务端解密密文并比对明文,若一致即证明双方持有同一把对称加密密钥。由于有过期时间,设备需要准确的时间(通常从 NTP 服务器读取),时间不准会导致连接失败。连接建立后,设备与 IoT Hub 之间的所有双向数据都用共享访问密钥加密。
✅ 思考:如果多台设备共用同一个连接字符串会发生什么?
💁 把密钥硬编码进代码是不良安全实践:黑客拿到源码就等于拿到密钥,且发布代码时每台设备都要重新编译。更好的做法是从硬件安全模块(HSM)——设备上一块存储加密值、供代码读取的芯片——加载密钥。学习阶段把密钥写在代码里(如前几课那样)通常更方便,但绝不能把密钥提交进公开的源代码仓库。
双密钥与密钥轮换
每台设备有两把密钥和两套对应的连接字符串。这允许你进行密钥轮换(rotation):当第一把密钥被泄露时切换到第二把,然后重新生成第一把。轮换机制是 IoT Hub 设备身份认证的内置能力,使密钥泄露后可快速止损。
X.509 证书:更安全的非对称认证
使用非对称加密时,你需要把公钥提供给任何想给你发数据的人。问题是:接收方如何确认这把公钥真的属于你,而不是冒名顶替者?答案是:不直接提供公钥,而是把公钥放进一份由可信第三方验证过的证书中,即X.509 证书。
X.509 证书是包含公钥/私钥对中公钥部分的数字文档。它们通常由被称为证书颁发机构(CA)的可信组织签发,并由 CA 数字签名以证明密钥有效且属于你。你信任证书及其中的公钥,是因为你信任签发它的 CA——就像你信任护照或驾照是因为信任签发国。证书需要付费,因此为了测试,你也可以自签名(self-signed)——自己创建并自己签名一份证书。
⚠️绝不要在生产环境使用自签名证书。自签名证书仅用于测试验证。
证书包含若干字段:公钥归属者、签发 CA 的详情、有效期以及公钥本身。使用证书前,应校验它确实由原始 CA 签名。
使用 X.509 证书时,发送方和接收方各自持有自己的公钥、私钥以及包含公钥的 X.509 证书。双方交换证书,用对方的公钥加密所发送的数据,用自己的私钥解密所接收的数据:
X.509 证书的一大优势是可以在设备之间共享:你可以创建一份证书,上传到 IoT Hub,供所有设备使用,每台设备只需知道用于解密 IoT Hub 消息的私钥。
设备向 IoT Hub 加密消息所用的证书由 Microsoft 发布,与众多 Azure 服务使用的是同一张证书,有时甚至内置在 SDK 中。
💁 记住,公钥就是"公开的"。Azure 公钥只能用于加密发往 Azure 的数据,不能解密,因此可以随处分享,包括放进源码。设备代码中用到的客户端证书一般放在项目内的
certs/目录,IoT Hub 通过指纹或 CA 关系来校验。
实操:生成并使用 X.509 证书
生成 X.509 证书的步骤为:
- 生成一对公钥/私钥。最广泛使用的密钥对生成算法之一是RSA(Rivest–Shamir–Adleman);
- 将公钥连同相关数据提交签名,可由 CA 签名,也可自签名。
Azure CLI 提供了在 IoT Hub 中创建新设备身份、自动生成公钥/私钥对并创建自签名证书的命令,一步到位。
任务一:用 X.509 证书创建设备身份
运行以下命令注册新的设备身份,自动生成密钥与证书:
az iot hub device-identity create --device-id soil-moisture-sensor-x509 \ --am x509_thumbprint \ --output-dir . \ --hub-name <hub_name>将<hub_name>替换为你的 IoT Hub 名称。该命令会创建 ID 为soil-moisture-sensor-x509的设备(与上一课创建的soil-moisture-sensor区分),并在当前目录生成两个文件:
soil-moisture-sensor-x509-key.pem—— 设备的私钥文件;soil-moisture-sensor-x509-cert.pem—— 设备的X.509 证书文件。
务必妥善保管这两个文件!私钥文件绝不能提交进公开源代码仓库。
💁 若想了解不用 Azure CLI、手动生成证书的详细步骤(如用 OpenSSL),可参考前序课程对 OpenSSL 自签名流程的说明。
任务二:在设备代码中使用 X.509 证书
不同硬件平台的接入方式不同:
- Arduino - Wio Terminal:截至撰写本文时,Azure Arduino SDK 尚不支持 X.509 证书。想体验 X.509,可改用 Python SDK 的虚拟设备方案,详见 Wio Terminal 说明。
- 树莓派 / 虚拟 IoT 设备(Python SDK):完整步骤见 单板电脑 X.509 接入指南,核心改动如下。
Python SDK 的 X.509 接入要点
把
soil-moisture-sensor-x509-key.pem和soil-moisture-sensor-x509-cert.pem复制到设备代码所在目录(树莓派通过 VS Code Remote SSH 时可直接拖拽复制);打开
app.py,在创建设备客户端前声明 IoT Hub 主机名:host_name = "<host_name>"将
<host_name>替换为 IoT Hub 主机名(来自连接字符串的HostName段,即 hub 名称加.azure-devices.net后缀);声明设备 ID:
device_id = "soil-moisture-sensor-x509"从
azure.iot.device模块导入X509类:from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse, X509用证书与私钥文件创建
X509实例:x509 = X509("./soil-moisture-sensor-x509-cert.pem", "./soil-moisture-sensor-x509-key.pem")将原来用连接字符串创建
device_client的代码替换为:device_client = IoTHubDeviceClient.create_from_x509_certificate(x509, host_name, device_id)这将以 X.509 证书替代连接字符串完成认证;
删除
connection_string变量那一行;运行代码,按之前的方式监测发送到 IoT Hub 的消息并发送直接方法(direct method)请求。你会看到设备正常连接、上报土壤湿度读数,并能接收直接方法请求。
本课仓库中提供了可直接对照的完整实现:树莓派版本 与 虚拟设备版本。从源码结构可以看到完整的认证改造:host_name、device_id、X509实例三段式配置取代了前序课程(第 4 课连接代码)中的connection_string = '<connection_string>'与create_from_connection_string(connection_string);设备端handle_method_request对relay_on/relay_off直接方法的响应逻辑保持不变,遥测照常以Message(json.dumps({'soil_moisture': soil_moisture}))形式每 10 秒上报一次——安全加固并未改变应用行为,只替换了认证凭据。
💁 对比前序课程可知,第 4 课 中创建设备身份用的是
az iot hub device-identity create --device-id soil-moisture-sensor --hub-name <hub_name>(默认走对称密钥),再用az iot hub device-identity connection-string show取出连接字符串;本课则是同一命令族增加--am x509_thumbprint参数,直接从对称密钥切换到 X.509 指纹认证,两份凭据互不干扰、可随时切换。
项目收尾:清理云资源,控制成本
这是本项目的最后一课。完成本课及作业后,务必清理云服务(作业需要这些服务,所以先完成作业再清理)。清理指南详见 clean-up.md。
在本项目中你可能创建过以下资源:资源组(Resource Group)、IoT Hub、设备注册、存储账户、函数应用(Functions App)等。多数资源免费或处于免费层;即便费用较低,用完后删除仍然值得——例如订阅中免费层的 IoT Hub 只能创建一个,想再建就得用付费层。
由于所有服务都建在资源组内,删除资源组即可连同其中所有服务一并删除:
az group delete --name <resource-group-name>将<resource-group-name>替换为你的资源组名称。命令会弹出确认提示:
Are you sure you want to perform this operation? (y/n):输入y确认,删除所有服务会花费一些时间。
🚀 挑战:用 Azure Portal 管理服务
创建、管理和删除 Azure 服务(如资源组与 IoT Hub)有多种方式,其中一种是Azure Portal——基于 Web 的图形化管理界面。请登录 Portal,尝试用 Portal 创建一个 IoT Hub,然后将其删除。
提示:通过 Portal 创建服务时无需预先创建资源组,创建服务时可以一并创建;但完成后务必把资源组也删除。
作业:构建一台全新的 IoT 设备
详细要求与评分标准见 assignment.md。在过去的 6 课中,你学习了数字农业,以及如何用 IoT 设备采集数据预测植物生长、依据土壤湿度自动浇水。现在请综合所学,用你选定的传感器与执行器构建一台新 IoT 设备:向 IoT Hub 发送遥测,并用无服务器代码依据遥测控制执行器。可以使用本课程或前一项目用过的传感器与执行器,若有其他硬件也可以尝试新组件。评分关注三方面:能否编码出同时使用传感器和执行器的设备、能否部署 IoT Hub 并双向通信(发送遥测 + 接收命令)、能否部署由遥测事件触发的 Azure Function 来控制执行器。
回顾与自修建议
- 深入了解密码学的演进历史(从替换密码到现代密码体系);
- 系统阅读 X.509 证书规范,掌握其中的字段含义与证书链验证机制;
- 若想深入了解 IoT Hub 的其他通信原语(设备到云消息、云到设备消息、直接方法、设备孪生),可回顾第 4 课对 IoT Hub 通信模型的讲解。
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考