hexo博客不知道出现什么缘故,deploy不上了。
由于这阵子的代码一直通过github desktop进行push。感觉很头疼。所以重新理解了一下github 的ssh机制。
果然书读百遍,其意自现,我已经掉入技术的大坑,如法自拔了:
我是看着这篇文章,讲自己的体会:https://www.cnblogs.com/diffx/p/9553587.html
1. 初见SSH
SSH是一种协议标准,其目的是实现安全远程登录以及其它安全网络服务。
SSH仅仅是一协议标准,其具体的实现有很多,既有开源实现的OpenSSH,也有商业实现方案。使用范围最广泛的当然是开源实现OpenSSH。
想法1:http和https的区别是什么?重点是https加了ssl协议,更加安全。ssl和ssh之间有什么联系吗?
2. SSH工作原理
在讨论SSH的原理和使用前,我们需要分析一个问题:为什么需要SSH?
从1.1节SSH的定义中可以看出,SSH和telnet、ftp等协议主要的区别在于安全性。这就引出下一个问题:如何实现数据的安全呢?首先想到的实现方案肯定是对数据进行加密。加密的方式主要有两种:
- 对称加密(也称为秘钥加密)
- 非对称加密(也称公钥加密)
所谓对称加密,指加密解密使用同一套秘钥。如下图所示:
Client:
Server:
对称加密的加密强度高,很难破解。但是在实际应用过程中不得不面临一个棘手的问题:如何安全的保存密钥呢?尤其是考虑到数量庞大的Client端,很难保证密钥不被泄露。一旦一个Client端的密钥被窃据,那么整个系统的安全性也就不复存在。为了解决这个问题,非对称加密应运而生。非对称加密有两个密钥:“公钥”和“私钥”。
两个密钥的特性:公钥加密后的密文,只能通过对应的私钥进行解密。而通过公钥推理出私钥的可能性微乎其微。
下面看下使用非对称加密方案的登录流程:
- 1.远程Server收到Client端用户TopGun的登录请求,Server把自己的公钥发给用户。
- 2.Client使用这个公钥,将密码进行加密。
- 3.Client将加密的密码发送给Server端。
- 4.远程Server用自己的私钥,解密登录密码,然后验证其合法性。
- 5.若验证结果,给Client相应的响应。
私钥是Server端独有,这就保证了Client的登录信息即使在网络传输过程中被窃据,也没有私钥进行解密,保证了数据的安全性,这充分利用了非对称加密的特性。
这样就一定安全了吗?
上述流程会有一个问题:Client端如何保证接受到的公钥就是目标Server端的?,如果一个攻击者中途拦截Client的登录请求,向其发送自己的公钥,Client端用攻击者的公钥进行数据加密。攻击者接收到加密信息后再用自己的私钥进行解密,不就窃取了Client的登录信息了吗?这就是所谓的中间人攻击
SSH中是如何解决这个问题的?
1. 基于口令的认证
从上面的描述可以看出,问题就在于如何对Server的公钥进行认证?在https中可以通过CA来进行公证,可是SSH的publish key和private key都是自己生成的,没法公证。(所以这里是说明了https的机制和ssh的机制不是一回事吗?)只能通过Client端自己对公钥进行确认。通常在第一次登录的时候,系统会出现下面提示信息:
The authenticity of host 'ssh-server.example.com (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)?
上面的信息说的是:无法确认主机ssh-server.example.com(12.18.429.21)的真实性,不过知道它的公钥指纹,是否继续连接?
之所以用fingerprint代替key,主要是key过于长(RSA算法生成的公钥有1024位),很难直接比较。所以,对公钥进行hash生成一个128位的指纹,这样就方便比较了。
如果输入yes后,会出现下面信息:
Warning: Permanently added 'ssh-server.example.com,12.18.429.21' (RSA) to the list of known hosts. Password: (enter password)
该host已被确认,并被追加到文件known_hosts中,然后就需要输入密码,之后的流程就按照图1-3进行。
想法:没错,我今天要deploy我的博客的时候,也出现了这些提示,只是我被服务器拒绝了- -(没有访问repo的权限,应该就是我本地的SSH keys出了问题??)。。。如下:
2.基于公钥认证
在上面介绍的登录流程中可以发现,每次登录都需要输入密码,很麻烦。SSH提供了另外一种可以免去输入密码过程的登录方式:公钥登录。流程如下:
- 1.Client将自己的公钥存放在Server上,追加在文件authorized_keys中。
- 2.Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
- 3.Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
- 4.Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
- 5.Server端会最后比较Digest1和Digest2是否相同,完成认证过程
在步骤1中,Client将自己的公钥存放在Server上。需要用户手动将公钥copy到server上。这就是在配置ssh的时候进程进行的操作。下图是GitHub上SSH keys设置视图:
想法:没错。刚开始配置github的时候,就需要在bash上输入命令生成key,然后到找~./ssh下的那个文件,然后把文件内的内容拷贝到github上。
所以,拷贝的是本地客户端生成的公钥 。
然后看到我id_ras.pub存放的公钥是这样的:
但是目前我的github上的ssh key是这样子的:
这俩根本就不一样。我也不知道发生了啥,也忘记了发生了啥。感觉是我整DeskTop的时候,改了什么东西。 所以我这里失败,应该就是本地请求连接的时候,发送了自己的公钥过去,然后服务器把接受的公钥和自己的authorized_keys比较,发现这个叫keneyr@163.com的用户,给的公钥不匹配。duang,就把我拒绝了?关键是这个连接请求是什么?是tcp三次握手的第一次握手的SYN=1的数据包吗?细节的东西,我想不到- -
3. SSH实践
生成密钥操作
经过上面的原理分析,下面三行命令的含义应该很容易理解了:
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys $ chmod 0600 ~/.ssh/authorized_keys
ssh-keygen是用于生产密钥的工具。
- -t:指定生成密钥类型(rsa、dsa、ecdsa等)
- -P:指定passphrase,用于确保私钥的安全
- -f:指定存放密钥的文件(公钥文件默认和私钥同目录下,不同的是,存放公钥的文件名需要加上后缀.pub)
首先看下面~/.ssh中的四个文件:
- 1.id_rsa:保存私钥
- 2.id_rsa.pub:保存公钥
- 3.authorized_keys:保存已授权的客户端公钥
- 4.known_hosts:保存已认证的远程主机ID(关于known_hosts详情,见文末更新内容)
四个角色的关系如下图所示:
需要注意的是:一台主机可能既是Client,也是Server。所以会同时拥有authorized_keys和known_hosts。
登录操作
# 以用户名user,登录远程主机host
$ ssh user@host
# 本地用户和远程用户相同,则用户名可省去
$ ssh host
# SSH默认端口22,可以用参数p修改端口
$ ssh -p 2017 user@host
4 总结
本文以图文方式对SSH原理进行解析(主要指远程登录,没有涉及端口转发等功能)。同时分析了非对称加密的特性,以及在实践过程中如何对加密操作进行改进。
1. known_hosts中存储的内容是什么?
known_hosts中存储是已认证的远程主机host key,每个SSH Server都有一个secret, unique ID, called a host key。
2. host key何时加入known_hosts的?
当我们第一次通过SSH登录远程主机的时候,Client端会有如下提示:
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?
此时,如果我们选择yes,那么该host key就会被加入到Client的known_hosts中,格式如下:
# domain name+encryption algorithm+host key
example.hostname.com ssh-rsa AAAAB4NzaC1yc2EAAAABIwAAAQEA。。。
3. 为什么需要known_hosts?
最后探讨下为什么需要known_hosts,这个文件主要是通过Client和Server的双向认证,从而避免中间人(man-in-the-middle attack)攻击,每次Client向Server发起连接的时候,不仅仅Server要验证Client的合法性,Client同样也需要验证Server的身份,SSH client就是通过known_hosts中的host key来验证Server的身份的。
这中方案足够安全吗?当然不,比如第一次连接一个未知Server的时候,known_hosts还没有该Server的host key,这不也可能遭到中间人攻击吗?这可能只是安全性和可操作性之间的折中吧。
看完以后我有几个问题:
1、在githhub上https方式(ssl)和ssh方式的区别是什么?
2、本地bash生成key以后,本地用户免密push上传下载,非常具体的底层细节是什么?具体到三次握手报文段那种。
3、Desktop和bash的方式有不同吗?它们共用一个key吗?
4、ssh和session、cookie有啥联系吗?
为了解决上述问题,我又开始生成key,然后尝试了一遍配置:
可以看到,本地的客户端,根据我的keneyr@163.com的账号id,生成了公钥和私钥。
我把公钥复制到了github的ssh页面上,复制的时候,还让我重新输入了登录密码:
然后github给我发了邮件:
这时我的客户端和服务器关于ssh的公钥私钥都已经配置完成。那么当我的客户端要上传我的文档或者代码到github时,应该的流程,就是:
- 1.Client将自己的公钥存放在Server上,追加在文件authorized_keys中。
- 2.Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
- 3.Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
- 4.Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
- 5.Server端会最后比较Digest1和Digest2是否相同,完成认证过程
认证过程完了以后,相当于是tcp三次握手已经完成,建立起了连接。
然后,客户端就开始发送code/文档的数据流到服务器,然后二者开始tcp通信了?
我测试了一下ssh登录连接到github,由于这时候相当于第一次ssh访问github。所以要获取github服务器给的公钥,然后把github 服务器的一些信息加载到known_hosts文件,SSH client就是通过known_hosts中的host key来验证Server的身份的。
那么那个github does not provide shell access啥意思呢?
在使用ssh加公钥认证时会输入 ssh -T Github.com,认证成功后会输出如下Log。
“but GitHub does not provide shell access ”这句话的意思是,GitHub不提供shell(ssh)访问/接入权限。
ssh -T选项的意思为,不分配伪终端。
当你在使用ssh协议连接到自己或者其他服务器时,本地终端会显示命令提示符,你可以在上面操作输入命令ls等。
结合上面几点,这句话的意思即为你无法使用ssh协议直接登录github,在github服务器上建立一个伪终端,并进行操作。
所以,这句提示并不是一个错误,而是github输出的一句提示语。
同样你可以在本地使用ssh协议进行git相关操作,并提交到github,没有任何影响。
所以这时候,我应该是配置完成了。那么ssl和ssh的区别是啥呢?我记得https每次都需要输入密码丫,ssh就免密登录了:
我又看了如下博客:
https://www.cnblogs.com/dzblog/p/6930147.html
https://www.cnblogs.com/ajianbeyourself/p/4220244.html
所以我认为ssl(https)和ssh是两种安全性协议,但是ssh和telnet这种远程登录主机是并列的。ssl是为了让客户访问服务器= =。
更通俗的说,SSH可以让用户以某个主机用户的身份登录主机,并对主机执行操作(即执行一些命令),目前用的最多的就是远程登录和SFTP(还有简易版的SCP);而SSL和主机用户名登录没有任何关系,它本身并不实现主机登录的功能,它只的一个单纯的加密功能。为了方便理解,可以简单的认为SSH=SSL+主机用户登录功能等应用层协议
它们的是应用层,传输层还是TCP!!!什么tcp三次握手,四次挥手少不了!!!
关键是session和cookie和ssl、ssh有关系么?我又看了如下博客:
https://www.zhihu.com/question/19786827
目前的理解是这样的:
session和cookie是为了记录用户会话,cookie存储在本地,像我的浏览器,我通常第一次登录以后,第二天登录就不想要输入密码,直接就在状态了,这就是cookie存储了我的账号和密码。session是服务器存储的,服务器要为特定的用户创建session,用用于标识这个用户,并且跟踪用户,知道这个用户的购物车里面有几本书。
每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。
所以session和cookie可以理解为追踪。
ssl和ssh似乎跟他们不沾边,可以认为这俩是对账号密码进行加密的,一种“算法”。为了安全。