程序员人生 网站导航

SSH Agent Forwarding原理

栏目:框架设计时间:2016-07-07 13:32:27
 

SSH Agent Forwarding原理 

 2947人浏览 评论(2) 收藏 举报

目录(?)[+]

转载自:http://blog.pkufranky.com/2012/08/ssh-agent-forwarding-guide/

ssh-agent的manual写得倒是挺详细,可看了好几次都没怎样弄明白。08年在网上找到了非常好的1篇文章,An Illustrated Guide to SSH Agent Forwarding (后文简称agent guide), 将ssh的各种认证方法讲得非常之详细。 文章从密码认证,公钥认证,使用agent和agent forward的公钥认证几个方面,逐渐的将全部进程剖析得非常全面。 看完以后总算是入了门,为此写了1篇简短的博文。

本周为了做ssh agent相干的培训,多方查看资料,包括ssh/sshd的manual, 相干RFC, wikipedia。 终究算是把密码学和ssh相干东西理解得更深入了。然后重新将agent guide看了看,发现了1些问题。agent guide是2006年写的,而06年SSH⑵刚刚出来,因此文章是基于SSH⑴的。虽然ssh agent的基本原理还是对的,但有的地方(主要是认证部份)已不正确了。

所以本文针对SSH⑵,将不准确的地方重新梳理1下,并添加了1些SSH基石(密码学)相干的内容。

密码学

先从密码学说起。 现代之前,密码学(cryptography)主要专指加密(encryption)解密(decryption)。1组配对的加密和解密算法称为cipher. 加解密的具体运作由两部份决定:1个是算法(algorithm),另外一个是钥匙(key).

现代密码学主要分为对称钥匙密码学和公钥密码学(非对称钥匙密码学)。对称钥匙密码学指的是加密方和解密方都具有相同的密钥。对称钥匙加密算法包括3DES, AES, Blowfish等。 对称钥匙密码学依赖于钥匙的保密性,其为难的困难是:当安全的通道不存在于双方时,如何安全传送这1双方同享的密钥?如果有通道可以安全地建立钥匙,何不使用现有的通道。这个“鸡生蛋、蛋生鸡”的矛盾是终年以来密码学没法在真实世界利用的阻碍。直到1976年,公钥密码学的诞生,安全通道的问题才得以很好的解决。这1点下面讲SSL/TLS的时候会提到。

公钥密码学,则使用1对公钥和私钥,通过公钥加密,私钥解密。公钥和私钥是相干的,但很难从1个推导出另外1个。公钥密码学不存在安全传送密钥的问题,由于公钥可以对外公然,明文传送。

公钥密码学包括公钥加密算法和数字签名算法。RSA是最多见的公钥加密算法。RSA算法由3步构成: 公钥私钥的生成,加密和解密。公钥和私钥中的任何1个可用作加密,另外一个则用作解密。

RSA也可用作数字签名,甲方将消息的散列值使用私钥加密,作为签名附在消息后面,乙方收到消息后使用公钥将签名解密,然后和消息计算的散列值进行对照。假设二者符合的话,那末乙方就能够知道发信人持有甲的私钥,和这个消息在传播路径上没有被篡改过。

DSA是经常使用的数字签名算法,但不能用作加密解密。

如何利用密码学来安全传输数据呢?目前最经常使用的安全数据传输协议(利用层协议)是SSL/TLS. SSL (Secure Socket Layer)协议分为1.0, 2.0(1995),3.0(1996)3个版本。TLS (Transport Layer Security)则是SSL的后继协议,分为1.0, 1.1,1.2(2008)3个版本。TLS在SSL3.0的基础上改动其实不大,但和SSL3.0不能互操作(interoperate)。TLS中包括将连接降级到SSL3.0的方法,因此也写作SSL/TLS.

TLS1般使用基于非对称密码学的Diffie-Hellman key exchange来安全传送同享密钥,然后使用对称钥匙加密算法和这1同享密钥对传送的数据进行加密。很多利用层的协议都可通过SSL/TLS来安全传输数据,比如最多见的HTTPS, 邮件传输服务协议(SMTP)等。

Secure Sockets Layer (SSL) uses Diffie-Hellman key exchange if the client does not have a public-private key pair and a published certificate in the Public Key Infrastructure, and Public Key Cryptography if the user does have both the keys and the credential.

ssh认证和agent forwarding

终究到正题了,下面开始讲SSH.

那SSH (Secure Shell)和SSL/TLS是甚么关系呢?SSH也是1个网络协议,用来进行安全数据交换,远程shell服务和命令履行等。SSH由传输,认证和连接等协议组成。SSH的传输协议类似SSL/TLS (Diffie-Hellman key exchange和对称钥匙加密)。

本文的重点是SSH的认证部份。client和server通过key exchange取得同享密钥(shared session key)后,所有以后的传输数据都进行了加密。然落后入认证部份,认证成功后,则双向连接通道建立,通常是login shell.

来自securecrt官网关于shared session key的描写

Session keys are the “shared keys” described above and are randomly generated by both the client and the server during establishment of a connection. Both the client and host use the same session key to encrypt and decrypt data although a different key is used for the send and receive channels. Session keys are generated after host authentication is successfully performed but before user authentication so that usernames and passwords can be sent encrypted. These keys may be replaced at regular intervals (e.g., every one to two hours) during the session and are destroyed at its conclusion.

SSH认证有多种方法,本文侧重讲最多见了两种:密码认证和公钥认证。

1. 密码认证

密码认证最简单:

  1. ssh client向目标机器发起tcp连接(1般22端口)并发送username (username是SSH协议的1部份)
  2. 目标机器ssh daemon回应需要密码
  3. ssh client提示用户输入密码,然后将密码发送到服务器
  4. ssh daemon如果密码匹配成功, 则认证通过,

基于密码认证的缺点是

  • 容易被brute-force password guessing
  • 不合适于管理多台机器
    若每台机器使用相同的密码,如果密码泄漏,所有机器都被攻破。若使用不同密码,则密码太多很难记住,因此也不可能使用很强的密码。

2. 公钥认证

公钥认证详细协议见RFC4252的publickey部份

公钥认证需要先在本地机器生成公钥私钥对,然后将公钥放到目标机器的$HOME/.ssh/authorized_keys中。具体进程以下

  1. ssh client向目标机器发起tcp连接(1般22端口)
  2. ssh client提示用户输入passphrase以解密私钥
  3. ssh client发送私钥签名的包括username和公钥等信息的message. 
  4. 目标机器ssh daemon通过检查消息中指定用户的$HOME/.ssh/authorized_keys,肯定公钥是不是可用作认证并验证签名的合法性, 如果二者都ok, 则通过认证

如果公钥认证失败,ssh还会尝试其他认证策略,比如密码认证。多个认证策略的尝试顺序和服务器端没关系,由客户真个配置来决定。

需要说明的是,即便把本机的公钥(如.ssh/id_rsa.pub)删除掉,认证依然可以成功。那第3步中提到的公钥从哪里来的呢?实际上,上面(如第2步)提到的私钥(如.ssh/id_rsa)是广义的,既包括了私钥,也包括了公钥,也有可能还包括了其他信息(比如证书)。比如通过ssh-keygen -y ~/.ssh/id_rsa就能够看到id_rsa里面的公钥。

用作认证的私钥最好通过passphrase进行加密,否则会有很大安全隐患,只要私钥泄漏,他人就可以访问你能访问的所有远程机器。

公钥认证由于需要配置公钥私钥,初始配置略微麻烦1些,但好处是所有机器只需配置1组公私钥对就能够了。由于只有1个私钥,没必要设置多个密码,因此可以为其设置比较强的密码。并且仅当私钥和密码1同丢失时才有风险,但这个几率非常小。

不过依然烦人的是,每次登陆都得输入passphrase。

3. 使用ssh agent的公钥认证

为解决每次登陆远程机器都需要输入passphrase的问题,ssh-agent被引入了。ssh-agent启动后,可通过ssh-add将私钥加入agent. ssh-add会提示用户输入passphrase以解密私钥,然后将解密后的私钥纳入agent管理。agent可同时管理多个私钥。

连接服务器的步骤以下:

  1. ssh client向目标机器发起tcp连接(1般22端口)
  2. ssh client向本地的agent要求, 得到私钥签名的包括username和公钥等信息的message
  3. ssh client向目标机器发送此message和签名
  4. 目标机器ssh daemon通过检查消息中指定用户的$HOME/.ssh/authorized_keys,肯定公钥是不是可用作认证并验证签名的合法性, 如果二者都ok, 则通过认证

如果ssh-agent中有多个私钥, 会顺次尝试,直到认证通过或遍历所有私钥. 

在全部进程中,私钥只存在于agent的内部(内存中), ssh client并没有获得到私钥。

使用ssh-agent后,只需在将key纳入agent管理时输入passphrase,以后的ssh相干操作就没必要输入passphrase了。但如果从本机A登陆机器B后,又想从B登陆C (或从B传输文件到C),依然需要输入passphrase (如果B上也配置了用户的私钥)或password。还是比较麻烦。

幸亏,ssh agent forwarding解决了这1问题。

4. 使用ssh agent forwarding的公钥认证

  1. 假定用户已从homepc连接到了第1台机器server。homepc的agent中已保存了用户的私钥
  2. server: 用户从server向server2发起ssh连接要求
  3. server: ssh client向本地(server)的agent要求, 得到私钥签名的包括username和公钥等信息的message。

    注意server上其实ssh-agent压根就没有启动,ssh client只是检查$SSH_AUTH_SOCK这个环境变量是不是存在,如果存在,则和这个变量指定的domain socket进行通讯。而这个domain socket实际上是由server上的sshd创建的。所以ssh client实际上是和sshd在通讯。

    而server的sshd并没有私钥信息,所以sshd做的事情实际上是转发该要求到homepc的ssh client,再由该client将要求转发给本地(homepc)的agent。该agent将需要的消息和签名准备终了后,再将此数据按原路返回到server的ssh client. 路径以下所示

    agent_homepc --($SSH_AUTH_SOCK)-- ssh_homepc --(tcp)-- \ sshd_server --($SSH_AUTH_SOCK)-- ssh_server --(tcp)-- \ sshd_server2

    这下明白为何叫agent forwarding(转发)了吧,就是所有中间节点的sshd和ssh都充当了数据转发的角色,1直将私钥操作的request转发到了本机的agent,然后再将agent的response原路返回。

  4. server: ssh client向目标机器server2发送此message和签名

  5. server2: ssh daemon通过检查消息中指定用户的$HOME/.ssh/authorized_keys,肯定公钥是不是可用作认证并验证签名的合法性, 如果二者都ok, 则通过认证

上面只是示例,从server2,还可以类似的无密码登陆到server3。事实上,通过ssh agent forwarding, 能实现任意级别的无密码登陆。并且私钥只保存在本地的机器上,保证了私钥的安全。

agent forwarding功能是默许关闭的,为实现任意级别无密码登陆,在ssh到其他机器时,1定要记得添加-A参数, 以打开agent forwarding (在目标机器上会生成$SSH_AUTH_SOCK环境变量)。 比如ssh -A server2

agent forwarding打开以后,也会有安全的风险。如果用户A通过ssh连接server并打开了agent forwarding,由于server上的root用户也有权限访问与agent通讯的套接字,只要root用户将$SSH_AUTH_SOCK指向用户A对应的套接字地址,就能够以A的身份访问其它A可以访问的机器。因此请确保agent forwarding仅在可信任的服务器上打开。

本文主要从基本原理角度对ssh认证和agent相干问题进行了分析。下文会讲讲最好实践。



ps:

使用步骤以下:

1 eval `ssh-agent`

2 ssh-add

3 ssh -A  要连接的主机


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐