SSH key的介绍与在Git中的使用

有必要先来了解什么是SSH和什么是SSH key。

SSH

Secure Shell (SSH) 是一个允许两台电脑之间通过安全的连接进行数据交换的网络协议。通过加密保证了数据的保密性和完整性。SSH采用公钥加密技术来验证远程主机,以及(必要时)允许远程主机验证用户。

传统的FTP、Telnet是再网络中明文传送数据、用户帐号和密码,很容易受到中间人攻击。

SSH是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用SSH协议可以有效防止远程管理过程中的信息泄露问题。通过SSH可以对所有传输的数据进行加密,也能够防止DNS欺骗和IP欺骗。

      ssh客户端(ssh)                       ssh服务端(sshd)

     +----------+                       +---------+
     |          |                       |         |
     |          |                       |         |
     |          |                       |         |
     |          |                       |         |
     +---+---+--+                       +-+---+---+
         |   |                            |   |
         |   |                            |   |
         |   +----------------------------+   |
         |                                    |
         |        ssh加密了的TCP通信            |
         +------------------------------------+

                    SSH连接

SSH只是一种协议,其开源实现有OpenSSH程序。

首发于: SSH-key的生成与在Git中的使用

SSH服务端和客户端程序

OpenSSH (OpenBSD Secure Shell) 是一套使用ssh协议,通过计算机网络,提供加密通讯会话的计算机程序

如果需要作为ssh的服务端,则需要安装openssh。

如果仅是作为ssh客户端,在Linux中直接使用ssh命令即可。

Windows中的ssh客户端程序有:

  • Putty
  • PuTTY Tray(Putty的加强版)
  • Bitvise 的 ssh client (功能多,免费)
  • Xshell (2017年被爆多版本存在后门)
  • SecureCRT(算了吧)
  • Cmder(开源的命令行工具,并且集成了Git for Windows和多个Unix命令,cmder的使用可参考 Cmder - 简书 里面有讲到ssh agent的配置)

SSH Key

SSH 密钥对 最直观的作用:让你方便的登录到 SSH 服务器,而无需输入密码。由于你无需发送你的密码到网络中,SSH 密钥对被认为是更加安全的方式。

原因是:SSH利用SSH Key来进行前面提到的基于密钥的安全验证。

使用SSH key的步骤:

  • 在客户端生成SSH key(密钥对:公钥和私钥)
  • 在服务端的配置文件中加入你的公钥。(比如我们需要再GitHub中粘贴你的公钥)

生成密钥对

ssh-keygen命令用于为ssh生成、管理和转换认证密钥,它支持RSA和DSA两种认证密钥。

该命令的选项:

-b:指定密钥长度;
-e:读取openssh的私钥或者公钥文件;
-C:添加注释;
-f:指定用来保存密钥的文件名;
-i:读取未加密的ssh-v2兼容的私钥/公钥文件,然后在标准输出设备上显示openssh兼容的私钥/公钥;
-l:显示公钥文件的指纹数据;
-N:提供一个新密语;
-P:提供(旧)密语;
-q:静默模式;
-t:指定要创建的密钥类型。

生成密钥对时,有一个选项要求你设置密码(passphrase),该密码是用来保护你的私钥的密码。如果设置了则在使用私钥时会要求你输入这个密码;一般不设置,记不住【之后还可更改此密码,使用ssh-keygen -p】。

生成后最好将私钥进行备份。另还有-C选项,用于为指定注释,通常使用自己的邮件名作为注释

-b bits选项 Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 2048 bits. Generally, 2048 bits is considered sufficient. DSA keys must be exactly 1024 bits

示例:为了安全考虑使用RSA加密方式并指定密钥长度 -b 2048(1024的密钥长度能够被破解,建议指定为2048或4096)。

$ ssh-keygen -t rsa -C "your_email@example.com" -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key
(/Users/your_user_directory/.ssh/id_rsa): 按回车键 (如果需要生成多对key,则输入/home/users/.ssh/filename)
Enter passphrase (empty for no passphrase): 输入密码(一般不输入密码,直接回车)
Enter same passphrase again: 再次输入密码
...

# 查看公钥文件中的内容
$ cat ~/.ssh/id_rsa.pub
ssh-rsa "公钥内容" your_email@example.com

# 注意在其他地方导入公钥时一定要将公钥文件中的*全部内容*都导入,包括末尾你的邮箱。

实际操作的一次示例:

$ ssh-keygen -t rsa -C "Fan@outlook.com" -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/home/fan/.ssh/id_rsa): /home/fan/.ssh/FDGitHub_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/fan/.ssh/FDGitHub_rsa.
Your public key has been saved in /home/fan/.ssh/FDGitHub_rsa.pub.
The key fingerprint is:
SHA256:GcK7ORvFzH6fzA7qPmnzBr1DOWho5cCVgIpLkh6VGb8 Fan@outlook.com
The key's randomart image is:
+---[RSA 2048]----+
|   .+... .       |
|   +o.  o        |
| o.. oo..        |
|+o.   +*.o       |
|+..  E.=So .     |
|..    o== =      |
|     .=..+oo     |
|       +=o+= .   |
|      .++=.o*    |
+----[SHA256]-----+

公钥是一串很长的字符;为了便于肉眼比对和识别,所以有了指纹这东西;指纹位数短,更便于识别且与公钥一一对应。

公钥加密指纹fingerprint有两种形式:

  • 之前的十六进制形式:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
  • 现在使用sha256哈希值并且使用base64进行格式:SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8

指纹的用处之一是在使用SSH第一次连接到某主机时,会返回该主机使用的公钥的指纹让你识别。示例:

The authenticity of host '某主机名' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)?

简单介绍一下:

公钥用于给别人用来加密文件。公钥就是一把锁,你把锁给别人,他用锁锁住东西后,除了你自己外其他人是没有钥匙(私钥)的,都无法打开。配对的私钥就是钥匙。

必须保证使用你的公钥的人明确知道这个公钥一定是你的。你可以在网站或通过其它方式公布你的公钥,以便他人进行对照确认。由于公钥很长,所以有了对应的指纹(指纹更易辨别,位数更少),可以通过指纹进行对照(公布指纹)。

如何创建多个ssh key而不是覆盖默认文件

在创建ssh key时自行输入路径和文件名称,而非使用默认路径和文件名即可。

或者使用 -f来指定文件名

ssh-keygen -t rsa -C "your_secondemail@email.com" -f ~/.ssh/second-rsa

使用非默认的SSH key

对于OpenSSH客户端(Linux默认安装),需要在 ~/.ssh/config 文件中进行配置(如果没有该文件则自行创建一个)。

分为如下两种情况。

1.为不同服务器的同一用户配置不同SSH key

好吧,这里同一用户在不同服务器上是可以使用同一个SSH key

Working with non-default SSH key pair paths

比如:你在GitLab上粘贴的公钥(Public SSH keys)不是默认的密钥对;此时要想让你的ssh client正常与GitLab服务器通信,必须对ssh client进行配置,当通信对象为GitLab服务器主机时,使用哪个私钥(SSH private key)。

注意:这里使用公钥也是可以的

示例:

# GitLab.com server
Host gitlab.com
# 如果提示: Unsupported option "rsaauthentication",则可以选择注释掉该行
RSAAuthentication yes
IdentityFile ~/.ssh/private-key-filename-01

# Private GitLab server
Host gitlab.company.com
RSAAuthentication yes
IdentityFile ~/.ssh/private-key-filename

对于GitLab等:上传到GitLab服务器中的SSH公钥只能属于单个用户,你的SSH密钥是您通过SSH推送代码时的标识符;它需要唯一映射到单个用户。也就是说,一个公钥在该服务器上只能被一个账户使用;但是你可以在不同的服务器上使用同一个密钥对,也可以在不同服务器上分别使用不同的密钥对。

GitHub使用非默认密钥对:

Host github.com
RSAAuthentication yes
# 也可以使用公钥
IdentityFile ~/.ssh/FDGitHub_rsa.pub

配置完成后可以使用如下命令测试连接:

# 测试时替换掉 example.com
ssh -T git@example.com
# 例如 gitlab
ssh -T git@gitlab.com
# 例如 github
ssh -T git@github.com
# 例如 coding
ssh -T git@git.coding.net
# 例如 码云
ssh -T git@gitee.com
# bitbucket
ssh -T git@bitbucket.org

# 也可以使用下面的命令来调试连接
ssh -Tv git@example.com

如果测试时出现如下提示: Unsupported option "rsaauthentication",则可以选择忽略或注释掉配置文件中的 RSAAuthentication yes行。

2.配置多个账户

为同一服务器配置不同账户,比如说你在coding上有两个账户,那么可以这样在config文件中配置:

# coding
Host git.coding.net
User your_email@example.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa  //默认的私钥

# second
Host git.coding.net
User youre_secondemail@example.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/second_rsa  // 生成的第二个私钥

SSH agent

ssh-agent命令是一种控制用来保存公钥身份验证所使用的私钥的程序。在Linux中ssh-agent 在X会话登录会话之初启动,所有其他窗口或程序则以客户端程序的身份启动并加入到ssh-agent程序中。通过使用环境变量,可定位代理并在登录到其他使用ssh机器上时使用代理自动进行身份验证。

其实ssh-agent就是一个密钥管理器,运行ssh-agent以后,使用ssh-add命令将私钥交给ssh-agent保管,其他程序需要身份验证的时候可以将验证申请交给ssh-agent来完成整个认证过程。

另外如果您的私钥使用密码短语来加密了的话,每一次使用 SSH 密钥对进行登录的时候,您都必须输入正确的密码短语。而 SSH agent 程序能够将您的已解密的私钥缓存起来,在需要的时候提供给您的 SSH 客户端。这样子,您就只需要将私钥加入 SSH agent 缓存的时候输入一次密码短语就可以了。这为您经常使用 SSH 连接提供了不少便利。

有不少的 SSH agent 供您选择,我们将为您介绍几种常用的 SSH agent,您可以根据您的需要进行选择。

  • ssh-agent 是 OpenSSH 自带的一个 SSH agent
  • GnuPG agent也许想要 GnuPG 来缓存您的私钥。当然咯,有些用户比较喜欢在 GnuPG 对话框来输入 PIN 码,这样子管理密码短语也是不错的选择。

ssh agent带来的问题

在Linux中我并没有遇到过因 ssh-agent 而带来的问题,这里说一下Windows中使用ssh时遇到的相关问题。

尝试通过SSH进行身份验证时,您可能会看到以下错误消息 :

当尝试使用Git并通过SSH协议进行 clone, push,或 pull时,如果Github无法使用SSH agent提供的密钥进行身份验证,则可能会收到下面的某一条消息:

  • Permission denied (publickey)
  • No suitable response from remote
  • repository access denied

可能的原因:

  • 你的 公钥 并没有添加到服务器端。

  • 您的密钥未加载到ssh agent中 。(如果您的SSH代理不知道为Bitbucket提供密钥,则连接将失败。如果您最近重新启动了系统,则可能会遇到此问题。 )解决方法:

    • 检查相应的 ssh key 是否被加载:

      ssh-add -l
      
    • 如果没有被加载,则使用下面的命令加载私钥

      #后面可以同时跟多个私钥
      ssh-add ~/.ssh/<private_key_file>  
      
    • 如果提示 "Could not open a connection to your authentication agent." 说明你的ssh agent并没有运行;使用下面的命令运行ssh agent,再使用ssh-add命令添加你的ssh key。

      # macOS/Linux
      $ eval `ssh-agent`
      
      # 在Windows中的git-bash中
      $ eval $(ssh-agent) 
      

还有个注意点,就是不要同时运行多个 ssh agent,可通过任务管理器或 ps命令进行查看。

Github/GitLab中使用SSH

Github/GitLab中为什么会用到SSH?

Using the SSH protocol, you can connect and authenticate to remote servers and services. With SSH keys, you can connect to GitHub without supplying your username or password at each visit.

使用SSH协议,您可以连接和验证远程服务器和服务。

使用SSH密钥,您可以连接到GitHub,而无需在每次访问时提供用户名或密码。

GitHub/GitLab 中导入SSH Key

SSH Key导入:导入过程比较简单。

GitHub: 点击用户头像 > Setting > SSH and GPG keys > New SSH key > 粘贴你生成的公钥(简单的方法是用文本编辑器打开公钥文件然后复制)。

访问远程仓库时可以选择 SSH 或者 HTTPS协议进行访问。

(比如,与gitlab 远程仓库进行进行安全认证可选择使用ssh或者https),两者的表现形式:

SSH  git@gitlab.com:faner/test01.git
HTTPS  https://gitlab.com/faner/test01.git

当你选择HTTPS时,会看到它有下面的一段提示"Create a personal access token on your account to pull or push via Https"简单的翻译一下就是"在您的帐户上创建个人访问令牌,以通过Https进行pull或push",并且在你第一次将本地仓库push到远程仓库时会要求你输入gitlab的用户名和密码。

经验:由于我的ssh的config文件出现配置错误,并且ssh-agent也未运行,当我选择git@gitlab.com:faner/test01.git时提示有有误(当时的情况就是使用ssh无法认证)

我就尝试使用了https的https://gitlab.com/faner/test01.git路径,之后就让我输入密码并成功连接。

那么现在您已经设置了SSH密钥,在下次克隆存储库时可以使用SSH 的 URL。如果您已经拥有通过HTTPS克隆的存储库,可以将存储库的远程URL更改为其SSH URL 。

从用户操作上来看,HTTPS需要用户输入远程仓库的用户名和密码,比如需要输入gitlab的帐号和密码;SSH无需输入用户和密码。

问题:生成ssh key所使用的邮箱是否需要和本地git设置的邮箱相同?
本地git中配置的用户名和邮箱会随同提交日志被公开到GitHub上,而非生成ssh key时使用的邮箱。

学习资料

了解SSH的最好方式是参见维基百科中的条目:Secure Shell - 维基百科,自由的百科全书

这里是部分引用:

中间人攻击:就是存在另一个人或者一台机器冒充真正的服务器接收用户传给服务器的数据,然后再冒充用户把数据传给真正的服务器。

SSH协议框架中最主要的部分是三个协议:

  1. 传输层协议(The Transport Layer Protocol):传输层协议提供服务器认证,数据机密性,信息完整性等的支持。
  2. 用户认证协议(The User Authentication Protocol):用户认证协议为服务器提供客户端的身份鉴别。
  3. 连接协议(The Connection Protocol):连接协议将加密的信息隧道复用成若干个逻辑通道,提供给更高层的应用协议使用。

在客户端来看,SSH提供两种级别的安全验证:

  • 第一种级别(基于密码的安全验证),知道帐号和密码,就可以登录到远程主机,并且所有传输的数据都会被加密。但是,可能会有别的服务器在冒充真正的服务器,无法避免被“中间人”攻击。
  • 第二种级别(基于密钥的安全验证),需要依靠密钥,也就是你必须为自己创建一对密钥,并把公有密钥放在需要访问的服务器上。客户端软件会向服务器发出请求,请求用你的密钥进行安全验证。服务器收到请求之后,先在你在该服务器的用户根目录下寻找你的公有密钥,然后把它和你发送过来的公有密钥进行比较。如果两个密钥一致,服务器就用公有密钥加密“质询”(challenge)并把它发送给客户端软件。从而避免被“中间人”攻击。

在服务器端,SSH也提供安全验证:

在第一种方案中,主机将自己的公用密钥分发给相关的客户端,客户端在访问主机时则使用该主机的公开密钥来加密数据,主机则使用自己的私有密钥来解密数据,从而实现主机密钥认证,确保数据的保密性。 在第二种方案中,存在一个密钥认证中心,所有提供服务的主机都将自己的公开密钥提交给认证中心,而任何作为客户端的主机则只要保存一份认证中心的公开密钥就可以了。在这种模式下,客户端必须访问认证中心然后才能访问服务器主机。

必看: Secure Shell - 维基百科,自由的百科全书

如果要详细了解,请认真参考:SSH keys (简体中文)
实战:Connecting to GitHub with SSH
Readme · Ssh · Help · GitLab
配置 SSH 公钥访问代码仓库 – CODING 帮助中心
Bitbucket上列出了各种ssh相关问题和解决方法:Troubleshoot SSH issues - Atlassian Documentation

强烈建议学习的几篇SSH文章:
阮一峰:
SSH原理与运用(一):远程登录
SSH原理与运用(二):远程操作与端口转发
Asrchlinux wiki:
Secure Shell (简体中文)
SSH keys (简体中文)

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 87,413评论 13 122
  • 简介 SSH(Secure Shell)是一个提供数据通信安全、远程登录、远程指令执行等功能的安全网络协议,由芬兰...
    LeiLv阅读 545评论 0 1
  • 2018-Read-Record 记录我的2018学习历程 文中首先解释了加密解密的一些基础知识和概念,然后通过一...
    NinthDay阅读 7,060评论 9 96
  • 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现...
    纳兰三少阅读 621评论 1 6
  • 最喜这样的季节。天气晴好,阳光越加灿烂与明媚了。 校园里,茶花开得最艳,红似火,白似雪,争先恐后地盛开着;朵朵含笑...
    jean000777阅读 113评论 0 2