【问题标题】:How can I set up authenticated links between processes in Elixir?如何在 Elixir 中的进程之间建立经过身份验证的链接?
【发布时间】:2021-03-20 21:43:31
【问题描述】:

背景:

我正在尝试在 Elixir 中编写一个程序,通过在一组进程上运行分布式算法并记录某些统计数据来测试分布式算法。首先,我将在同一台机器上运行这些进程,但最终目的是让它们在不同的机器/VM 上运行。

问题:

我希望实现的算法要求之一是消息包括身份验证。也就是说,每当一个进程向另一个进程发送消息时,接收者应该能够验证该消息确实来自发送者,并且不是由另一个进程伪造的。下面的 sn-ps 应该有助于说明这个想法:

# Sender
a = authenticate(self, receiver, msg)
send(receiver, {msg, self, a})
# Receiver
if verify(msg, sender, a) do
  deliver(msg)
end

到目前为止的想法:

我已经广泛搜索了 Elixir 进程之间经过身份验证的通信的任何文档,但没有找到任何东西。也许在某种程度上,这已经在幕后为我完成了,但到目前为止我还无法验证这一点。如果是这样,我想知道当进程不在同一台机器上运行时它是否仍然正确。

我已经研究过使用 SSL/TLS 函数 provided by Erlang 的可能性,但由于我在这方面的知识有限,我不确定这将如何适用于我运行一组进程的情况,而不是在客户端-服务器系统和 HTTPS 中更标准的使用。如果我走这条路,我相信我必须事先自己设置所有密钥和签名,我相信这可以使用X509 Elixir package,尽管我不确定这是否合适并且可能比是必须的。

总结:

  1. 是否有标准/预先存在的方式来实现 Elixir 中进程之间的经过身份验证的通信?
  2. 如果是,它是否适合在不同机器/VM 之间进行通信的进程?
  3. 如果以上任何一项都不是,我自己可以实现这一目标的最简单方法是什么?

【问题讨论】:

  • 你为什么不首先信任来自同一个 ErlangVM/集群运行的其他 erlang 进程的消息?
  • @AlekseiMatiushkin 的观点是正确的,我认为。一旦你将 ErlangVM 连接到集群中,它们就可以相互访问。特别是可以在一个上执行任意代码。我想说你应该确保虚拟机本身之间的连接是安全的(例如通过加密通道),而不是试图在进程之间的消息级别上强制执行。
  • 感谢您的回复。 @PawełObrok Aleksei 问题的答案是,我可能会故意设置一些行为不端的流程。这是我想做的测试的一部分。我知道这有点奇怪。在我的情况下,执行任意代码的可能性实际上不会成为问题 - 我只需要确保消息经过身份验证。您是否建议可以通过连接虚拟机的方式简单地实现身份验证?如果是这样,我可能不得不调查一下。
  • 在我的测试中可能会设置一些恶意行为的进程 假定的身份验证如何帮助避免恶意进程?通常这将由您放置在系统前面的任何代理/负载均衡器处理,即内部是受信任的,外部不是,并且客户端通常进行身份验证,例如使用证书。这对算法没有影响,因为在任何现实世界的场景中,它都是在边界处处理的,可能使用专用的硬件/网络应用程序。因此,无论您尝试建模什么都是幻想,永远没有人会那样运行它。
  • @UnslanderMonica 正如我在问题中所展示的那样,如果一个进程确实发送了一条具有不同名称的消息,则验证步骤将失败并且不会被接受。我知道这不是标准的,我从未声称它是标准的。但是,我希望测试的算法的正确性完全依赖于此。在我的情况下,说“这对算法没有影响”根本不正确。我没有对外部的负载平衡器或客户端做任何事情。我觉得你可能误解了我的情况,坦率地说这是一种幻想是没有帮助的。

标签: authentication ssl erlang elixir distributed-system


【解决方案1】:

我越了解你想要达到的目标,我就越确信你所需要的只是调用过程的footprint

对于同步调用GenServer.handle_call/3,您已经拥有第二个参数作为足迹。

对于异步消息,您可以将调用者信息添加到消息本身。比如,不要发送简单的:foo 消息,而是发送{:foo, pid()} 或更复杂的{:foo, {pid(), timestamp(), ip(), ...} 并让被调用者验证这些消息。

这绝对是安全的: 集群将确保这些消息来自受信任的来源,您的内部验证可能会确保来源在您的内部规则范围内有效。 p>

【讨论】:

  • 再次感谢您。我将处理异步消息,并且我确实打算向它们添加调用者信息。我的问题更多是关于如何进行您提到的验证。因此,如果我收到一条消息{:foo, pid},我不确定如何验证这不是来自另一个进程,该进程只是在消息中包含了另一个进程的 pid。我知道我可以避免这种情况发生,但我想实际上完全阻止它。对不起,如果我误解了。
  • 好吧,在受信任的erlang 集群内,我们无法保护自己。如果您的一个进程想要伪造另一个进程,则实际上没有办法阻止它。甚至通过 10 因素身份验证的 SSL。
【解决方案2】:

正如 Aleksei 和 Paweł 所指出的,如果您的集群中有某些东西,那么它已经是可信的。这与验证可能源自几乎任何地方的随机 Web 请求不同,您谈论的是源自受信任机器的本地网络的消息。如果某个不法分子正在您的一台服务器上运行,那么您需要担心的问题远不止验证消息。

在集群内运行的 Elixir/Erlang 进程在安全性方面几乎没有限制:例如,它们的状态可以被任何其他进程检查。为了让容错系统能够进行热代码重新加载,这种透明度的一部分是设计使然,并且是必要的,但关于具体的方式和原因的对话过于细微,我无法做到公正。

如果您确实需要进行一些日志记录来获得可审计的“书面记录”来验证哪个进程发送了哪个消息,我认为您必须推出自己的解决方案,该解决方案可能依赖于许多常用技术(例如密钥 + 签名、区块链等)。但请记住:无论如何,如果您要处理不同服务器之间的 Web 请求,就会出现这些问题!并且有已经协议用于在计算机之间建立安全连接,因此我不建议在您的应用程序中重新发明这些网络协议。

您最好将时间花在算法本身上,而不是试图在安全方面重新发明轮子。您的应用程序应该专注于其他人正在做的独特事情(在您的案例中是算法)。如果您有多个互连的虚拟机相互传递消息,那么所有“安全”要求都伴随着定义对每台机器/子网的正确访问,并且无论您在它们上运行什么应用程序/语言,该要求都适用。

【讨论】:

  • 非常感谢您的详细回答。作为测试的一部分,我可能会设置一些本应表现恶劣的流程,但我想我可以限制他们这样做的方式。不幸的是,我想确保准确表示算法及其性能,而忽略它会让我怀疑我的结果是否真的是现实的。我当然不想重新发明任何协议。
猜你喜欢
  • 2017-02-21
  • 2020-08-25
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 2010-09-09
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
相关资源
最近更新 更多