ssh原理以及与https的区别

标签: ssh

最近在使用云服务器的时候使用到了ssh去做登陆验证。关于ssh的使用原理,公钥和密钥如果对服务器的登陆做验证的。以及对称加密和非对称加密的基本原理,这里做一个比较详细的归纳和总结。

第一部分是关于ssh的使用以及原理的,这里引用了博主:疲惫的豆豆http://www.cnblogs.com/dzblog/p/6930147.html。这一篇讲得比较通俗易懂。也易于上手操作。

一、明白的以下几个概念:

know_host : 存储 已经确保正常、可以安全连接的所有服务器(hosts)的公钥

authorized_hosts : 存储 已经认证的客户端的公钥

public key :公钥

private key :私钥

使用ssh和https有什么不同:

HTTPS:使用https url克隆对初学者来说会比较方便,复制https url然后到git Bash里面直接用clone命令克隆到本地就好了,但是每次fetch和push代码都需要输入账号和密码,这也是https方式的麻烦之处(发现了https免密登录的方式)。
SSH:使用SSH url克隆却需要在克隆之前先配置和添加好SSH key,因此,如果你想要使用SSH url克隆的话,你必须是这个项目的拥有者或管理员,否则你是无法添加SSH key的。另外ssh默认是每次fetch和push代码都不需要输入账号和密码,如果你想要每次都输入账号密码才能进行fetch和push也可以另外进行设置

生成SSH Key的基本命令:

#步骤1:
cd  ~/.ssh ls
#这两个命令就是检查是否已经存在id_rsa.pub或id_dsa.pub文件,如果文件已经存在,那么你可以跳过步骤2

#步骤2:创建一个SSH Key 
ssh-keygen -t rsa -C "你的email地址"
#代码参数含义: 
#-t指定密钥类型,默认是rsa,可以省略。 
#-C设置注释文字,比如邮箱。 
#-f指定密钥文件存储文件名。 

二、关于ssh

 SSH是一种网络协议,用于计算机之间的加密登录。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。

最早的时候,互联网通信都是明文通信,一旦被截获,内容就暴露无疑。1995年,芬兰学者Tatu Ylonen设计了SSH协议,将登录信息全部加密,成为互联网安全的一个基本解决方案,迅速在全世界获得推广,目前已经成为Linux系统的标准配置。

三、基本用法

ssh [email protected]

四、对称加密和非对称加密的区别

首先想到的实现方案肯定是对数据进行加密。加密的方式主要有两种:

  • 对称加密(也称为秘钥加密)
  • 非对称加密(也称公钥加密)

所谓对称加密,指加密解密使用同一套秘钥。如下图所示:

1、用于加密数据的组件和用于解密数据的组件,两者之间的关联性决定了该种加密方式是对称型的还是非对称型的。

对称加密采用同一个密钥加密和解密数据。也就是说,任意两个持有同样密钥的人就可以在相互之间传递加密信息并解密。

该种加密方式常被称为“共同的秘密(shared secret)”式加密或者“秘密的钥匙(secret key)”式加密。通常情况下,所有的操作都使用同一个密钥,或者一对关联度非常高、使得接收方能够很容易的推断出发送方使用的密钥的密钥对。

SSH使用对称密钥为整个连接过程加密。众所周知的公钥/私钥(public/private)是非对称密钥对,然而它们仅仅用于身份验证的过程,而没有用在传输过程。对称加密可以保护密码验证过程不受嗅探(snooping)的威胁。

该对称密钥由客户端与服务器端共同创建,生成的密钥不告知任何第三方。创建密钥的过程涉及一个密钥交换算法(key exchange algorithm),使用该算法时,客户端和服务器端根据共享的部分公共数据加上指定的秘密数据分别独立生成同样一个密钥(下文将详细介绍这个过程)。

该过程创建的对称加密密钥是基于会话(session)的,负责对服务器和客户端之间传输的数据进行加密。创建后,其余的所有数据传输都会经过该密钥的加密。这个过程在认证客户端之前执行。

SSH可以配置不同的对称加密法(symmetrical cipher system),包括AES、Blowfish、3DES、CAST128、以及Arcfour。服务器和客户端都可以选择其使用的加密法,最终使用的加密法一般由机器上加密法列表的排序决定:客户端加密法列表上出现的第一个服务器端也支持的加密算法,将用于双方加密传输的实现。

Ubuntu 14.04的默认列表顺序如下(客户端和服务器端通用):aes128-ctr、aes192-ctr,aes256-ctr、arcfour256、arcfour128、[email protected][email protected][email protected]、aes128-cbc、blowfish-cbc、cast128-cbc、aes192-cbc、aes256-cbc、arcfour。

也就是说,如果是两台Ubuntu 14.04之间进行数据传输,则它们总会使用aes128-ctr加密算法(除非做过另外的配置)。

 对称加密-Client端


对称加密-Server端


2、非对称加密有两个密钥:"公钥"和"私钥"。

特性:

公钥加密后的密文,只能通过其对应的私钥进行解密。

通过公钥推理出私钥的可能性微乎其微。

非对称加密的发送与接收需要使用两个密钥,这两个密钥是相互关联的,一个叫做私钥(private key),另一个叫做公钥(public key)。

公钥可以共享给其他人,仅仅持有公钥是无法推导出私钥的。从数学的实现上,公钥加密的信息仅仅可以由私钥解密(而不能由公钥自己解密),私钥加密的信息也不能用公钥解密。这是一个单向的过程。

私钥必须要严格保密,不可与其他人共享。私钥的保密是整个加密范式安全性的关键。该范式假设:持有私钥是解密的唯一方式。如果一台主机能够解密由公钥加密过的信息,这只能表示它掌握着对应的密钥。

SSH在以下几个节点采用了非对称加密。首先是一开始建立用于连接的对称加密时的密钥交换过程(key exchange)。在这一阶段,服务器和客户端都各自生成了临时的公钥/私钥对,以计算出同一个用于连接加密的共享密钥。

其次是广为人知的SSH身份验证过程。SSH密钥对用于让服务器验证一个客户端的身份。密钥对在客户端上生成,其中的公钥上传至远程服务器,保存在~/.ssh目录下一个叫做authorized_keys的文件里。

安全连接建立后,服务器就会触发身份验证过程。服务器会用其文件里的公钥加密一条信息发给客户端,如果客户端能够解密出正确的信息,则证明了它持有对应的私钥,然后服务器才会对该客户端开放自己的环境。

非对称加密原理图:


登录流程:

  1. 远程Server收到Client端用户TopGun的登录请求,Server把自己的公钥发给用户。

  2. Client使用这个公钥,将密码进行加密。

  3. Client将加密的密码发送给Server端。

  4. 远程Server用自己的私钥,解密登录密码,然后验证其合法性。

  5. 若验证结果,给Client相应的响应。

补充:这一种登陆方式是通过口令的方式登陆。需要每次输入一次密码,密码输入后通过服务端的公钥加密后进行传输到服务端,服务端的私钥进行解密。 

五、中间人攻击

SSH之所以能够保证安全,原因在于它采用了公钥加密。

整个过程如上图所示:

(1)远程主机收到用户的登录请求,把自己的公钥发给用户。

(2)用户使用这个公钥,将登录密码加密后,发送回来。

(3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

这个过程本身是安全的,但是实施的时候存在一个风险:

Client端如何保证接受到的公钥就是目标Server端的?,如果一个攻击者中途拦截Client的登录请求,向其发送自己的公钥,Client端用攻击者的公钥进行数据加密。攻击者接收到加密信息后再用自己的私钥进行解密,不就窃取了Client的登录信息了吗?

如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。可以设想具体场景,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的"中间人攻击"(Man-in-the-middle attack)。

以用户TopGun为例,如图四:

六、解决中间人攻击方法

1、口令登录(基于口令的认证)

从上面的描述可以看出,问题就在于如何对Server的公钥进行认证?在https中可以通过CA来进行公证,可是SSH的publish key和private key都是自己生成的,没法公证。只能通过Client端自己对公钥进行确认。

通常在第一次登录的时候,系统会出现下面提示信息:

$ ssh [email protected]
The authenticity of host 'host (12.18.429.21)' can't be established.
RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
Are you sure you want to continue connecting (yes/no)?

上面的信息说的是:无法确认主机host(12.18.429.21)的真实性,不过知道它的公钥指纹,询问你是否继续连接?

所谓"公钥指纹",是指公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较,就容易多了。

之所以用fingerprint代替key,主要是key过于长(RSA算法生成的公钥有1024位),很难直接比较。所以,对公钥进行hash生成一个128位的指纹,这样就方便比较了。

很自然的一个问题就是,用户怎么知道远程主机的公钥指纹应该是多少?

回答是没有好办法,远程主机必须在自己的网站上贴出公钥指纹,以便用户自行核对,或者自己甄别host地址是否正确。

假定经过风险衡量以后(一般用户直接就选择yes吧),用户决定接受这个远程主机的公钥。
  Are you sure you want to continue connecting (yes/no)? yes
系统会出现一句提示,表示host主机已经得到认可。
  Warning: Permanently added 'host,12.18.429.21' (RSA) to the list of known hosts.
然后,会要求输入密码。
  Password: (enter password)
如果密码正确,就可以登录了。

当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts,保存一些对所有用户都可信赖的远程主机的公钥。

我本地的known_hosts文件,可以发现已经保存了五个我觉得放心的服务器(hosts)的公钥

简单说,当host已被确认,并被追加到文件known_hosts中,下次连接只需要输入密码即可,之后的流程就按照图3进行。

2、公钥登录(基于公钥的认证)

使用密码登录,每次都必须输入密码,非常麻烦。好在SSH提供了另外一种可以免去输入密码过程的登录方式:公钥登录。

所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。

登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

公钥认证流程:

1. Client端用户TopGun将自己的公钥存放在Server上,追加在文件authorized_keys中。

2. Server收到登录请求后,随机生成一个字符串str1,并发送给Client。

3. Client用自己的私钥对字符串str1进行加密。

4. 将加密后字符串发送给Server。

5. Server用之前存储的公钥进行解密,比较解密后的str2和str1。

6. 根据比较结果,返回客户端登陆结果。

这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个

运行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个。

运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。前者是你的公钥,后者是你的私钥。

比如,我需要用用户user登录host服务器,只需再输入下面的命令,将公钥传送到远程主机host上面:

$ ssh-copy-id [email protected]

好了,从此你再登录,就不需要输入密码了。

如果还是不行,就打开远程主机的/etc/ssh/sshd_config这个文件,检查下面几行前面"#"注释是否取掉。
  RSAAuthentication yes
  PubkeyAuthentication yes
  AuthorizedKeysFile .ssh/authorized_keys
然后,重启远程主机的ssh服务。
  // ubuntu系统
  service ssh restart
  // debian系统
  /etc/init.d/ssh restart

3、什么是authorized_keys文件?

远程主机将用户的公钥,保存在登录后的用户主目录的$HOME/.ssh/authorized_keys文件中。公钥就是一段字符串,只要把它追加在authorized_keys文件的末尾就行了。

这里不使用上面的ssh-copy-id命令,改用下面的命令,解释公钥的保存过程:

$ ssh [email protected] 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
这条命令由多个语句组成,依次分解开来看:(1)"$ ssh [email protected]",表示登录远程主机;(2)单引号中的mkdir .ssh && cat >> .ssh/authorized_keys,表示登录后在远程shell上执行的命令:(3)"$ mkdir -p .ssh"的作用是,如果用户主目录中的.ssh目录不存在,就创建一个;(4)'cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub的作用是,将本地的公钥文件~/.ssh/id_rsa.pub,重定向追加到远程文件authorized_keys的末尾。
写入authorized_keys文件后,公钥登录的设置就完成了。



版权声明:本文为PeipeiQ原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/PeipeiQ/article/details/80702514