openssh 密钥上传_OpenSSH密钥管理,第3部分

openssh 密钥上传

我们许多人都使用出色的OpenSSH作为古老的telnetrsh命令的安全加密替代品。 OpenSSH的更吸引人的功能之一是能够使用RSA和DSA身份验证协议对用户进行身份验证,该协议基于一对互补的数字“密钥”。 RSA和DSA身份验证的主要吸引力之一是可以在不提供密码的情况下建立与远程系统的连接。 有关更多背景信息,请参阅本系列有关OpenSSH密钥管理的前几期,分别介绍RSA / DSA身份验证 (第1部分)以及ssh-agent和密钥链 (第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-agentkeychain ,并使用OpenSSH的新身份验证转发功能将无密码身份验证扩展到任何不受信任的主机。 简而言之,身份验证转发通过允许远程ssh会话联系在受信任系统上运行的ssh-agent工作。

身份验证代理转发

为了了解身份验证转发的工作原理,我们首先来看一个假设情况,即用户drobbins拥有一个称为lappy的受信任的笔记本电脑,一个名为trustbox的受信任服务器以及他必须访问的其他两个不受信任的系统,即notrust1notrust2 ,分别。 目前,他在所有四台机器上都使用ssh-agentkeychain ,如下所示:

图1.在受信任和不受信任的机器上运行的ssh-agent
openssh 密钥上传_OpenSSH密钥管理,第3部分_第1张图片

这种方法的问题在于,如果某人获得了notrust1notrust2根访问权限,那么此人当然有可能从现在容易受到攻击的ssh-agent进程中提取密钥。 为了解决这个问题, drobbins停止在不受信任的主机notrust1notrust2上运行ssh-agentkeychain 实际上,要更加小心, drobbins决定只在lappy上使用ssh-agentkeychain 这限制了他解密后的私钥的暴露,从而保护他免遭私钥盗窃:

图2.仅在lappy上运行的ssh-agent; 更安全的配置
openssh 密钥上传_OpenSSH密钥管理,第3部分_第2张图片

当然,这种方法的问题在于, drobbins现在只能从lappy建立无密码连接。 让我们看看如何启用身份验证转发并解决此问题。

假设所有机器都运行OpenSSH的最新版本,我们可以通过使用身份验证转发来解决此问题。 身份验证转发使远程ssh进程可以与在本地受信任计算机上运行的ssh-agent联系-而不是要求ssh-agent版本在要从ssh退出的同一台计算机上运行。 通常,这使您可以在一台计算机上运行ssh-agent (和keychain ),并且意味着所有(直接或间接)源自此计算机的ssh连接都将使用本地ssh-agent

为了启用身份验证转发,我们trustbox添加到lappytrustbox的/ etc / ssh / ssh_config 。 请注意,这是ssh ( ssh_config )的配置文件,而不是ssh守护程序sshd ( sshd_config )的配置文件:

清单1.将此行添加到您的/ etc / ssh / ssh_config
ForwardAgent Yes

现在,为了利用认证转发, drobbins可以从连接lappytrustbox ,然后从trustboxnotrust1而无需任何连接提供密码短语。 这两个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来显式启用身份验证转发。 这是上面使用身份验证转发登录到trustboxnotrust1时幕后情况的trustbox

图3.实际的代理转发
openssh 密钥上传_OpenSSH密钥管理,第3部分_第3张图片

如您所见,当ssh连接到trustbox ,它保持与在lappy运行的ssh-agent的连接。 当从trustboxnotrust1建立ssh连接时,这个新的ssh进程将保持与先前ssh的身份验证连接,从而有效地扩展了链。 此身份验证链是否可以扩展到notrust1以外的其他主机,取决于notrust1的/ etc / ssh / ssh_config的配置方式。 只要启用了代理转发,链中的所有部分都将能够使用在受信任的lappy上运行的ssh-agent进行身份验证。

代理连接转发的优点

身份验证转发具有许多此处未涉及的安全优势。 为了使我相信代理连接转发的重要性,Charles Karney与我分享了这三个安全优势:

  1. 私钥仅存储在受信任的计算机上。 这样可以防止恶意用户从磁盘上获取您的加密密钥并尝试破解加密。
  2. ssh-agent仅在受信任的计算机上运行。 这样可以防止入侵者执行远程ssh-agent进程的内存转储,然后从转储中提取解密的私钥。
  3. 由于只需要在受信任的计算机上键入密码,就可以防止任何击键记录程序在输入密码时偷偷抓住您的密码。

依赖身份验证代理连接转发的一个缺点是它不能解决允许cron作业利用RSA / DSA身份验证的问题。 解决此问题的一种方法是设置所有需要RSA / DSA身份验证的cron作业,以便它们从LAN上的受信任计算机执行。 如有必要,这些cron作业可以使用ssh连接到远程系统以自动执行备份,同步文件等等。

现在,我们已经研究了身份验证代理连接转发,接下来我们来看看对keychain脚本本身所做的最新改进。

钥匙串功能改进

由于提交了用户补丁程序,因此对keychain源进行了许多重大改进。 用户提交的几个keychain补丁与功能相关。 例如,您会记得keychain创建了一个〜/ .ssh-agent文件。 该文件的名称现已更改为〜/ .ssh-agent- [hostname],以便keychain可以与可从多个不同物理主机访问的NFS安装的主目录配合使用。 除了〜/ .ssh-agent- [hostname]文件之外,现在还有一个〜/ .ssh-agent-csh- [hostname]文件,可以通过csh兼容的shell来获取。 最后,添加了新的--nocolor选项,以便在您碰巧使用不兼容vt100的终端时可以禁用着色功能。

Shell兼容性修复

虽然功能上的改进非常重要,但绝大多数修复程序都解决了Shell兼容性问题。 您会看到,虽然钥匙串1.0需要bash ,但后来的版本已更改为可与任何与sh兼容的shell一起使用。 这项更改使keychain几乎可以在任何UNIX系统上“开箱即用”,包括Linux,BSD,Solaris,IRIX和AIX以及其他UNIX平台。 sh和一般UNIX兼容性的过渡是一个坎bump的旅程,但它也已经是一个很棒的学习经验。 创建一个可以在所有这些平台上运行的脚本确实非常棘手,主要是因为我根本无法访问大多数这些操作系统! 值得庆幸的是,来自全球的keychain用户确实如此,许多人在识别兼容性问题和提交修补程序方面都提供了很大的帮助。

实际上,必须解决两种兼容性问题。 首先,我需要确保keychain仅使用所有sh实现完全支持的内置函数,表达式和运算符,包括所有流行的免费和商业UNIX sh shell, zsh (在sh兼容模式下)和bash版本1和2。这是一些用户提交的,适用于keychain源的外壳兼容性修补程序:

由于较早的sh shell不支持~约定来引用用户的主目录,因此将使用~的行改为使用$HOME

清单3.使它成为$ HOME
hostname=`uname -n`
pidf=${HOME}/.ssh-agent-${hostname}
cshpidf=${HOME}/.ssh-agent-csh-${hostname}

接下来,所有对source引用都更改为. 确保与纯粹的NetBSD的/bin/sh兼容,后者根本不支持source命令:

清单4.培训NetBSD
if [ -f $pidf ]
then
    . $pidf
else
SSH_AGENT_PID="NULL"
fi

在此过程中,我还应用了一些与性能相关的不错的修复程序。 一位精明的shell脚本编写者告诉我,您可以通过输入touch foo来“触摸”文件,而不是:

清单5.触摸文件
> foo

通过依靠内置的shell语法而不是使用外部二进制文件,可以避免fork() ,并且脚本的效率会稍微提高。 > foo应该与任何sh兼容的shell一起工作; 但是, ash似乎不支持它。 对于大多数人来说,这应该不是问题,因为ash更多是应急磁盘类型的外壳,而不是人们日常使用的外壳。

平台可执行文件问题

要使脚本在多个UNIX操作系统下都可以工作,不仅需要坚持纯sh语法。 请记住,大多数脚本还会调用外部命令,例如grepawkps等,并且这些命令必须尽可能以符合标准的方式进行调用。 例如,虽然大多数UNIX版本中包含的echo可以识别-e选项,但是Solaris不能-在使用时,它只是将-e打印到stdout。 因此,为了应对Solaris, keychain现在可以自动检测echo -e是否有效:

清单6.探听Solaris
if [ -z "`echo -e`" ]
then
    E="-e"
fi

上面,如果支持-e转义,则E设置为-e 然后,可以按如下方式调用echo:

清单7.更好的回声
echo $E Usage: ${CYAN}${0}${OFF} [ ${GREEN}options${OFF} ] ${CYAN}sshkey${OFF} ...

通过使用echo $E代替echo -e ,可以根据需要动态启用或禁用-e选项。

pidof,ps

最重要的兼容性修补程序可能涉及更改keychain检测当前正在运行的ssh-agent进程的方式。 以前,我是使用pidof命令执行此操作的,但是由于一些系统没有pidof ,因此必须将其删除。 确实, pidof并不是最佳解决方案,因为当我们对当前有效UID拥有的所有ssh-agent进程真正感兴趣时, pidof会列出系统上运行的所有 ssh-agent进程(无论用户如何)。

因此,我们不再依赖pidof ,而是切换到将ps输出管道传输到grepawk ,以提取所需的进程ID。 这是用户提交的修复程序:

清单8.比pidof更好的管道
mypids=`ps uxw | grep ssh-agent | grep -v grep | awk '{print $2}'`

上面的管道会将mypids变量设置为当前用户拥有的所有ssh-agent进程的值。 grep -v grep命令是管道的一部分,以确保grep ssh-agent进程不会成为我们PID列表的一部分。

尽管这种方法在概念上是好的,但是使用ps开辟了一个全新的蠕虫罐,因为ps选项未在各种BSD和System V UNIX派生产品中标准化。 这是一个示例:虽然ps uxw在Linux下工作,但在IRIX下却不工作。 而且,虽然ps -u username -f在Linux,IRIX和Solaris下均可工作,但在BSD下却无法工作,后者仅了解BSD风格的ps选项。 为了解决这个问题, keychain会在执行ps管道之前自动检测当前系统的ps是否使用BSD或System V语法:

清单9.检测BSD与系统V
psopts="FAIL"
ps uxw >/dev/null 2>&1
if [ $? -eq 0 ]
then
psopts="uxw"
else
ps -u `whoami` -f >/dev/null 2>&1
if [ $? -eq 0 ]
then
psopts="-u `whoami` -f"
fi
fi
if [ "$psopts" = "FAIL" ]
then
echo $0: unable to use \"ps\" to scan for ssh-agent processes.  
Report KeyChain version and echo system configuration to [email protected].
exit 1
fi

mypids=`ps $psopts 2>/dev/null | grep "[s]sh-agent" | awk '{print $2}'` > /dev/null 2>&1

为了确保我们同时使用System V和BSD风格的ps命令,该脚本会对ps uxw进行“ ps uxw运行”, ps uxw丢弃所有输出。 如果此命令的错误代码为零,则说明ps uxw有效,并且我们适当地设置了psopts值。 但是,如果ps uxw返回了非零的错误代码(表明我们需要使用BSD样式的选项),我们ps -u `whoami` -f空运行,再次丢弃所有输出。 至此,希望我们找到了可以使用的ps的BSD或System V变体。 如果没有,则打印出错误并退出。 但是很可能两个ps命令之一都起作用了,在这种情况下,我们执行了上面的代码片段ps管道中的最后一行。 通过在ps之后立即使用$psopts变量扩展,我们可以将正确的选项传递给ps命令。

ps管道还包含一个真正的grep gem,由Hans Peter Verne寄给我。 注意grep -v grep不再是管道的一部分; 相反,它已被删除, grep "ssh-agent"已更改为grep "[s]sh-agent" 这个单一的grep命令最终完成的功能与grep ssh-agent | grep -v grep相同grep ssh-agent | grep -v grep grep ssh-agent | grep -v grep ; 你能弄清楚为什么吗?

清单10.整洁的grep技巧
mypids=`ps $psopts 2>/dev/null | grep "[s]sh-agent" | awk '{print $2}'` > /dev/null 2>&1

难过吗 如果您确定grep "ssh-agent"grep "[s]sh-agent"应该完全相同的文本行,那么您是正确的。 那么,为什么将ps的输出通过管道传递给它们时它们会产生不同的结果呢? 它是这样工作的:当您使用grep "[s]sh-agent" ,您将更改grep命令在ps进程列表中的显示方式。 这样做可以防止grep自身匹配,因为[s]sh-agent字符串与[s]sh-agent正则表达式不匹配。 那不是很聪明吗? 如果仍然不了解它, grep尝试一下grep ,您将很快得到它。

结论

本专栏总结了我对OpenSSH的介绍。 希望您已经学到了足够的知识,可以开始使用OpenSSH保护系统。 下个月的“ 公共线程”专栏将继续“高级文件系统实施者指南”系列。


翻译自: https://www.ibm.com/developerworks/opensource/library/l-keyc3/index.html

openssh 密钥上传

你可能感兴趣的:(openssh 密钥上传_OpenSSH密钥管理,第3部分)