代理程序转发和 keychain 改进
Daniel Robbins(drobbins@gentoo.org)
总裁兼首席执行官,Gentoo Technologies, Inc.
2002 年 2 月
在这一系列的第三篇文章中,Daniel Robbins 向您显示了如何利用 OpenSSH 代理程序连接转发来增强安全性。他还分享 keychain shell 脚本的近期改进。
我们中的许多人都使用非常优秀的 OpenSSH 作为古老的 telnet 和 rsh 命令的替代品,OpenSSH 不仅安全而且是加密的。OpenSSH 更吸引人的特性之一是它能够使用以一对互补的数字式“密钥”为基础的 RSA 和 DSA 认证协议来认证用户。RSA 和 DSA 认证承诺不必提供密码就能够与远程系统建立连接,这是其主要魅力之一。有关更多背景资料,请参阅关于 OpenSSH 密钥管理的本系列文章中以前的几篇,分别包括 RSA/DSA 认证(第 1 部分)和 ssh-agent 和 keychain(第 2 部分)。
由于第 2 部分发表在 2001 年 9 月的 developerWorks 上,并且稍后在 Slashdot 和 Freshmeat(请参阅本文后面的参考资料,获取到这些站点的链接)上引用了此文,因此,许多人已经开始使用 keychain,而且它已经做了许多更改。我收到了世界各地开发人员编写的约 20 个高质量的补丁程序。我已将其中许多补丁代码合并入 keychain 源码中,它目前的版本是 1.8(请参阅参考资料)。我真诚地感谢所有提交补丁程序、错误报告、功能请求及感谢信的那些人。
加强 ssh 安全性
在上篇文章中,我花了一些时间来讨论运行 ssh-agent 在安全性方面的利弊。第二篇文章发表在 developerWorks 的几天后,我收到来自 Sarnoff Corporation 的 Charles Karney 的一封电子邮件,他非常礼貌地通知了我 OpenSSH 新的认证代理程序转发的能力,我们将会简要地讨论这一能力。另外,Charles 强调:在不可信机器上运行 ssh-agent 是十分危险的:如果有人成功地获取系统上的 root 访问权,那么就能从 ssh-agent 中抽取您解密的密钥。即使抽取密钥有一定的困难,但是它还是在专业的解密高手的能力范围之内。而且,基本事实就是偷窃私钥是可能的,这意味着我们应首先采取措施来防止这种情况的发生。
为了简单描述保护私钥的策略,首先必须把我们访问的机器归为两种类型中的一类。如果特定主机是安全性良好或是孤立的 — 要成功获取主机的 root 访问权几乎不可能 — 那么,那台机器应被认为是可信主机。不过,如果许多其他人使用这台机器或者您怀疑系统的安全性,那么这台机器应被认为是不可信主机。为防止您的私钥被他人抽取,绝对不应在不可信主机上运行 ssh-agent(和由此启动的 keychain)。 那样的话,即使系统安全性受到威胁,由于 ssh-agent 没有运行,闯入者在第一时间内也不能抽取密钥。
但是,这产生了一个问题。如果不能在不可信主机上运行 ssh-agent,那么如何从这些系统上建立安全的、无密码的 ssh 连接呢?答案是:只在可信主机上使用 ssh-agent 和 keychain,并利用 OpenSSH 新的认证转发能力将无密码的认证扩展到任何不可信主机上。简略地说,就是通过允许远程 ssh 会话来联系运行在可信系统上的 ssh-agent,使认证转发工作。
认证代理程序转发
要了解认证转发工作的原理,让我们首先看一下一个假设情况,其中用户 drobbins 有一个称为 lappy 的可信的便携式电脑、一个称为 trustbox 的可信服务器和另外两个他必须访问的不可信系统,分别称为 notrust1 和 notrust2。当前,他在所有这四台机器上都使用 ssh-agent 以及 keychain,如下所示:
图 1. 运行在可信和不可信机器上的 ssh-agent

这种方法所带来的问题是如果有人获取 notrust1 或 notrust2 的 root 访问权,那么这个人当然可以从现在易受攻击的 ssh-agent 进程中抽取密钥。为了解决这个问题,drobbins 停止运行不可信主机 notrust1 和 notrust2 上的 ssh-agent 和 keychain。事实上,为了更为小心,drobbins 决定只在 lappy 上使用 ssh-agent 和 keychain。这样限制了他解密的私钥的泄露,同时防止他的私钥被偷窃:
图 2. ssh-agent 只运行在 lappy 上;一个更安全的配置

当然,这种方法带来的问题是 drobbins 现在只能从 lappy 建立无密码的连接。让我们看一下如何启用认证转发并解决这个问题。
假设所有机器都运行 OpenSSH 的最近版本,通过使用认证转发,我们能解决这个问题。认证转发允许远程 ssh 进程联系您正在本地可信机器上运行的 ssh-agent — 而不要求在您正运行 ssh 的同一台机器上运行 ssh-agent 的一个版本。这通常允许您在单个机器上运行 ssh-agent(和 keychain),并且这意味着源于这台机器的所有 ssh 连接(直接或间接)都将使用本地 ssh-agent。
为了启用认证转发,我们在 lappy 和 trustbox 的 /etc/ssh/ssh_config 中添加了下面行。请注意:这是 ssh 的配置文件(ssh_config),而不是 ssh 守护进程 sshd 的配置文件(sshd_config):
清单 1. 将这行添加到 /etc/ssh/ssh_config 中
ForwardAgent Yes
现在,为了利用认证转发,drobbins 可以从 lappy 连接到 trustbox,然后在不提供任何连接的密码的情况下,从 trustbox 连接到 notrust1。这两个 ssh 进程都“进入”运行在 lappy 上的 ssh-agent:
清单 2. 进入 lappy
$ ssh drobbins@trustbox
Last login: Wed Sep 26 13:42:08 2001 from lappy
Welcome to trustbox!
$ ssh drobbins@notrust1
Last login: Tue Sep 25 12:03:40 2001 from trustbox
Welcome to notrust1!
$
如果您尝试使用类似的配置,并发现代理程序转发不起作用,请尝试使用 ssh -A 替代原来单纯的 ssh 来明确启用认证转发。这里是当我们使用上面提到的认证转发而登录到 trustbox 和 notrust1 时,实现此操作的内部运行图:
图 3. 正在运作的代理程序转发

正如您看到的,当 ssh 连接到 trustbox 时,它维持与运行在 lappy 上的 ssh-agent 的连接。当产生从 trustbox 到 notrust1 的 ssh 连接时,这个新的 ssh 进程维持与以前 ssh 的认证连接,这样有效地延伸了链。这个认证链是否能延伸到 notrust1 以外的其它主机取决于 notrust1 的 /etc/ssh/ssh_config 是如何配置的。 只要启用了代理程序转发,通过使用在可信 lappy 上运行的 ssh-agent,这个链上的所有部分都能认证。
代理程序连接转发的优点
认证转发提供了许多在此没有提到的安全性优点。为了让我相信代理程序连接转发的重要性,Charles Karney 与我分享了以下三个安全性优点:
1. 私钥只存储在可信机器上。这样防止怀有恶意的用户从磁盘获取加密的密钥并防止他们试图解加密。
2. ssh-agent 只运行在可信机器上。这样防止闯入者进行远程 ssh-agent 进程的内存转储并从转储中抽取出您的解密私钥。