IoT-For-Beginners:在 Raspberry Pi 与虚拟设备代码中使用 X.509 证书安全连接 IoT Hub
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
本指南基于 IoT-For-Beginners 项目「2-farm/6-keep-your-plant-secure」课程,讲解如何让土壤湿度监测设备(Raspberry Pi 单板计算机或虚拟 IoT 设备)放弃脆弱的连接字符串,改用 X.509 证书完成与 Azure IoT Hub 的身份认证与安全连接。读完本文你将掌握 X.509 设备身份的创建命令、azure.iot.deviceSDK 中X509类与create_from_x509_certificate的完整用法,并能在自己的设备代码中替换连接字符串实现非对称加密认证。
为什么要用 X.509 证书替代连接字符串
在课程 2-farm/lessons/6-keep-your-plant-secure/README.md 的前半部分中,已经介绍了 IoT 设备面临的安全威胁:攻击者可以克隆设备 ID 冒充真实设备发送虚假遥测(例如持续发送"土壤湿度很高"的假读数,导致灌溉系统永远不启动),或窃听个人数据。防范的核心手段是加密——用只有设备和云端知道的密钥把数据打乱,云端无法用密钥正确解密的消息将被直接拒绝。
加密分为两类:
- 对称加密:加密与解密使用同一把密钥,双方必须共享这把密钥。连接字符串中的
SharedAccessKey就是典型的对称密钥,它结构简单(HostName=...;DeviceId=...;SharedAccessKey=...),但密钥一旦在传输或源码中泄露,整个通信即可被破解。 - 非对称加密:使用公钥/私钥对。公钥只用于加密,私钥只用于解密;私钥永远保存在持有者手中,任何人都可以持有公钥而不会破坏安全性。
非对称加密面临一个新问题:接收方如何确认收到的公钥确实来自你,而不是冒名顶替者?解决方案就是 X.509 证书——一种包含公钥的数字文档,通常由可信的第三方认证机构(CA)签发并签名。使用证书时,双方各持自己的公钥/私钥对,交换包含公钥的 X.509 证书,用对方的公钥加密发送的数据、用自己的私钥解密收到的数据:
X.509 证书还有一个突出优势:一张证书可以被多台设备共享。你只需创建一张证书并上传到 IoT Hub,所有设备只需知道对应的私钥即可。设备发送给 IoT Hub 的加密证书由微软发布,与许多 Azure 服务共用,部分 SDK 甚至内置了该证书,因此可以安全地公开存放。需要注意:自签名证书仅用于测试,生产环境严禁使用自签名证书。
前置任务:创建基于 X.509 证书的设备身份
在修改设备代码之前,需要先在 IoT Hub 中注册一个新的设备身份。使用 Azure CLI 执行以下命令(将<hub_name>替换为你的 IoT Hub 名称):
az iot hub device-identity create --device-id soil-moisture-sensor-x509 \ --am x509_thumbprint \ --output-dir . \ --hub-name <hub_name>该命令自动完成三项工作:
- 生成 RSA 公钥/私钥对(RSA 是最常用的非对称密钥生成算法);
- 创建自签名 X.509 证书;
- 在 IoT Hub 中注册设备 ID 为
soil-moisture-sensor-x509的设备(与前几课用连接字符串创建的设备标识区分开)。
命令执行后会在当前目录生成两个关键文件:
| 文件 | 内容 | 安全级别 |
|---|---|---|
soil-moisture-sensor-x509-key.pem | 设备的私钥 | 必须保密,严禁提交到公开源码仓库 |
soil-moisture-sensor-x509-cert.pem | 设备的 X.509证书(含公钥) | 可公开分发 |
改造设备代码:从连接字符串切换到 X.509 证书
本节逐步讲解如何改造app.py。参照对象是前几课基于连接字符串的实现,例如 2-farm/lessons/4-migrate-your-plant-to-the-cloud/code/pi/soil-moisture-sensor/app.py 中通过IoTHubDeviceClient.create_from_connection_string(connection_string)连接的方式。
第 1 步:复制密钥与证书文件到代码目录
把soil-moisture-sensor-x509-key.pem和soil-moisture-sensor-x509-cert.pem复制到存放设备代码的文件夹。如果通过 VS Code Remote SSH 操作 Raspberry Pi、而密钥是在 PC/Mac 上生成的,可直接将文件拖拽到 VS Code 资源管理器中完成复制。
第 2 步:声明 IoT Hub 主机名
在创建设备客户端之前,添加保存主机名的变量:
host_name = "<host_name>"将<host_name>替换为你的 IoT Hub 主机名。可以从原连接字符串的HostName段获取,它就是 IoT Hub 名称加上.azure-devices.net后缀。
第 3 步:声明设备 ID
在host_name下方声明设备 ID,必须与上一步az iot hub device-identity create命令中--device-id参数一致:
device_id = "soil-moisture-sensor-x509"第 4 步:导入 X509 类
在从azure.iot.device模块导入类的语句中加入X509:
from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse, X509第 5 步:创建 X509 类实例
在host_name声明下方,用证书与私钥文件创建X509实例:
x509 = X509("./soil-moisture-sensor-x509-cert.pem", "./soil-moisture-sensor-x509-key.pem")X509构造函数的两个参数依次为证书文件路径与私钥文件路径(即上一步生成的两个.pem文件),这里使用相对路径./指向代码所在目录。
第 6 步:用证书创建设备客户端
把原本基于连接字符串创建device_client的那一行替换为:
device_client = IoTHubDeviceClient.create_from_x509_certificate(x509, host_name, device_id)create_from_x509_certificate接收三个参数——X509实例、IoT Hub 主机名和设备 ID,SDK 会以 X.509 证书方式完成与 IoT Hub 的认证握手,而非使用连接字符串。
第 7 步:删除 connection_string 变量
移除代码中所有connection_string相关行,确保不再引用连接字符串,避免对称密钥残留在源码中。
第 8 步:运行并验证
运行改造后的代码,观察终端输出与 IoT Hub 中的消息流:设备应显示Connecting→Connected,随后每 10 秒上报一次土壤湿度读数,并继续接收和处理来自云端的直接方法(Direct Method)请求(如relay_on/relay_off)。至此,土壤湿度传感器程序已通过 X.509 证书安全地接入 IoT Hub。
参考实现:仓库中的完整代码
本课程仓库中已提供可直接运行的完整示例,硬件与虚拟设备版本各一份:
- Raspberry Pi 版本:2-farm/lessons/6-keep-your-plant-secure/code/pi/soil-moisture-sensor/app.py
- 虚拟设备版本:2-farm/lessons/6-keep-your-plant-secure/code/virtual-device/soil-moisture-sensor/app.py
以 Raspberry Pi 版本为例,改造后的关键代码段如下:
import time from grove.adc import ADC from grove.grove_relay import GroveRelay import json from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse, X509 adc = ADC() relay = GroveRelay(5) host_name = "<host_name>.azure-devices.net" device_id = "soil-moisture-sensor-x509" x509 = X509("./soil-moisture-sensor-x509-cert.pem", "./soil-moisture-sensor-x509-key.pem") device_client = IoTHubDeviceClient.create_from_x509_certificate(x509, host_name, device_id) print('Connecting') device_client.connect() print('Connected') def handle_method_request(request): print("Direct method received - ", request.name) if request.name == "relay_on": relay.on() elif request.name == "relay_off": relay.off() method_response = MethodResponse.create_from_method_request(request, 200) device_client.send_method_response(method_response) device_client.on_method_request_received = handle_method_request while True: soil_moisture = adc.read(0) print("Soil moisture:", soil_moisture) message = Message(json.dumps({ 'soil_moisture': soil_moisture })) device_client.send_message(message) time.sleep(10)从源码结构可以清晰看到改造要点:硬件版本通过grove.adc读取土壤湿度、通过GroveRelay(5)控制继电器;虚拟设备版本则将这两处硬件访问替换为counterfit_shims_grove垫片(shim)库,并通过CounterFitConnection.init('127.0.0.1', 5000)连接 CounterFit 模拟器。除硬件访问层外,两者在 X.509 认证部分的代码完全一致,这印证了"证书认证与具体硬件无关"的设计——无论真实硬件还是模拟设备,认证逻辑都是同一套X509+create_from_x509_certificate组合。
安全要点总结
- 私钥是底线:
soil-moisture-sensor-x509-key.pem一旦泄露,攻击者即可冒充设备;切勿将其提交到公开源码控制库,建议部署时从硬件安全模块读取。 - 证书过期问题:若使用对称连接字符串,设备需依赖 NTP 服务器保持时间准确,否则 SAS 令牌校验会失败;而 X.509 证书同样有有效期字段,测试期自签名证书到期后需要重新生成并更新设备端文件。
- 生产环境注意:课程中的自签名证书仅用于学习测试,生产部署必须使用由受信任 CA 签发的证书。
- 多设备共享:X.509 证书支持一张证书对应多台设备,设备只需各自保管私钥,显著简化了大规模设备的密钥分发。
本课程是该农业 IoT 项目的最后一课,完成本部分后别忘了参照 clean-up.md 清理云资源以避免持续产生费用。你还可以阅读 2-farm/lessons/6-keep-your-plant-secure/wio-terminal-x509.md 了解同一套 X.509 方案在 Arduino/Wio Terminal 平台上的移植方法,两篇文档共同构成了本课程"用 X.509 证书加固全部设备形态"的完整实践路径。
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考