从客户端浏览器通过SSH连接到服务器,而无需中间人服务器

时间:2020-10-13 20:49:33

标签: ssh browser sftp client-side webassembly

没有具体的代码可看-只是希望讨论我面临的问题,列出我知道的选项,并查看是否缺少任何选项。请让我知道这是否不合适,我将删除问题。

问题

我正在开发一个基于Web的应用程序,该应用程序具有一种在用户拥有的服务器上运行命令的方法,最好是通过SSH。我需要实现一种解决方案,以最安全,最方便的方式(对于用户)从浏览器执行SSH命令。我正在详细说明我想出的一些解决方案,这些解决方案并不能完全消除芥末酱,希望大家都有一些我没想到的想法或我可能不知道的工具。

我当前的解决方案

当前,我有一个有效的API,可将HTTPS帖子转换为SSH命令(主要是SFTP)。应用程序将给定用户名和密码或上载的私钥,将应用程序服务器上的SSH实例连接到用户拥有的服务器。然后,服务器维护SSH客户端,必要时使用用户提供的凭据重新连接。该应用程序不存储用户名,密码或私钥,并且客户端和应用程序服务器之间的信息通过HTTPS进行;但是,身份验证信息IS保存在Redis内存会话实例中。由于该信息必须通过我的中间人应用程序服务器传播,从而引起对客户端服务器安全性的潜在担忧,因此,我想找到另一种解决方案。

我理想的解决方案

理想情况下,我将使用Go之类的语言编写SSH客户端,将其转换为WebAssembly,然后可以在浏览器中下载并运行它。没有对我的应用服务器的呼叫-所有SSH流量(包括身份验证)都直接从客户端传递到其服务器。 WebAssembly将由浏览器缓存(尽管重量很轻),防止了下载量过大,同时仍然允许我根据需要进行更新。但是,这不起作用,因为浏览器是沙盒式的,并且无法与远程服务器建立连接。我已经研究过Browsix之类的解决方案,以便在浏览器中运行轻型Unix系统,而该系统又可以运行SSH应用程序,但它似乎仅限于直接运行WebAssembly。 (Browsix似乎也没有得到维护?)

我想出了两种潜在的替代解决方案,它们都有一些缺点,使我无法致力于这些解决方案:

解决方案1 ​​

移动SSH客户端客户端。我的理想解决方案是这种形式,但是要解决浏览器的限制,我需要客户端下载一个小型SSH客户端,该客户端可以从客户端Web应用程序调用。实际上,如果我支持不运行Chromium的浏览器,并且如果避免为每个选择支持的浏览器维护浏览器扩展,那意味着我无法在浏览器和本机应用程序之间建立接口。为了解决这个问题,我想我可以将SSH客户端包装在要在特定端口(例如:9090)上运行的Web服务器中。然后,该Web应用程序可以调用localhost:9090 / listDirectories,这会将请求主体集中到SSH客户端,该客户端将在客户端拥有的服务器上执行相关调用。唯一的缺点是,它将要求用户下载并运行安装程序,并且程序必须不断运行并在客户端计算机的端口上侦听。这并不是我想要的那样无缝的用户体验,并且很容易出现错误,例如程序终止或在机器启动时无法正常启动。我还必须维护多个主要操作系统的安装程序。

解决方案2

放弃SSH。创建一个小型Web服务器(可能在Go中)以侦听客户端拥有的服务器上的端口。然后,客户端Web应用程序可以直接通过HTTPS加密对客户端服务器的API调用,并且在客户端服务器上侦听的Web服务器将处理请求。缺点:我需要创建一个用户管理系统(而不是依赖于客户端拥有的服务器的身份验证系统),并采用某种方式来确定客户端拥有的服务器实际上是客户端拥有的。

大家可能提出的问题

您可能会问:“为什么不制作本地应用程序?如果您愿意制作Web应用程序,则可以使用Electron之类的东西!”是的,但是我真的更希望该应用程序位于浏览器中,以便进行更新和易于访问。我知道,这听起来像是我很难受。

请让我知道我是否可以提供更多详细信息,或者您是否有任何潜在的潜在客户。

1 个答案:

答案 0 :(得分:0)

好的-我假设这个问题非常针对我的用例,因此这里对答案的需求可能不大,但是如果有人沿着相同的道路前进...

我要做的是在Go中创建一个简单的HTTP服务器,客户端可以将其安装在自己的服务器上,然后我的Web应用程序可以与其通信。一切都比我想象的要简单。无法使用SSH,因此我创建了一个简单的身份验证系统,然后来自Web应用程序的HTTP请求提示了客户端服务器上的所有操作。

这里的一个陷阱是您将违反CORS政策。幸运的是,您可以完全控制服务器应用程序,因此跨域请求是可管理的。您需要阅读如何在服务器上允许跨源请求(请参阅the excellent MDN reference),并特别注意所有可能的Access-Control- *标头。

还请注意(这让我困扰了很长时间),CORS请求是成对出现的-一个使用OPTIONS方法(作为浏览器飞行前检查的一部分),另一个使用您指定的任何方法(GET) ,POST等)。 OPTIONS方法是最先发送的,而且很挑剔。阅读OPTIONS和浏览器的飞行前again at MDN,以及在其他任何地方可以找到所需信息的信息。

身份验证是OPTIONS的障碍,因为200以外的状态代码可能会导致飞行前失败并暂停您的请求;但是全面批准OPTIONS请求可能会导致OPTIONS和您的方法之间的内容大小不匹配,从而导致请求也失败。为了克服该障碍,我让我的初始身份验证始终返回状态200,然后在返回正文中设置“已身份验证”或“未身份验证”,以便我的客户端应用程序知道请求是否成功。我还在服务器端设置了一个会话变量,这样用户就无需继续发送身份验证信息,因此我可以正常使用HTTP状态响应。

这是一个很大的概述。如果有人有特定问题,请随时提问-我不是CORS专家,但我可以为您指明正确的方向!