我的一直在努力推进git在公司内部的普及和使用,前些日子在公司内部作了一次分享课,给你们介绍了下项目发布流程相关的内容,顺便普及了一些git的相关知识。对git是什么,以及怎样配置和使用它作了一些说明。但过后,不少同事的反馈,让我意识到他们不少人都卡在ssh免密钥登陆的配置上。咱们常说,学习一个新的东西应该遵循3W1H法则--WAHT(是什么),WHEN(何时用),HOW(怎样用)和 WHY(为何这样用)。我想你们应该是由于不知道为何这样用,因此才会感到困惑。恰好,最近也在整理“使用Python相关模块进行数据加密”的文档,须要作些理论性的铺垫,因此才想写这篇文章,但愿对你们有所帮助。html
另外须要说明的是,网络安全涉及不少方面的不少内容,本文只是针对网络数据传输过程当中的安全性发表一下我的认识和见解。若是描述的有什么不妥之处,欢迎你们留言交流和指正。git
咱们说的数据加密与解密一般是为了保证数据在网络传输过程当中的安全性。在网络发展初期,网络的数据安全性是没有被足够的重视的。事实上,当时为了实现数据能够经过网络进行传输已经耗费了科学家大部分男细胞,所以在TCP/IP协议设计的初期,他们也实在没有太多精力去过多考虑数据在网络传输过程当中可能存在的安全性问题。随着TCP/IP协议及相关技术的日渐成熟,网络数据传输技术愈来愈稳定,人们才慢慢开始重视这个问题,美国国家标准与技术研究院(National Institue of Standard and Technology,简称NIST)也开始制定相关的安全标准。算法
网络安全涉及到不少个方面,咱们这里仅仅讨论下网络数据传输过程当中可能受到的威胁,其中常见的有:浏览器
针对以上威胁,咱们介绍下网络数据传输的安全性涉及的几个方面:安全
机密性是指对要传输的数据进行加密和解密,防止第三方看到通讯数据的明文内容。其对应的通讯过程以下:服务器
数据发送方:网络
plaintext(明文) ==> 转换算法 ==> ciphertext(密文)
数据接收方:ssh
ciphertext(密文) ==> 转换算法 ==> plaintext(明文)
数据完整性是指不容许数据在传输过程当中被修改(第三方恶意篡改或电平信号形成的部分数据丢失),可是它不要求数据的机密性,也就是说容许其余人看到明文数据。咱们一般经过以不可逆的算法对数据提取特征码(也叫数据指纹),经过验证特征码的一致性来判断数据是否被修改过,通讯过程以下:post
数据发送发:性能
plaintext(明文) ==> 转换算法 ==> plaintext(明文) + footprint(数据指纹A)
数据接收方:
plaintext(明文) + footprint(数据指纹A) ==> 转换算法 ==> footprint(数据指纹B) ==> 对比数据指纹A与B是否一致
身份验证一般是指数据接收方须要确认发送数据给本身的数据是本身想要通讯的那一方,防止他人冒充通讯对方的身份进行通讯。身份验证的大致原理是:数据发送方与数据接收方约定一种特殊的数据加解密方式,数据发送方将一个经过约定的加密方式进行加密后的数据发送给数据接收方,数据接收方如能按照约定的加密方式正确解密该数据就表示对数据发送方的身份验证成功。其对应的通讯过程以下:
数据发送方:
plaintext(明文) ==> 转换算法 ==> ciphertext(密文)
数据接收方:
ciphertext(密文) ==> 转换算法 ==> plaintext(明文)
上面提到的网络数据传输所涉及到的几个方面都须要特定的转换算法来实现,经常使用的转换算法(数据加密/解密算法)大致上能够分为如下几类:
对称加密是指数据加密与解密使用相同的密钥。
一般用于保证数据的机密性。
须要说明的是,秘钥长度越长,数据加密与解密的时间就越久。
单向加密是指只能对明文数据进行加密,而不能解密数据。
一般用于保证数据的完整性。
可能出现中间人攻击,中间人能够对原始内容进行修改以后从新生成数据指纹,数据接收方验证数据指纹时会发现数据是正常的。此时,数据发送方只能把生成的数据指纹进行加密后再发送给数据接收方,那么问题就又回到了加密密钥的传输和管理上。
公钥加密,也被称做非对称加密,也就是说加密和解密所使用的密钥是不一样的。
一般用于保证身份验证。
咱们发现公钥加密“貌似”已经解决了密钥管理的问题--全部人只须要知道本身的那一对儿密钥便可,须要跟谁通讯就去获取对方的公钥,而后经过这个公钥对数据进行加密和机密就能够了。咱们能够用它来完成如下两件事情:
事实上,公钥加密算法不多用于数据加密,它一般只是用来作身份认证,由于它的密钥太长,加密速度太慢--公钥加密算法的速度甚至比对称加密算法的速度慢上3个数量级(1000倍)。
实际上,已经存在一种专门用于秘钥交换的算法--Diffie-Hellman加密算法。该加密算法自己仅限于秘钥的交换用途,被许多商用产品用做秘钥交换技术。这种秘钥交换技术的目的在于使得两个用户安全的交换一个密钥,以便用于以后的数据对称加密。也就是说,通讯双方能够经过这个技术,动态的协商生成一个用于对称加密的密钥,而不用管理不少静态的密钥,这样就解决了密钥的管理问题。
须要说明的是,在经过秘钥交互技术动态协商生成密钥以前,一般须要先经过公钥加密算法对对方的身份进行验证。实际上,https就是这样工做的。
公钥实际上也是一段文本,验证公钥的合法性涉及到两个方面:
其实,这个已经不是靠纯技术能解决的问题了,这须要借助一些机构和人为约定来解决。常见的解决方案有两种:
咱们常见的对于上面这些加密算法的经典应用就是ssh和https了,它们都是使用这些加密算法实现的网络协议。下面咱们对ssh和https的工做原理进行下介绍,一方面当作上面这些加密算法的实例讲解,帮助你们了解这些算法的经典应用;另外一方面,也帮助你们更深刻的理解ssh和https是什么,以及它们是怎样工做的。
简单来讲,SSH就是一种网络协议,主要用于计算机之间的加密登陆与数据传输,使用方式以下:
# ssh user@host
表示要以user这个用户的身份登陆host这台网络机器。也能够省略前面的user,这样来用ssh host
,表示以当前本地登陆的用户名登陆host这台网络机器。
早期,人们主要是经过telnet协议进行计算机之间的登陆操做,可是它有一个很严重的安全隐患就是“数据是明文传输的”,登陆时传输的包括用户名和密码在内的全部信息都有可能会被恶意拦截而暴露。而SSH则是将登陆信息所有加密后进行传输的,所以使用SSH进行登陆时安全的,即便数据在传输过程当中被截获,里面的密码已经被加密而不会泄露。
如今SSH做为互联网安全的一个基本解决方案,已经在全世界得到推广,且目前已经成为Linux系统的标准配置。须要说明的是,SSH只是一种协议,它有多种软件实现,既有商业的,也有开源的。OpenSSH是当前使用最为普遍的一个SSH协议的开源实现。
其实SSH是充分利用了公钥加密/非对称机密 、对称加密 和 单向加密 来实现数据安全登陆的。在使用SSH进行通讯时,通讯过程分为如下几个步骤:
下面来看具体解析。
上面提到,SSH是经过对数据进行加密后进行传输来保证数据安全的。可是,SSH的数据加密采用的是对称加密算法,只是对称加密所使用的密钥是经过公钥加密/非对称加密实现加密后的安全传输的。另外,每台Linux机器都有本身的密钥对儿(一般放在/etc/ssh目录下),这个密钥对儿跟具体的用户无关。其工做流程是:
这样即使有人结果了帐号密码信息,也是密文信息,并不能知道里面是什么内容。貌似已经OK了,可是,主机A怎么验证主机B的身份呢?若是有主机C冒充主机B截获了登陆请求,将本身伪造的公钥发送给主机A,怎么办?尽管信息是加密过的,通讯过程也是合法的,可是通讯信息都被主机C截获了,其实这就是所谓的“中间人攻击”(Man-in-the-middle attack)。其实,对主机B进行验证就是对主机B发送过来的公钥的合法性进行验证的过程。
上面咱们提到过,验证公钥的合法性有两种方式:
SSH主要用于机器之间的安全登陆,所以一般不会经过权威的机构去签发证书,它主要是经过验证数据指纹的方式来验证公钥的合法性的。公钥的合法性验证是发生在主机A接收到主机B发送的公钥以后,主机A向主机B协商产生会话密钥以前,也就是上个部分所列举的数据机密时间的第2个步骤和第3个步骤之间。具体的工做流程以下:
每一个用户都有本身的kown_hosts文件,它们是相互独立的。咱们也能够为全部用户保存一份公共的可信赖的远程主机的公钥,这个文件一般是/etc/ssh/ssh_known_hosts。
当机器A接收到机器B的公钥指纹时,发现knowns_hosts文件中虽然有机器B的公钥,可是计算得出的公钥指纹与机器B发送过来的公钥指纹不一致。这确定是不一致的,由于每台机器的密钥对都是随机生成的,几乎不可能出现重复。所以,咱们会看到以下提示信息:
上面的大概意思是,主机A发现主机B的公钥指纹对不上了,怀疑咱们正在遭受中间人攻击(即有人在冒充主机B),而且密码验证方式和键盘交互验证方式都被禁止使用了。其实,咱们本身知道是由于IP被绑定到其余机器上引发的这个问题,因此咱们若是想继续登陆新的主机B,只须要在.ssh/known_hosts文件中把原来保存的主机B的公钥删掉就能够了。
你们都知道,SSH免密钥登陆是经过公钥认证的,用户登陆时只须要提供用户名,而不须要输入密码。其实其优势不止这一个,咱们来总结下:
其实登陆的过程就是被登陆端对登陆用户进行“身份验证”的过程,前面是经过帐号和密码来验证用户身份,由于密码应该只有该帐号的拥有者才知道。而咱们知道公钥加密算法中,用公钥加密的数据只能由与其配对的私钥才能解密,而私钥只有用户本身才有。那么,咱们是否能够经过这种方式来验证用户身份呢?实际上SSH免密钥登陆就是这样的原理。好比,咱们想在主机A上以root用户以SSH免密钥的方式登陆主机B,登陆验证过程是这样的:
root@192.168.1.2
),发送的信息包括用户名root和root的公钥指纹,且全部信息都是经过会话密钥加密过的。那么主机A是怎样获取root用户的私钥的呢?主机B又是怎样获取root用户的公钥的呢? 这个就是实现SSH免密钥登陆所要配置的内容:
ssh-keygen
命令生成一个ssh密钥对儿,一路回车就能够;生成的密钥对儿默认保存在当前登陆用户家目录下的.ssh目录,也能够指定保存目录。咱们当前是以root用户登陆,所以是保存在/root/.ssh目录:ssh root@hostB
进行登陆时,主机A会尝试读取登陆用户的家目录下的私钥文件(这里是以root用户登陆主机B,所以主机A会读取/root/.ssh/id_rsa文件做为私钥),也能够经过-i选项指定要使用的私钥文件;ssh-copy-id root@hostB
命令直接完成这个操做,也能够经过复制粘贴的方式来完成;咱们在管理git仓库中的项目时,可使用http/https协议,也可使用ssh协议来管理咱们的项目代码:
http/https协议:
http://192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git https://192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git
ssh协议:
ssh://git@192.168.1.1/GROUP_OR_USER/PROJECT_NAME.git
不管使用http/https协议仍是ssh协议来管理项目仓库,对于非公开的仓库都是须要进行登陆(即帐户身份验证)的。若是咱们使用http/https协议的话,就须要提供用户名和密码进行验证;若是咱们使用ssh协议的话,就能够把咱们公钥保存到项目仓库机器的指定位置,来经过非对称加密的方式进行身份验证,验证的原理上面已经详细说明过了。
HTTPS实际上就是HTTP协议和SSL/TSL协议的组合,能够把HTTPS大体理解为“HTTP over SSL”或“HTTP over TSL”。关于它们的相关介绍,能够参考这篇文章。对于HTTPS咱们应该有如下几个认知:
那么使用HTTPS与网站服务器进行交互的流程和原理究竟是怎样的呢?让咱们先以逆向思考的方式来进行说明:
咱们说过,公钥加密/非对称加密方式虽然安全,可是因为密钥过长,加密和解密速度都远远低于对称加密。所以,出于对性能方面的考虑,HTTPS并非把全部传输的数据都使用公钥加密的方式进行机密性的保护,而是继续使用对称加密的方式来加密数据。还有一个缘由就是,使用公钥机密算法来保证数据机密性的话,须要通讯双方都要有密钥对儿,不然总有一方发出的数据是能被对方公布的公钥解密的。
既然时使用对称加密的方式加密数据,就须要有一个通讯双方都知道的加解密所使用的密钥。HTTPS是经过上面提到的密钥交换技术来动态协商这个密钥的,实际上就是由客户端生成一个随机密钥,而后发送给服务器端,这样就解决了密钥的管理问题。
既然说HTTPS是安全的,那么客户端生成的这个随机密钥确定不能以明文的方式发送给服务器端啊。是的,当客户端以https的方式访问一个站点时,该站点会自动下发其公钥信息。客户端会使用这个公钥对产生的随机密钥进行加密,而后传送给服务器端。服务器端以本身的私钥对这个密文进行解密,而后获得这个密钥的明文内容。至此,客户端与服务端用于对称加密和解密的密钥协商与传输工做已经安全的完成了。
那么要经过网络获取服务器端的公钥信息,那么怎么验证该公钥信息的合法性呢?咱们上面说过,不是全部问题都能依赖技术来解决的。这里要验证公钥信息的合法性就要依靠CA证书签发机构了,网站服务的提供者必须找一个你们都信任的机构来对他提供的公钥进行签名,用户获得一个网站下发的公钥后看到有这个机构的签名就认为这个公钥是合法的,是可信赖的。
那么CA机构的签名要以什么样的形式来提供呢?实际上网站服务器下发给客户端(一般是浏览器)的公钥已经不只仅是密钥对儿中公钥的内容了,而是包含了证书签发机构写入的其余信息的CA证书。这个CA证书中包括证书签发机构的标识和公钥的数据指纹,固然还有包含网站服务提供者的公钥信息以及证书到期时间等等。可是,咱们前面提到过,单向加密只能保证数据的完整性,不能保证数据机密性。CA证书的伪造者彻底能够伪造公钥信息并生成相应的数据指纹,而后发送给用户。那么如今的问题就变成了要验证CA证书中公钥的合法性以及CA证书提供者的身份了。貌似问题只是转移了,而没有被解决。
其实每一个CA证书的签发机构也都有本身的密钥对儿,他们放在CA证书中的公钥的数据指纹时经过本身的私钥加密过的,而这些CA证书签发机构的公钥是被各浏览器厂商内置在浏览器内部的。当浏览器接收到某网站服务器下发的CA证书后会根据CA证书中签发机构的标识来读取浏览器内置的相应CA签发机构的公钥信息,经过这个公钥信息对公钥数据指纹的密文进行解密就能够获得CA证书中包含的公钥信息的真实数据指纹。浏览器再经过单向加密的方式本身计算一次CA证书中包含的公钥信息的数据指纹,两个数据指纹一致则说明这个CA证书确实是该CA机构签发的,同时也证实了CA证书中的公钥信息没有被篡改过。至此,全部的问题就都解决了。
如今咱们再来以正常的顺序描述一下使用HTTPS与网站服务器进行交互的过程: