1

我正在用微型嵌入式 Linux 盒子创建小型中继站。它们连接了一些传感器,并通过 HTTP POST 将数据传输回服务器。现在服务器只接受他们的消息,以及一个唯一的 ID(eth0 的 MAC 地址)。

我想扩展它以包括某种类型的安全性。我希望能够以最少的配置部署这些小设备。我想将基本固件复制到设备上,在现场将它们连接起来,然后它们会自行注册。他们第一次连接时,我希望服务器和设备进行某种类型的协商,我可以在其中存储指纹。随后的请求我可以使用该指纹验证/验证设备。

这样,一旦设备使用其唯一 ID 进行注册,我就可以确保来自该 ID 的所有数据都来自同一设备。如果一个 rouge 设备或一组设备确实注册了,我将删除它们(我将 IP 存储到,以便我可以按未知范围删除并阻止它们)。

我的问题是这样做的最佳方法是什么?我回想起 SSH 指纹的想法,第一次连接到服务器时,您会获得服务器指纹。如果将来的请求产生了不同的指纹,您会收到一个巨大的警告,并且如果服务器的密钥实际上已经重新生成(例如,您在没有保存旧的 SSH 密钥的情况下进行了重新安装),则必须手动从您的 authorized_keys 文件中删除指纹。

像这样的东西是否可能与 HTTP 一起使用,可能避免使用预共享密钥?

如果重要的话,客户端正在运行 Python2,而它们连接的服务器主要是在 Tomcat 上用 Scala 编写的。

4

1 回答 1

1

基本上,您需要做的就是告诉服务器公钥,然后用它签署所有消息。如果您不想要预共享密钥,则服务器无法保证新注册的人实际上是您的设备之一。但是,您仍然可以验证消息是否来自最初使用该标识符注册的同一设备。

这个过程基本上是这样的:

  1. 客户端生成一个新的密钥对(例如,一个 RSA 公钥/私钥对)。
  2. 客户端向服务器注册,发送其公钥。服务器存储此公钥。
  3. 当客户端发送消息时,它会生成其消息的签名,并将其附加到消息中。当服务器收到消息时,它会验证签名以确保消息是由持有相应私钥的人发送的。

PyCrypto 中的代码如下所示:

生成密钥对

from Crypto.PublicKey import RSA
key = RSA.generate(2048)
private_key = key.exportKey()
public_key = key.publickey().exportKey()
# private_key is a string suitable for storing on disk for retrieval later
# public_key is a string suitable for sending to the server
# The server should store this along with the client ID for verification

生成签名

from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
key = RSA.importKey(private_key)
# where private_key is read from wherever you stored it previously
digest = SHA.new(message).digest()
signature = key.sign(digest, None)
# attach signature to the message however you wish

服务器应该加载之前存储的公钥,并使用您使用的 Scala/Java 加密 API 提供的“验证”方法,并且只有在成功时才接受消息。

了解每种方法的注意事项很重要,因为各种技术只能防止某些类型的攻击。例如,上述方法不能防止“重放攻击”,即攻击者记录具有特定含义的消息,然后稍后将其重新传输到服务器。防止这种情况的一种方法是在经过哈希处理的消息中包含时间戳;另一种方法是使用适当的加密传输(例如 SSL/TLS)。

于 2011-07-27T22:48:57.310 回答