通过用户名密码认证保障 MQTT 接入安全
认证是一种安全措施,用于识别用户并验证他们是否有权访问系统或服务器。它能够保护系统免受未经授权的访问,确保只有经过验证的用户才能使用系统。
物联网连接万物,对试图访问基础设施的用户进行认证至关重要。未经授权的访问存在重大的安全隐患,必须加以防范。因此,物联网开发者应该全面了解各类认证方法。
在本文中,我们将探讨 MQTT 中的认证机制,以及其可以解决什么安全风险,并介绍一种常用的认证方式:基于密码的认证。
MQTT 中的认证
在 MQTT 中,认证是在连接建立时对客户端或者服务端的身份进行验证的过程。它仅涉及是否有权限连接到 Broker,与授权不同,后者决定客户端可以发布和订阅哪些主题。我们将在本系列之后的文章中对授权进行详细讲解。
- 基于密码的认证:Broker 检查客户端是否具有正确的连接凭据,包括用户名、客户端 ID 和密码。Broker 可以根据密码验证用户名或客户端 ID。
- 增强认证:引入了支持质询-响应机制的认证框架,可以支持 SCRAM、Kerberos 等多种认证机制。
- 其他:如基于令牌的身份验证(例如 JWT)等。
本文中我们将重点介绍基于密码的认证方式。
基于密码的认证
基于密码的认证是一种通过检验连接方是否拥有正确的密码凭据来确认连接方身份的方法。
在 MQTT 中,基于密码的认证通常使用用户名和密码作为凭据,但在某些特殊场景下,有些客户端可能无法提供用户名,因此客户端 ID 也可以作为唯一标识来代表身份。
当 MQTT 客户端与 Broker 建立连接时,它会在 CONNECT 报文中携带用户名和密码。下面的示例展示了用 Wireshark 工具抓取的客户端 CONNECT 报文,其中 Client ID 为 client1,用户名为 user,密码为 MySecretPassword。
Broker 从 CONNECT 报文中提取用户名(或客户端 ID)和密码后,需要在相应的数据库中查询该用户名对应的凭据,然后与客户端发送的密码进行比较。如果数据库中不存在该用户名,或者密码与数据库中的凭据不一致,Broker 将拒绝客户端的连接请求。
下图展示了 Broker 如何使用 PostgreSQL 来验证客户端的用户名和密码。
基于密码的认证可以确保只有拥有正确凭据(即用户名和密码)的客户端才能连接到 Broker。但是,正如在 Wireshark 抓包过程中所见,如果有人能够黑进通信通道,他们就可以轻松地截取数据包并获取连接凭据,因为它们都以明文形式发送。关于这个问题,我们将在本系列的后续文章中讲解如何使用 TLS(安全传输层协议)进行解决。
使用 Salt 和 Hash 保护你的密码
以明文方式存储密码是一种危险的做法,因为这将导致密码容易被窃取。如果攻击者获得了密码数据库或密码文件的访问权,他们就可以轻松地读取并使用密码对系统进行非法访问。为了防止这种情况发生,密码应该在存储之前经过哈希和 Salt 加密。
哈希是一个函数,接收输入数据,对数据进行数学运算,然后生成一个与原始输入数据完全无关的哈希值。这样做的目的是为了混淆原始输入数据。这个函数应该是不可逆的,确保不能根据输出还原输入。然而,哈希值本身并不安全,可能会受到字典攻击,如下例所示。
sha256 hash: 8f0e2f76e22b43e2855189877e7dc1e1e7d98c226c95db247cd1d547928334a9
加密后的密码看起来很安全,通过观察你无法推测出密码是什么。然而,对于一个固定的密码,哈希值总是相同的。因此,很容易制作一个包含常用密码及其哈希值的数据库。如下表:
sha256 hash | 明文密码 |
---|---|
dc1e7c03e162397b355b6f1c895dfdf3790d98c10b920c55e91272b8eecada2a | MyPassword |
8f0e2f76e22b43e2855189877e7dc1e1e7d98c226c95db247cd1d547928334a9 | passw0rd |
27cc6994fc1c01ce6659c6bddca9b69c4c6a9418065e612c69d110b3f7b11f8a | hello123 |
黑客就可以从在线哈希数据库中搜索这个哈希值,从而得到密码 passw0rd。
在密码中加入 Salt 可以解决这个问题。Salt 是一串随机的字符,在哈希运算之前被附加到密码中。这使得即使密码相同,加入 Salt 后它们的哈希值也会不一样。Salt 与密码的哈希值一起存储在数据库中,当用户登录时,将 Salt 拼接到他们的密码中,然后将生成的哈希值与存储在数据库中的哈希值进行比较。如果哈希值相同,用户就被允许访问。
在执行哈希函数之前,在密码中插入一串随机的字符串,这个随机字符串就是 Salt。
例如,Salt 为 az34ty1,sha256(passw0rdaz34ty1) 为 :6be5b74fa9a7bd0c496867919f3bb93406e21b0f7e1dab64c038769ef578419d
这个哈希值很难在哈希数据库中匹配,因为要想匹配该值,哈希数据库需要为密码 passw0rd 添加海量的条目。
基于密码的认证方法在 MQTT 中的最佳实践
通过上文的介绍,我们将 MQTT 中基于密码的认证方法最佳实践总结如下:
- 在 MQTT 中进行基于密码的认证,最重要的一点是要选择复杂和独特的密码。容易被破解或在多个账户中重复使用的密码会危害整个 MQTT 系统的安全。
- 安全地存储和传输密码以防止它们被恶意窃取也非常重要。例如,密码应在存储前进行 Hash 和 Salt 加密,并通过 TLS 等安全通道进行传输。
- 此外,为了减少密码的暴露,不要在代码或配置文件中硬编码密码,而是应该使用环境变量或其他安全存储机制。
结语
总而言之,基于密码的认证在保护 MQTT 连接和物联网系统的完整性方面起着关键作用。通过遵循密码选择、存储和传输的最佳实践,同时注意暴力攻击等常见问题,物联网开发者可以有效实现 MQTT 系统的安全保障。作为一个广泛使用的可扩展、高可用的 MQTT Broker,EMQX 也提供了包括基于密码认证在内的一系列安全措施,以保证用户的物联网系统的安全。
基于密码认证只是 MQTT 众多认证方式中的一种,且并不一定适合每个使用场景。数字证书或 OAuth 2.0 等更高级的方法可能会在某些情况下提供更强的安全性。物联网开发者需要了解和掌握各类常用的认证方式并选择最适合的一种或多种。
在本系列的下一篇文章中,我们将介绍另一种认证方式:增强认证。敬请关注。