Node.js:使用唯一的 public 密钥验证客户端(类似于 Github SSH 密钥验证)
Node.js: Authenticate client using unique public key (Similar to Github SSH key authentication)
我有一个中央网络服务器 (Node.js),还有几台客户端计算机(还有 运行 节点)。这些客户端将把数据推送到网络服务器中,因此,为了安全起见,客户端最初将在主服务器上注册——生成它自己唯一的 SSL private/public 密钥并将 public 密钥存储在服务器。
现在,注册后,每次客户端尝试与服务器通信时,它都需要出示它的 Public 密钥 (?) 来验证自己。
我正在尝试了解如何解决这个问题。我应该将客户端所有 public 键的内容存储在常规数据库集合中吗?
我如何让客户 "present" 他们的证书连同他们的数据?我见过一些像 client-certificate-auth 这样的包,但我认为这对我的用例没有帮助。
编辑:我忘了说,我将通过 HTTPS(端口 443)进行通信,所以我认为这会处理实际的安全部分。我只是想确保没有流氓、未注册的客户端使用 pub/private 加密/SSL 证书将数据推送到服务器。
我强烈建议您不要自己这样做,如果您没有正确实施,可能会出错很多事情。
也就是说,这种事情在架构上的工作方式是 不是 到 "present the client's public key" 而是让客户端用它的私钥加密一些东西并发送加密的数据到服务器,然后用客户端的 public 密钥解密。如果它能够做到这一点,它就知道客户端就是它声称的客户端(理论上;其可靠性可能因您的密钥空间而异)。
客户端加密什么?好吧,这在很大程度上取决于(再次)你想要多安全/多疑。执行此操作的一种方法(准 kerberos)是客户端向服务器发送请求以加密信息。这是通过 SSL 完成的,因此客户端可以确保服务器是它所说的(如果需要,可以检查 CA 等)。传回的是一些数据,包括随机值、到期时间,可能还有某种随机数。它也由服务器存储以供以后查找验证,当然会按时驱逐。客户端通常会获取那个确切的对象(可能是 JSON 对象)并使用其私钥对其进行加密,然后将其发送回服务器的某个登录端点。正如我之前所说,服务器随后会根据客户端的 ID 检查该对象的存储位置,并进行比较以查看这两个对象是否相同。如果是,那么它可以接受客户就是它所说的那个人。
通常,此握手仅用于交换客户端可用于加密其所有流量的会话密钥,因为对称密钥加密在 CPU 上通常比 PKI 更容易。
不过老实说,我只了解了皮毛。您可能最好查看 PassportJS 必须提供的策略并选择其中之一。也许 passport-api-key
或 passport-client-cert
会满足您的需要。
如果您要走这条路,请使用 Subtle Crypto API。您很可能不应该这样做。
您希望在 javascript 中生成的私钥在客户端保密,并且 public 密钥安全地发送并存储在服务器上。
在身份验证期间,客户端 表明它是什么 public 密钥 是通过一些与其关联的唯一标识符 public 键,例如id 或常用名或用户名。
服务器然后使用客户端的 public 密钥.
加密的消息负载发出质询
用户使用他的私钥解密消息,然后用正确的解密响应进行响应。
这不提供安全性,您必须在已经建立的 SSL 连接上执行此操作。
它是传统 cookie 和会话令牌的替代品,只是不同,更难,而不是更好。
私钥 永远不会到达服务器。客户端不使用它的私钥加密,这不是 public-key 加密的工作方式。
但是它可以发送数字签名,服务器可以验证。这是唯一标识符的替代方法;确保你指定了一个真实且足够长的随机数来签名。
为了执行数字签名挑战,服务器向客户端发送一个挑战字符串,客户端使用它的私钥签署挑战并响应服务器,然后服务器使用 public 密钥 验证签名。 public 密钥 必须是签名的一部分,服务器必须知道信任 public 密钥 , 所以它必须有一种快速查找的方法。
另一种选择是依靠用户的知识来设置他们自己的客户端证书,在这种情况下,Paul 的回答中提到的 passport-client-cert
可以解决这个问题。
我有一个中央网络服务器 (Node.js),还有几台客户端计算机(还有 运行 节点)。这些客户端将把数据推送到网络服务器中,因此,为了安全起见,客户端最初将在主服务器上注册——生成它自己唯一的 SSL private/public 密钥并将 public 密钥存储在服务器。
现在,注册后,每次客户端尝试与服务器通信时,它都需要出示它的 Public 密钥 (?) 来验证自己。
我正在尝试了解如何解决这个问题。我应该将客户端所有 public 键的内容存储在常规数据库集合中吗?
我如何让客户 "present" 他们的证书连同他们的数据?我见过一些像 client-certificate-auth 这样的包,但我认为这对我的用例没有帮助。
编辑:我忘了说,我将通过 HTTPS(端口 443)进行通信,所以我认为这会处理实际的安全部分。我只是想确保没有流氓、未注册的客户端使用 pub/private 加密/SSL 证书将数据推送到服务器。
我强烈建议您不要自己这样做,如果您没有正确实施,可能会出错很多事情。
也就是说,这种事情在架构上的工作方式是 不是 到 "present the client's public key" 而是让客户端用它的私钥加密一些东西并发送加密的数据到服务器,然后用客户端的 public 密钥解密。如果它能够做到这一点,它就知道客户端就是它声称的客户端(理论上;其可靠性可能因您的密钥空间而异)。
客户端加密什么?好吧,这在很大程度上取决于(再次)你想要多安全/多疑。执行此操作的一种方法(准 kerberos)是客户端向服务器发送请求以加密信息。这是通过 SSL 完成的,因此客户端可以确保服务器是它所说的(如果需要,可以检查 CA 等)。传回的是一些数据,包括随机值、到期时间,可能还有某种随机数。它也由服务器存储以供以后查找验证,当然会按时驱逐。客户端通常会获取那个确切的对象(可能是 JSON 对象)并使用其私钥对其进行加密,然后将其发送回服务器的某个登录端点。正如我之前所说,服务器随后会根据客户端的 ID 检查该对象的存储位置,并进行比较以查看这两个对象是否相同。如果是,那么它可以接受客户就是它所说的那个人。
通常,此握手仅用于交换客户端可用于加密其所有流量的会话密钥,因为对称密钥加密在 CPU 上通常比 PKI 更容易。
不过老实说,我只了解了皮毛。您可能最好查看 PassportJS 必须提供的策略并选择其中之一。也许 passport-api-key
或 passport-client-cert
会满足您的需要。
如果您要走这条路,请使用 Subtle Crypto API。您很可能不应该这样做。
您希望在 javascript 中生成的私钥在客户端保密,并且 public 密钥安全地发送并存储在服务器上。
在身份验证期间,客户端 表明它是什么 public 密钥 是通过一些与其关联的唯一标识符 public 键,例如id 或常用名或用户名。
服务器然后使用客户端的 public 密钥.
加密的消息负载发出质询用户使用他的私钥解密消息,然后用正确的解密响应进行响应。
这不提供安全性,您必须在已经建立的 SSL 连接上执行此操作。
它是传统 cookie 和会话令牌的替代品,只是不同,更难,而不是更好。
私钥 永远不会到达服务器。客户端不使用它的私钥加密,这不是 public-key 加密的工作方式。
但是它可以发送数字签名,服务器可以验证。这是唯一标识符的替代方法;确保你指定了一个真实且足够长的随机数来签名。
为了执行数字签名挑战,服务器向客户端发送一个挑战字符串,客户端使用它的私钥签署挑战并响应服务器,然后服务器使用 public 密钥 验证签名。 public 密钥 必须是签名的一部分,服务器必须知道信任 public 密钥 , 所以它必须有一种快速查找的方法。
另一种选择是依靠用户的知识来设置他们自己的客户端证书,在这种情况下,Paul 的回答中提到的 passport-client-cert
可以解决这个问题。