Python Socket编程如何获取通信全程固定的客户端与服务端ID
解决方案
你之前尝试通过hostname、IP获取设备ID的思路本身就不成立——IP是动态分配的,hostname可以随意修改,你拿到127.0.1.1是因为系统hosts默认将本地主机名映射到回环地址,这类网络标识完全不满足安全场景下ID固定、唯一的要求。
获取跨平台、长期固定的设备ID,可以用以下两类方案:
方案1:基于网卡MAC地址生成ID(实现简单,跨平台兼容性最好)
MAC地址是物理网卡的硬件标识,除非更换网卡否则不会变动,适合大多数场景。注意不要直接使用原始MAC,建议做哈希处理,避免泄露硬件隐私。
import uuid import hashlib def get_persistent_device_id() -> str: # 读取物理网卡MAC地址,跨Windows/Linux/macOS生效 mac_addr = uuid.getnode() # 对MAC做SHA256哈希,生成固定长度的统一格式ID return hashlib.sha256(str(mac_addr).encode("utf-8")).hexdigest()
如果设备存在多网卡(有线、无线、虚拟网卡并存),uuid.getnode()会默认优先读取第一个物理网卡的MAC,只要硬件不改动,返回值始终固定。
方案2:读取系统级原生机器ID(稳定性最高)
各操作系统在安装时会生成全局唯一的机器标识,哪怕更换网卡也不会变动,稳定性比MAC更高,仅在系统重装时会重置:
- Linux:读取
/etc/machine-id文件 - Windows:读取注册表中
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography下的MachineGuid值 - macOS:读取硬件平台UUID
IOPlatformUUID
跨平台实现代码如下:
import sys import subprocess import hashlib def get_system_level_device_id() -> str | None: raw_id = "" if sys.platform.startswith("linux"): with open("/etc/machine-id", "r", encoding="utf-8") as f: raw_id = f.read().strip() elif sys.platform == "win32": import winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography") raw_id, _ = winreg.QueryValueEx(key, "MachineGuid") winreg.CloseKey(key) elif sys.platform == "darwin": res = subprocess.run( ["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"], capture_output=True, text=True ) for line in res.stdout.splitlines(): if "IOPlatformUUID" in line: raw_id = line.split('"')[-2] break return hashlib.sha256(raw_id.encode("utf-8")).hexdigest() if raw_id else None
安全通信场景的注意事项
设备ID仅作为身份的公开标识,不能直接作为认证凭证。要实现你要求的机密性、身份可认证、完整性可校验目标,不能只靠固定ID:
- 客户端、服务端首次部署时各自生成非对称密钥对,提前通过可信渠道交换双方「设备ID-公钥」的绑定关系
- 建立连接时,先用对方的公钥验证其身份签名,确认身份合法后再协商会话对称密钥,后续所有传输内容用会话密钥加密、附加校验码,才能完整满足安全要求
绝对不要用IP、动态主机名这类可变值作为身份标识,否则不仅会因为网络变动导致认证失效,还很容易被攻击者伪造身份。
内容的提问来源于stack exchange,提问作者Ankush Soni
相关产品推荐
相关产品推荐

