SSH key的生成与使用

Published: by Creative Commons Licence

SSH key的生成与使用

先来了解什么是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服务端和客户端程序

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

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

如果仅是作为ssh客户端,在Linux中直接使用ssh命令即可;在Windows中有免费的putty、PuTTY TrayBitvise的ssh client(功能最多)等程序可供选择。Xshell这种我就不做考虑了(2017年被爆多版本存在后门);至于SecureCRT就算了吧。

SSH Key

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

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

使用SSH key的步骤:

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

生成密钥对

运行命令ssh-keygen采用rsa加密算法生成密钥对

ssh-keygen -t rsa

生成密钥对时,有一个选项要求你设置密码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 4096

$ ssh-keygen -t rsa -C "your_email@example.com" -b 4096
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

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

实际操作的一次示例:

[fan 16:10:57]~$ ssh-keygen -t rsa -C "Fan@outlook.com" -b 4096
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 4096]----+
|   .+... .       |
|   +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时自行输入路径和文件名称,而非使用默认路径和文件名即可。

# 比如,输入绝对路径加文件名来指定
/home/fan/.ssh/gitlab_rsa

使用非默认的SSH key

对于OpenSSH客户端(Linux默认安装),需要在 ~/.ssh/config 文件中进行配置。

为不同服务器的同一用户配置不同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
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


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

配置多个账户

为同一服务器配置不同账户,比如说你在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 密钥对进行登录的时候,您都必须输入正确的密码短语。
而 SSH agent 程序能够将您的已解密的私钥缓存起来,在需要的时候提供给您的 SSH 客户端。这样子,您就只需要将私钥加入 SSH agent 缓存的时候输入一次密码短语就可以了。这为您经常使用 SSH 连接提供了不少便利。
SSH agent 一般会设置成在登录会话的时候自动启动,并在整个会话中保持运行。有不少的 SSH agent 供您选择,我们将为您介绍几种常用的 SSH agent,您可以根据您的需要进行选择。

  • ssh-agent 是 OpenSSH 自带的一个 SSH agent
  • GnuPG agent也许想要 GnuPG 来缓存您的私钥。当然咯,有些用户比较喜欢在 GnuPG 对话框来输入 PIN 码,这样子管理密码短语也是不错的选择。
  • Keychain 是一个用来方便管理 SSH 密钥对的程序,它能尽最大努力去减少对用户的打扰。

Pro Git: 7.14 Git 工具 - 凭证存储 Git自带有一个独立的凭证辅助工具。

如何使用 Seahorse 管理 PGP 和 SSH 密钥

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

SSH服务器使用非标准port时的解决办法

这里是对于自建的git服务

sshd使用标准的port:

$ git remote add origin git@localhost:TestGroup/Test.git

sshd使用非标端口时的方法:

# ssh使用非标准端口时的方法(这里是2200端口)
# 方法1 (失败)
$ git remote add origin git@localhost:2200/TestGroup/Test.git
# 方法2:使用ssh的形式;root为操作系统账号,端口与路径之间没有空格,路径为完整路径
$ git remote add origin ssh://root@127.0.0.1:2200/var/opt/gitlab/git-data/repositories/TestGroup/Test.git
# 方法3:使用http;输入该仓库用户的GitLab的用户名和密码
$ git remote add origin http://127.0.0.1:8081/TestGroup/Test.git
# 方法4:在配置文件中配置

git remote add with other SSH port

示例:

################## 实际操作 ################
[fan 23:31:12]~/backup$ git remote add origin git@127.0.0.1:TestGroup/Test.git
[fan 23:32:24]~/backup$ git push -u origin --all
ssh: connect to host 127.0.0.1 port 22: Connection refused
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

[fan 23:37:38]~/backup$ git remote add origin git@127.0.0.1:2200/TestGroup/Test.git
fatal: 远程 origin 已经存在。
[fan 00:33:38]~/backup$ git remote rm origin

-----

[fan 00:32:59]~/backup$ git remote add origin ssh://root@127.0.0.1:2200/TestGroup/Test.git
[fan 00:33:25]~/backup$ git push -u origin --all
fatal: '/TestGroup/Test.git' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
[fan 00:33:38]~/backup$ git remote rm origin
[fan 00:34:12]~/backup$ git remote add origin ssh://root@127.0.0.1:2200/var/opt/gitlab/git-data/repositories/TestGroup/Test.git
[fan 00:34:21]~/backup$ git push -u origin --all
对象计数中: 131, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (129/129), 完成.
写入对象中: 100% (131/131), 1.26 MiB | 0 bytes/s, 完成.
Total 131 (delta 15), reused 0 (delta 0)
remote: GitLab: You are not allowed to upload code for this project.
To ssh://root@127.0.0.1:2200/var/opt/gitlab/git-data/repositories/TestGroup/Test.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: 无法推送一些引用到 'ssh://root@127.0.0.1:2200/var/opt/gitlab/git-data/repositories/TestGroup/Test.git'

# 莫非是我的ssh key有问题?尝试重新按照官方教程生成ssh key。还是说是下面链接中说的git版本问题?
# 最终原因: 是使用git协议有问题,而使用http则可以

[fan 01:05:30]~/backup$ git remote add origin http://127.0.0.1:8081/TestGroup/Test.git
[fan 01:08:25]~/backup$ git push -u origin master
Username for 'http://127.0.0.1:8081': Fan
Password for 'http://Fan@127.0.0.1:8081': 
对象计数中: 131, 完成.
Delta compression using up to 4 threads.
压缩对象中: 100% (129/129), 完成.
写入对象中: 100% (131/131), 1.26 MiB | 0 bytes/s, 完成.
Total 131 (delta 15), reused 0 (delta 0)
remote: Resolving deltas: 100% (15/15), done.

To http://127.0.0.1:8081/TestGroup/Test.git
 * [new branch]      master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。

remote rejected错误原因

最终原因: 是GitHub使用git协议有问题,而使用http则可以。

学习资料

了解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

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