在linux下开发时,常常须要登陆到其余的设备上,例如虚拟机内ubuntu、树莓派等等,常常涉及到传输文件的操做,传输文件有不少中方法,如物理磁盘拷贝,基于网络的samba服务、SCP传输、ftp文件传输等等,今天咱们就来聊聊出场频率最高的SCP传输。linux
在linux环境中,当咱们须要在两台机器之间传输数据时,常常会用到SCP指令,(SCP指令其实就是基于SCP(secure copy)协议实现的应用程序),SCP的使用示例:git
scp a.out downey@192.168.1.101:/home/donwey
从示例能够看出,上述示例为:将a.out这个文件传送给IP为192.168.1.101目标机器的/home/downey目录下,若是是第一次传输,终端会显示:程序员
The authenticity of host '192.168.4.77 (192.168.4.77)' can't be established.ECDSA key fingerprint is 7f:d8:d6:37:4f:a7:6f:8d:a3:00:45:7f:0d:xx:xx:xx.Are you sure you want to continue connecting (yes/no)?
接着键入:github
yes
而后系统会提示你输入帐户和密码,注意这个密码指的是目标机器上用户的帐号密码,正确输入以后传输完成。算法
知道怎么作,固然还须要知道为何这么作,因此咱们须要来探究scp指令背后的秘密。ubuntu
在介绍SCP协议以前,咱们先得了解一下SSH协议,和计算机中的加密方式,由于SCP协议的登陆过程基于SSH协议。安全
对称加密,即在数据传输过程当中对数据进行加密和解密的算法使用同一个密钥,这种加密算法有什么弊端呢?服务器
当客户端须要与服务器端进行数据传输时,无论是由客户端仍是由服务端产生的密钥,都得将这个密钥传给对方才能实现加解密,而在传输的过程当中就可能形成密钥的泄漏。网络
那么有些人就要说了,那我不用网络传输秘钥,我可使用口头传输或者u盘拷贝的方法。session
是的,这样就能够保证安全,可是在大多数互联网应用中,通讯双方是陌生设备,没法作到上述的方式。
针对对称加密带来的风险,非对称加密则解决了这个问题。
将加解密使用的密钥分为公钥和私钥,公钥能够公开,而私钥则由密钥生成者保存,客户端使用公钥进行加密,而服务端用私钥进行解密,且目前来讲尚未出现能从公钥推算出私钥的的破解机制。
因此相对于对称加密而言,这种加密方式更加安全,可是这种加密方式的缺点是会占用更多的计算机资源,并且这种资源的耗费量是巨大的。
DES(Data Encryption Standard):加密速度较快,适合加密大量数据的场合。
3DES:基于DES的加密算法,顾名思义,这是对一块数据用三个不一样的密钥进行三次加密,显而易见强度更高,更安全。
RC2和RC4:用变长密钥对大量数据进行加密,速度比DES更快
IDEA:(International Data Encryption Algorithm)国际数据加密算法,使用 128 位密钥提供很是强的安全性;
AES:高级加密标准,是下一代的加密算法标准,速度快,安全级别高,这个加密算法被普遍应用。
RSA:是一个支持变长密钥的公共密钥算法,须要加密的文件块的长度也是可变的,目前使用最广的加密算法
Diff ieˉHellman:每次交换数据的时候都使用一组新的密钥,有效地防止了第三方得到私钥后解密全部信息,可是同时对中间人攻击的防御比较薄弱。
SSH是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境,最多见的运用是远程登陆。SSH的交互流程是这样的:
客户端发送请求:这个请求其实就是ssh登陆请求,即发起者拥有服务器上的某个用户的帐号密码,以远程登陆的方式来操做服务器。
服务器将公钥发送给客户端,这个公钥是给客户端进行数据加密用的
客户端收到服务器公钥,肯定是否继续链接?为何会有这么一个流程呢,既然我指定了就是要链接服务器,为何还要让我确认一次,这会不会是画蛇添足呢?其实否则,这是为了防范中间人攻击。
客户端用公钥对密码进行加密,再发送给服务器
服务器用私钥对密码进行解密,返回登陆结果
刚刚提到中间人攻击,咱们就来看看什么是中间人攻击?
咱们大能够想想,在一个不安全的网络中,若是我发送的请求被第三方截获,而第三方把他的公钥发给我,而我用他的公钥对密码进行加密,而后再发送给他,他就得到了完整的帐号密码,这时候他就能够拿着从我这儿窃取来的信息登陆服务器。
那么,在一个不安全的网络中,咱们该怎样防范这种攻击方式呢?通常有两种方法:
服务器将公钥公布在官方或者以其余方式公开,让用户能够查到进行对比,若是不匹配,就在第三步的时候取消登陆便可。
CA证书,由一个权威机构CA对公钥进行认证,CA机构的数字签名使得攻击者不能伪造和篡改证书。CA机构会为申请者发放一个公钥,CA将该公钥和申请者的身份信息绑定在一块儿,并为之签字。
若是一个用户想鉴别另外一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证经过,该证书就被认为是有效的。
说回到SCP的传输,SCP的传输第一步就是进行SSH的登陆动做,而后再基于SSH协议进行文件的传输,整个传输过程是加密的。
在上面提到的ssh登陆流程中,是最基本的登陆流程,特色在登陆时服务器要求客户端提供帐号密码进行验证,其实这样是很是麻烦的,在每次登陆或者传输文件时,都要输入帐号密码,这对于以偷懒为终极目标的程序员来讲这是不能忍受的。
咱们能够想想,为何在每次登陆的时候都须要用户输入密码?
全部人都知道这是为了验证登陆者的是否有操做权限,那换一个思路想一下,有没有另一种方法也能验证登陆者有这个登陆权限呢?
固然是有的,这种验证方式创建在非对称加密协议上,当客户端C想要访问服务器S时,在客户端生成一对密钥(一般使用rsa协议),将客户端C生成的公钥放置在服务器S上,这样在链接时只须要验证服务器S上是否存在客户端C的公钥就能够完成验证操做。(详细流程见下文)
若是你在服务器拥有一个帐号,名为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/中查找是否存在客户端的公钥,若是有,进行对比。
仅仅对比是否存在客户端的公钥固然是不够安全的,服务器接着使用客户端提供的公钥对客户端发过来的签名(经私钥加密)进行解密,若是解密后的数据内容正确,表示整个验证流程完成。
服务端返回登陆结果。
在上述免密传输的登陆部分的第三点我有提到,客户端将一段数据用私钥加密生成签名,而后服务器再对这段数据进行解密,那么服务器怎么知道这段数据是否正确呢?
首先,客户端发送给服务器的数据字段是这样的:
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的配置中,若是须要进行免密传输,流程是:
在客户机生成一对秘钥,一样是id_rsa,id_rsa.pub
将id_rsa.pub里的内容添加到github的settings的SSH and GPG keys选项页面中
一样的,至关于github服务端与机器已经创建用户识别机制,不须要再用帐号密码来识别。
好了,关于SCP传输的讨论就到此为止啦,若是朋友们对于这个有什么疑问或者发现有文章中有什么错误,欢迎留言
原创博客,转载请注明出处!