SCP的使用
背景介绍
最近项目是集群化部署(由 node1,node2,node3 三台 CentOS 7.4 的虚拟机构成)。
但是,涉及到跨机器同步文件的问题,想通过写shell文件实现,用 crontab 设置定时任务,定时执行改脚本。
由于每次都需要输入密码,导致定时任务没法正常工作,因此,需要三台机器之间可以免密码互相访问。
建立SSH的信任关系
以实现 node1 免密码给 node2 scp传输文件为例说明,需要如下几个步骤:
1、生成 node1 的秘钥(私钥和公钥)
1)进入 node1 的 /root/.ssh 目录
cd /root/.ssh/
2)执行如下命令,生成公钥和私钥(此时,一路回车即可)
ssh-keygen -t rsa
其中,id_rsa 是私钥,id_rsa.pub 是公钥。
2、将 node1 的 id_rsa.pub中的内容追加到 node2 的authorized_keys 认证文件中
1)将 node1 的公钥(id_rsa.pub)信息,输出到临时认证文件 authorized_keys_node1 中
cat id_rsa.pub >authorized_keys_node1
2)将 authorized_keys_node1 文件 scp 到 /root/.ssh/ 目录下
scp authorized_keys_node1 root@node2:/root/.ssh/
3)登录到node2节点,进入 /root/.ssh目录
cd /root/.ssh/
4)将 node1 的公钥信息,追加到 node2 的认证文件(authorized_keys)中
cat authorized_keys_node1 >>authorized_keys
至此,node1 到 node2 的信任关系建立好了,node1 scp文件到 node2,就不在需要输入密码验证了。
其他机器之间的信任关系,如有需要,可以依此方法进行配置。
注意: 授权列表authorized_keys可以追加多台电脑的公钥(id_rsa.pub), 让多台电脑免密码验证
【额外说明】
1、上面用到了 Shell 的 > 和 >>,因为使用场景不同。
如有不清楚二者异同点的同学,可以参考博文:https://blog.csdn.net/qq_43248623/article/details/107850758
2、文中提到的 id_rsa 和 id_rsa.pub 中的 rsa,是指的 RSA加密算法。
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。
详细解答部分:
预备知识
在介绍SCP协议之前,我们先得了解一下SSH协议,和计算机中的加密方式,因为SCP协议的登录过程基于SSH协议。
对称加密
对称加密,即在数据传输过程中对数据进行加密和解密的算法使用同一个密钥,这种加密算法有什么弊端呢?
当客户端需要与服务器端进行数据传输时,不管是由客户端还是由服务端产生的密钥,都得将这个密钥传给对方才能实现加解密,而在传输的过程中就可能造成密钥的泄漏。
那么有些人就要说了,那我不用网络传输秘钥,我可以使用口头传输或者u盘拷贝的方法。
是的,这样就可以保证安全,但是在大多数互联网应用中,通信双方是陌生设备,无法做到上述的方式。
非对称加密
针对对称加密带来的风险,非对称加密则解决了这个问题。
将加解密使用的密钥分为公钥和私钥,公钥可以公开,而私钥则由密钥生成者保存,客户端使用公钥进行加密,而服务端用私钥进行解密,且目前来说还没有出现能从公钥推算出私钥的的破解机制。
所以相对于对称加密而言,这种加密方式更加安全,但是这种加密方式的缺点是会占用更多的计算机资源,而且这种资源的耗费量是巨大的。
常见的加密方式
对称加密:
DES(Data Encryption Standard):加密速度较快,适合加密大量数据的场合。
3DES:基于DES的加密算法,顾名思义,这是对一块数据用三个不同的密钥进行三次加密,显而易见强度更高,更安全。
RC2和RC4:用变长密钥对大量数据进行加密,速度比DES更快
IDEA:(International Data Encryption Algorithm)国际数据加密算法,使用 128 位密钥提供非常强的安全性;
AES:高级加密标准,是下一代的加密算法标准,速度快,安全级别高,这个加密算法被广泛应用。
非对称加密:
RSA:是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的,目前使用最广的加密算法
Diff ieˉHellman:每次交换数据的时候都使用一组新的密钥,有效地防止了第三方获得私钥后解密所有信息,但是同时对中间人攻击的防护比较薄弱。
非对称加密算法是一种密钥的保密方法。
非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。
另一方面,甲方可以使用自己的私钥对机密信息进行签名后再发送给乙方;乙方再用甲方的公钥对甲方发送回来的数据进行验签。
甲方只能用其私钥解密由其公钥加密后的任何信息。 非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要。
非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了。这样安全性就大了很多。
SSH协议
SSH是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境,最常见的运用是远程登录。SSH的交互流程是这样的:
-
客户端发送请求:这个请求其实就是ssh登录请求,即发起者拥有服务器上的某个用户的账号密码,以远程登录的方式来操作服务器。
-
服务器将公钥发送给客户端,这个公钥是给客户端进行数据加密用的
-
客户端收到服务器公钥,确定是否继续连接?为什么会有这么一个流程呢,既然我指定了就是要连接服务器,为什么还要让我确认一次,这会不会是多此一举呢?其实不然,这是为了防范中间人攻击。
-
客户端用公钥对密码进行加密,再发送给服务器
-
服务器用私钥对密码进行解密,返回登录结果
中间人攻击
刚刚提到中间人攻击,我们就来看看什么是中间人攻击?
我们大可以想一想,在一个不安全的网络中,如果我发送的请求被第三方截获,而第三方把他的公钥发给我,而我用他的公钥对密码进行加密,然后再发送给他,他就获得了完整的账号密码,这时候他就可以拿着从我这儿窃取来的信息登录服务器。
那么,在一个不安全的网络中,我们该怎样防范这种攻击方式呢?一般有两种方法:
-
服务器将公钥公布在官方或者以其他方式公开,让用户可以查到进行对比,如果不匹配,就在第三步的时候取消登录即可。
-
CA证书,由一个权威机构CA对公钥进行认证,CA机构的数字签名使得攻击者不能伪造和篡改证书。CA机构会为申请者发放一个公钥,CA将该公钥和申请者的身份信息绑定在一起,并为之签字。
如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。
SCP的传输
说回到SCP的传输,SCP的传输第一步就是进行SSH的登录动作,然后再基于SSH协议进行文件的传输,整个传输过程是加密的。
在上面提到的ssh登录流程中,是最基本的登录流程,特点在登录时服务器要求客户端提供账号密码进行验证,其实这样是非常麻烦的,在每次登录或者传输文件时,都要输入账号密码,这对于以偷懒为终极目标的程序员来说这是不能忍受的。
SCP的免密传输
我们可以想一想,为什么在每次登录的时候都需要用户输入密码?
所有人都知道这是为了验证登录者的是否有操作权限,那换一个思路想一下,有没有另外一种方法也能验证登录者有这个登录权限呢?
当然是有的,这种验证方式建立在非对称加密协议上,当客户端C想要访问服务器S时,在客户端生成一对密钥(通常使用rsa协议),将客户端C生成的公钥放置在服务器S上,这样在连接时只需要验证服务器S上是否存在客户端C的公钥就可以完成验证操作。(详细流程见下文)
实现SCP免密传输的操作
如果你在服务器拥有一个账号,名为downey
在某一时刻你需要用一台客户机A登录到服务器上进行操作
在客户机A的家目录下的.ssh目录下生成一对秘钥,linux下的指令为:
ssh-keygen -t rsa -P “”
(ssh-keygen为秘钥生成应用程序,-t rsa 表示加密类型为rsa)
执行上述命令后,系统会提示选择生成秘钥放置的目录和密码,一般为默认选择,一路回车。(但是如果你要追求更高的安全性,你可以选择添加上私钥密码),然后在/home/downey/.ssh目录下就会生成两个文件:id_rsa和id_rsa.pub,其中id_rsa为私钥,而id_rsa.pub为公钥。
在服务器端的/home/downey/.ssh/目录下新建文件authorized_keys(如果有则不用创建),将客户端A上刚刚生成的id_rsa.pub文件中的内容复制到服务器端 /home/downey/.ssh/authorized_keys文件中(如果里面有内容则另起一行)
这样就可以直接用scp指令(或者ssh登录)进行文件传输而不用进行账号密码验证了,相当于客户机(操作机器)与服务器建立了安全连接(原理见下文),如果换一台机器登录,依旧需要验证(因为服务器端的公钥只与这台机器上私钥相匹配)。
注意
在这些文件操作的时候,特别需要注意的就是文件的权限问题,很多朋友就是把文件从其他地方复制过来,然后修改文件确保文件内容与目标一致就可以,但是发现这样的操作并没有达到免密传输的效果,很可能就是文件权限出了问题
同时,在某些服务器平台上,可能会提供网页端的接口来存放客户端的pub_key,就像github添加公钥的操作方式,但是原理都是将客户端公钥添加到服务器中
免密传输的登录流程
实现SCP传输的第一步是通信双方进行安全连接(登录),上面提到的SSH登录流程为SSH首次登录的大概讲解,我们不妨来详细探究在免密传输时的登录流程:
客户端向服务端发送连接请求,询问服务器是否支持pubkey的方式进行登录
服务端收到客户端的请求,表示接收pubkey的方式进行登录。
接收到服务端的回复,客户端决定使用pubkey的方式进行登录,客户端将一段数据用私钥进行加密,生成签名,并且将自己的公钥发送给服务器。
服务端收到客户端发过来的数据,首先将客户端的公钥取出来,在/home/$USER/.ssh/authorized_keys/中查找是否存在客户端的公钥,如果有,进行对比。
仅仅对比是否存在客户端的公钥当然是不够安全的,服务器接着使用客户端提供的公钥对客户端发过来的签名(经私钥加密)进行解密,如果解密后的数据内容正确,表示整个验证流程完成。
服务端返回登录结果。
SSH登录流程疑难解答
客户端发送给服务器的签名数据
在上述免密传输的登录部分的第三点我有提到,客户端将一段数据用私钥加密生成签名,然后服务器再对这段数据进行解密,那么服务器怎么知道这段数据是否正确呢?
首先,客户端发送给服务器的数据字段是这样的:
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "publickey"
boolean TRUE
string public key algorithm name
string public key to be used for authentication
string signature //数据签名部分
而客户端使用私钥进行加密的数据字段是这样的:
string session identifier
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "publickey"
boolean TRUE
string public key algorithm name
string public key to be used for authentication
对比发现,事实上客户端同时发了一份数据和数据的签名给服务端,服务端就可以做对比了。
为什么公钥可以对私钥加密的数据解密
很多朋友看完上述免密传输登录流程之后,表示非常疑惑:
为什么公钥可以对私钥加密的数据进行解密?
公钥本来就是公开的,那岂不是私钥加密的数据根本没有安全性可言?
首先回答第一个问题:为什么公钥可以对私钥的加密数据进行解密。答案是:这是SSH协议的规定(好像是废话)。
好吧,正经地回答第二个问题,公钥是公开的,所有人都可以获得,而私钥只有拥有者才有,那由这对密钥加密的数据是否就没有安全性可言呢?
答案当然不是,安全性高着呢。只是,一般的加密过程是公钥加密,私钥解密,这部分数据自然是安全的。
那么私钥加密的数据呢,私钥加密的数据确实没有安全性可言,因为用私钥加密数据根本就不是为了安全性,而是作为一种验证身份的手段。
因为私钥是唯一的,一旦使用公钥对私钥加密的数据解密成功,服务端S就可以完全确定这条消息是由拥有对应私钥的客户端C发出的,而不是第三方伪装者发出的。
所以,公钥加密私钥解密,是为了数据的安全性,而私钥加密公钥解密,则是为了验证数据发送者的身份。
数据传输的加密方式
一般情况下SSH使用rsa加密算法登录,SCP基于SSH协议,所以很多人自然地认为在数据传输时,使用的加密算法也是rsa。
事实上,由于非对称加密算法计算太过于耗时,对所有数据进行加密根本不现实,所以在传输数据时一般使用对称加密算法。
上面有提到,对称加密算法的弊端是密钥传输过程容易被窃取,所以通常使用非对称加密算法来传输对称加密算法的密钥,来保证安全性。
为此,我还使用wareshark工具试图梳理整个数据传输流程,花了一天的时间得出一个结论:针对整个SCP实现的加密算法这一块,以博主的水平,暂时惹不起…(不过也只是暂时!!)
不过收获还是有的:SCP数据传输流程结合了多种加密算法,同时还根据不同级别的安全要求结合不同的加密算法。
一般来说,综合对称和非对称加密算法的特性,非对称加密一般用于登录验证、密钥传输等数据量小、安全性要求较高的的部分。
而对称算法用来传输大量数据。
网上的错误描述
事实上,网络上对于SSH的登录过程描述有不少错误之处,最经典的一个错误观点是服务器发送一个通过公钥加密的字符串给客户端,客户端私钥进行解密,然后发给服务端。
服务端将发出的字符串与收到的字符串进行对于,完成验证过程。
这种做法看起来是非常合理的,但事实上SSH并不采用这种做法,具体原因引用官方文档中的一句话:
the signing operation involves some expensive computation.
To avoid unnecessary processing and user interaction。
这句话意思很简单,加密的计算操作是非常耗时的,我们应该避免不必要的交互以节省资源。
为什么我那么自信确定它们的描述有误呢?并不是飘柔给我的自信,而是官方文档
(多嘴一句,找资源一定要先找官方文档的)
github的免密传输
用过github的盆友可能对免密传输有种熟悉的感觉,没错!在github的配置中,如果需要进行免密传输,流程是:
在客户机生成一对秘钥,同样是id_rsa,id_rsa.pub
将id_rsa.pub里的内容添加到github的settings的SSH and GPG keys选项页面中
同样的,相当于github服务端与机器已经建立用户识别机制,不需要再用账号密码来识别。
好了,关于SCP传输的讨论就到此为止啦,如果朋友们对于这个有什么疑问或者发现有文章中有什么错误,欢迎留言
原创博客,转载请注明出处!