重新理解github ssh

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 keyprivate 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似乎跟他们不沾边,可以认为这俩是对账号密码进行加密的,一种“算法”。为了安全。

 

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页