ssh那些事儿(1)—基本原理

web开发系列-ssh那些事儿1


        工作了快一年了,大部分时间在熟悉业务,也断断续续的学习了些web相关内容,现在打算抽出点时间来整理下学习笔记,同时也对一些自己不够清楚的知识点做个梳理吧。这个系列我打算把web相关的东东尽可能的都总结一遍,当然还有很多地方自己也还不清楚,请大家指正。

        关于ssh的基本原理,阮一峰老师在他的博文中《SSH基本原理和应用》已经介绍的比较清楚了,为了完整性,我也写下自己的一些理解吧。ssh是一种计算机之间的加密登陆的协议,存在很多实现,目前用得比较多的免费的ssh实现是openssh,很多linux发行版一般都自带安装了。基本的用法就是大家熟悉的命令行 $ssh user@host,当然如果不是默认端口22,还要加参数-p port,如端口是12345,那么登陆命令就是ssh -p12345 user@host。ssh登陆验证有2种方式,密码认证和公钥认证,在公司服务器上用的的基本是密钥登陆,这样更加安全。

          

1、密码认证

          密码认证的过程是这样的,(1)用户输入ssh命令发送登陆请求 (2)远程主机收到用户登陆请求后,把自己的公钥发给用户。(3)用户使用这个公钥将自己的登陆密码加密后发送给远程主机。(4)远程主机用自己的私钥解密,得到登陆密码,如果密码验证正确,则允许用户登陆,并将该远程主机的公钥保存在$HOME/.ssh/known_hosts中。但是这个过程容易受到中间人攻击,所以用户在输入自己密码前必须要核对远程主机的密钥是否正确(一般在首次登陆时,远程主机会将自己的公钥生成指纹让用户确认,如果公钥指纹与远程主机公布的不一致,就有问题了。注意一点,我们核对的是公钥的指纹,因为公钥太长,很难一个个核对,而md5之类的哈希之后长度相对短一些,方便核对。但是实际存储在known_hosts中的是公钥本身)。具体细节请见参考资料1。

         

2、公钥认证

         密钥认证则会安全一些,登陆期间不会涉及到登陆密码在网络上传递,不过过程也相对复杂一些。主要分为以下几个步骤:

(1)首先你需要自己生成一对公私钥,然后将公钥如id_rsa.pub加入到远程主机目录$HOME/.ssh/authorized_keys文件中。目前用得比较多的是rsa加密算法生成密钥,rsa是一种非对称加密方法,比较安全。rsa加密算法原理,我会在另外一篇博客中说明,暂且不管。生成密钥的过程中会提示你输入加密密码,最好输入密码,不然你的私钥万一泄露了,那就不安全了。创建密钥的命令为ssh-keygen,具体参数含义参见http://lamp.linux.gov.cn/OpenSSH/ssh-keygen.html。

(2)接下来,就是验证过程了。用户输入ssh登陆命令,这是ssh客户端提示用户输入创建密钥的时候设置的密码(Passphrase)来解密私钥。(如果在使用ssh-keygen生成密钥时指定了Passphrase加密私钥,需要解密,加密私钥的算法是对称加密算法DES)。

(3)ssh客户端向远程主机发送私钥签名的包含username,公钥等信息的消息(签名用到的参数除了username,公钥,还有公钥加密算法名,消息标识等)。

(4)远程主机的ssh进程检查消息中指定用户的$HOME/.ssh/authorized_keys,确定公钥是否可以用作验证(也就是确认从用户客户机的消息中传过来的公钥是否在authorized_keys文件中存在),如果公钥合法,则接下来使用公钥解密该消息,验证消息合法性。

        更详细的过程请参见公钥认证过程。

        如果公钥验证失败,则ssh会尝试其他认证策略,如密码认证等,这个由ssh客户端配置而定。需要注意的是,在认证过程中,用户的本地机器上并不再需要公钥,你即使删掉本机上的id_rsa.pub文件同样可以认证成功,这是因为这里所谓的公私钥其实是个广义的词,在私钥中其实是即包含了私钥,也包含了公钥,当然还可能包含其他信息。你可以通过ssh-keygen -y ~/.ssh/id_rsa命令来得到公钥。所以,公钥验证中得第3步中的公钥就是从这里得到的。具体公钥和私钥的组织格式以及具体存储的内容,都将在下次博客说明rsa算法的时候一并分析。


3、ssh agent

        公钥认证是比较安全了,但是每次都要输入密码,比较麻烦。通过ssh agent可以解决这个问题。我们可以使用ssh-add .ssh/id_rsa命令将私钥加入到ssh-agent中由ssh agent来管理。当然在加入的时候,系统会提示你输入密码来解锁私钥。ssh-agent可以同时管理多个私钥,加入私钥到agent中后,连接远程服务器的步骤如下:

(1)ssh 客户端向远端服务器发起登陆请求。

(2)ssh客户端会先向本地的ssh agent请求,得到私钥签名的包含username和公钥等信息的消息。

(3)ssh客户端向远端服务器发送该消息(包含username,公钥以及签名等信息)。

(4)远端服务器的ssh进程检查消息验证公钥是否可以用于验证以及签名的正确性,如果验证通过,则同意登陆。

        可以看到,使用ssh-agent过程中,整个过程ssh客户端是没有得到私钥的,私钥只是存在于ssh-agent中。将私钥加入到ssh-agent之后,后续的登陆就不再需要我们输入密码来解锁私钥了,方便了登陆过程。

        但是,还有个问题比较麻烦的就是,比如我们登陆了远端服务器A,但是我们又想从A登陆到远端服务器B,就不行了。当然最简单的做法是将私钥拷贝一份到A上面,这样就可以从A直接登陆到B 了。但是在实际开发中,这样是万万不可的,因为服务器是大家公用的,你若暴露了自己的私钥,是会导致安全问题的,当然你会说我设了密码,一时半会破解不了,但是不怕一万就怕万一,所以这就需要提到ssh另外一个特性ssh agent forwarding了。


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

        很多时候,我们需要从本地机器登陆到远端服务器A,然后又需要从A登陆到远端服务器B,而我们在A上面是没有放置自己的私钥的,这时候就需要用到ssh agent forwarding了。ssh agent forwarding认证过程如下:

(1)假设用户从本地机器登陆到了远端服务器A,而本地机器的agent中保存了用户私钥。

(2)用户从A向另一个远端服务器B发起ssh登陆请求。

(3)服务器A的ssh客户端向“A的ssh agent”发起请求,获取私钥签名的包含username,公钥等信息的消息。

        需要注意的是,服务器A上面的ssh agent根本就没有启动,服务器A的ssh客户端只是检查服务器A上面是否存在$SSH_AUTH_SOCK这个环境变量,如果存在则通过这个变量指定的domain socket通信,而这个domain socket实际上就是由A的sshd进程创建的,所以A的ssh客户端实际上是与A的sshd进程通信。但是A的sshd并没有私钥信息,所以sshd所做的事情就是转发该请求到用户的本地机器的ssh客户端,然后由本地机器的ssh客户端将请求转发给本地机器的ssh agent。本地机器的ssh agent将包含username,公钥以及签名信息的消息准备后,按照前面的路径发送回A的ssh客户端。

(4)服务器A向服务器B发送从用户本地机器接收到的消息。

(5)服务器B的sshd进程检查指定用户$HOME/.ssh/authorized_keys文件,确定消息中的公钥是否可用于验证并验证签名的合法性。如果通过,则允许登陆。

        通过上述方法,可以实现任意级别的登陆,如从A登陆到B,B登陆到C等。由于私钥只保存在本地机器上,这样保证了私钥的安全。agent forwarding功能默认是关闭的,所以在上面的步骤中要想成功,需要在登陆服务器A的时候加上-A 参数。命令类似ssh -A username@host

        需要注意一点的是,agent forwarding打开后,如上述过程中服务器A打开了agent forwarding,则服务器A上面的root用户只要将$SSH_AUTH_SOCK指向用户对应的套接字地址,则root用户同样可以以该用户的身份登陆其他机器。因此需要确保agent forwarding只在可信的服务器上打开。


5、后续

        有时间会写一篇ssh实战的文章来说明下用法,对ssh操作不是很熟悉的朋友可以先参见这篇博客 使用ssh agent forwarding操作下。

6、参考资料

1.SSH原理与应用:http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html

                                   http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html

2.SSH Agent Forwarding原理: http://blog.pkufranky.com/2012/08/ssh-agent-forwarding-guide/

3.Openssh密钥管理:https://www.ibm.com/developerworks/cn/linux/security/openssh/part1/  

                                        https://www.ibm.com/developerworks/cn/linux/security/openssh/part2/



你可能感兴趣的:(web开发系列)