![Perl 服务器中基于 SSH 密钥的身份验证](https://linux22.com/image/576812/Perl%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%AD%E5%9F%BA%E4%BA%8E%20SSH%20%E5%AF%86%E9%92%A5%E7%9A%84%E8%BA%AB%E4%BB%BD%E9%AA%8C%E8%AF%81.png)
我有一个用 Perl 编写的服务器,客户端连接到该服务器以执行一些管理任务。不谈细节,我想实现两件事:
- 加密服务器和客户端之间的连接通道——可以使用 IO::Socket::SSL 来完成。
- 使用 SSH 密钥对客户端进行身份验证 - 我还不知道如何做到这一点。
最好的解决方案是将这两个要求合并为一个,并拥有一个与 SSH 连接/身份验证完全相同的机制。这可能吗?
谢谢。
答案1
您想使用 SSH 隧道。这将加密您的通信并使用 SSH 密钥进行身份验证。
如果您希望客户端用 perl 编写,那么请使用类似 Net::SSH::Perl 模块:http://search.cpan.org/~turnstep/Net-SSH-Perl-1.34/lib/Net/SSH/Perl.pm
如果不了解有关您的设置的更多信息,我真的无法帮助您完全实现 SSH 隧道。
答案2
SSH 使用密钥,而 SSL 倾向于使用 X.509 证书(顺便说一下,SSH 不是基于 SSL)。
(公钥) 证书不仅仅是一个公钥:它是公钥、标识符(例如主题 DN)和其他属性之间的关联,整个过程都经过签名(由 X.509 证书的颁发者签名)。
例如,当使用 RSA 时,可以提取公钥材料(模数和公钥指数)并将其转换为证书。此模型缺少的是 SSH 密钥,它们不是像 X.509 证书那样“签名”或“颁发”的。您将在模型中缺少 SSL 中经常使用的 PKI 方面。解决这个问题的一个简单方法是用它制作一个自签名证书。然后,您必须在客户端中明确导入它以使其受信任,或者在第一次连接到它时导入它(毕竟,这与第一次连接到 SSH 服务器时发生的情况非常相似)。
SSH 和 X.509 的 RSA 密钥格式不同,因此您需要编写一些代码来从 SSH 密钥中读取模数和指数,并以 SSL 堆栈可用的格式生成 X.509 证书和私钥。
这StackOverflow 上的问题应该是有趣的(尽管它是反过来的)。
答案3
除了简单地通过 SSH 隧道建立连接之外,Chris Ting 指出:
您可以实现 SSH 子系统,这样您的程序就可以与 SSH 无缝集成。对于用户来说,您的程序看起来只是使用 SSH 密钥和加密(由于实际使用 SSH,因此实际上确实如此)。尽管 OpenSSH SFTP 客户端和服务器在某种程度上是自文档化的,但该过程并没有得到很好的文档记录。
这需要进行大量重写,具体取决于客户端的连接方式和协议的语法。但明显的好处是,它可以无缝地融入用户的 SSH 配置中。
答案4
我之前写过类似的服务器/客户端应用程序。基本设计:
- 服务器不进行网络操作,它是通过 stdin/stdout 流进行通信的简单脚本(类似于 inetd 执行的守护进程);
- 所有网络和身份验证工作均由 ssh/sshd 完成,客户端使用基于密钥授权的 ssh,服务器有一个带有 command="" 选项的 authorized_keys 文件 - 该密钥始终执行我的服务器,不能用于访问 shell 或其他程序;
示例.ssh/authorized_keys
文件:
no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding,from="10.0.0.1",command="/usr/local/bin/fsdumps-receiver" ssh-rsa AAAA.... key_comment
注意 from="<ip>" 选项 - 本例中的访问仅限于一个 IP。
服务器代码可以访问一些有用的环境变量。例如:
- $ENV{'SSH_ORIGINAL_COMMAND'} - “命令”(不是真的)传递为
ssh server_ip that_command
- $ENV{'SSH_CLIENT'} - 客户端 IP
您可以使用 SSH_ORIGINAL_COMMAND 在服务器中选择管理任务。客户端代码可以使用此任务名称作为参数生成 ssh(或使用 Net::SSH::Perl),然后向服务器发送数据或从服务器接收数据。