SSH教程
SSH 是 Linux 系统的登录工具,现在广泛用于服务器登录和各种加密通信。
SSH基本知识
SSH(Secure Shell 的缩写)是一种网络协议,用于加密两台计算机之间的通信,并且支持各种身份验证机制。
实务中,它主要用于保证远程登录和远程通信的安全,任何网络服务都可以用这个协议来加密。
1、SSH是什么
历史上,网络主机之间的通信是不加密的,属于明文通信。这使得通信很不安全,一个典型的例子就是服务器登录。登录远程服务器的时候,需要将用户输入的密码传给服务器,如果这个过程是明文通信,就意味着传递过程中,线路经过的中间计算机都能看到密码,这是很可怕的。
SSH 就是为了解决这个问题而诞生的,它能够加密计算机之间的通信,保证不被窃听或篡改。它还能对操作者进行认证(authentication)和授权(authorization)。明文的网络协议可以套用在它里面,从而实现加密。
2、历史
1995年,芬兰赫尔辛基工业大学的研究员 Tatu Ylönen 设计了 SSH 协议的第一个版本(现称为 SSH 1),同时写出了第一个实现(称为 SSH1)。
OpenSSH 随 OpenBSD 2.6 版本一起提供,以后又移植到其他操作系统,成为最流行的 SSH 实现。目前,Linux 的所有发行版几乎都自带 OpenSSH。
3、SSH架构
SSH 的软件架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH 软件分成两个部分:
- 向服务器发出请求的部分,称为客户端(client),OpenSSH 的实现为 ssh;
- 接收客户端发出的请求的部分,称为服务器(server),OpenSSH 的实现为 sshd。
本教程约定,大写的 SSH 表示协议,小写的 ssh 表示客户端软件。
另外,OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp)
SSH客户端
1、简介
OpenSSH 的客户端是二进制程序 ssh。
1.1 Windows 系统的位置是\Program Files\OpenSSH\bin\ssh.exe
。【Win10中自带OpenSSH,在设置->应用->可选功能中开启,安装后在:C:\Windows\System32\OpenSSH】
利用ssh连接远程服务器:在windows上cmd,然后ssh 主机用户@主机ip直接连到远程,很方便
eg:ssh root@192.168.xx.yy
输入密码即可登录成功。
1.2 Linux 系统一般都自带 ssh,如果没有就需要安装。它在 Linux/Unix 系统的位置是/usr/local/bin/ssh
,
# Ubuntu 和 Debian
$ sudo apt install openssh-client
# CentOS 和 Fedora
$ sudo dnf install openssh-clients
安装以后,可以使用-V
参数输出版本号,查看一下是否安装成功。
$ ssh -V
2、基本用法
ssh 最常见的用途就是登录服务器,这要求服务器安装并正在运行 SSH 服务器软件。
ssh 登录服务器的命令如下。
$ ssh hostname
上面命令中,hostname
是主机名,它可以是域名,也可能是 IP 地址或局域网内部的主机名。不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。如果要指定用户名,可以采用下面的语法。
$ ssh user@hostname
上面的命令中,用户名和主机名写在一起了,之间使用@
分隔。
用户名也可以使用ssh
的-l
参数指定,这样的话,用户名和主机名就不用写在一起了。
$ ssh -l username host
ssh 默认连接服务器的22端口,-p
参数可以指定其他端口。
$ ssh -p 8821 foo.com
上面命令连接服务器foo.com
的8821端口。
3、连接流程
ssh 连接远程服务器后,首先有一个验证过程,验证远程服务器是否为陌生地址。
如果是第一次连接某一台服务器,命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接。
The authenticity of host 'foo.com (192.168.121.111)' can't be established.
ECDSA key fingerprint is SHA256:Vybt22mVXuNuB5unE++yowF7lgA/9/2bLSiO3qmYWBY.
Are you sure you want to continue connecting (yes/no)?
上面这段文字告诉用户,foo.com
这台服务器的指纹是陌生的,让用户选择是否要继续连接(输入 yes 或 no)。
所谓“服务器指纹”,指的是 SSH 服务器公钥的哈希值。每台 SSH 服务器都有唯一一对密钥,用于跟客户端通信,其中公钥的哈希值就可以用来识别服务器。
下面的命令可以查看某个公钥的指纹(哈希值)。
$ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 da:24:43:0b:2e:c1:3f:a1:84:13:92:01:52:b4:84:ff (ECDSA)
上面的例子中,ssh-keygen -l -f
命令会输出公钥/etc/ssh/ssh_host_ecdsa_key.pub
的指纹。
ssh 会将本机连接过的所有服务器公钥的指纹,都储存在本机的~/.ssh/known_hosts
文件中【windows上位于 C:\Users\用户名\.ssh ,存的是公钥】。每次连接服务器时,通过该文件判断是否为陌生主机(陌生公钥)。
在上面这段文字后面,输入yes
,就可以将当前服务器的指纹也储存在本机~/.ssh/known_hosts
文件中,并显示下面的提示。以后再连接的时候,就不会再出现警告了。
Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts
然后,客户端就会跟服务器建立连接。接着,ssh 就会要求用户输入所要登录账户的密码。用户输入并验证密码正确以后,就能登录远程服务器的 Shell 了。
之后重新连接就不会提示不认识这台机器了。
4、服务器秘钥变更
服务器指纹可以防止有人恶意冒充远程主机。如果服务器的密钥发生变更(比如重装了 SSH 服务器),客户端再次连接时,就会发生公钥指纹不吻合的情况。这时,客户端就会中断连接,并显示一段警告信息。
这时,你需要确认是什么原因,使得公钥指纹发生变更,到底是恶意劫持,还是管理员变更了 SSH 服务器公钥。
5、ssh命令行配置项
-c
-c
参数指定加密算法。
$ ssh -c blowfish,3des server.example.com
# 或者
$ ssh -c blowfish -c 3des server.example.com
上面命令指定使用加密算法blowfish
或3des
。
-C
-C
参数表示压缩数据传输。
$ ssh -C server.example.com
等等...
SSH密钥登录
SSH 默认采用密码登录,这种方法有很多缺点,简单的密码不安全,复杂的密码不容易记忆,每次手动输入也很麻烦。密钥登录是更好的解决方案。
1、密钥是什么
密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。
SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。
如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。
2、密钥登录的过程
SSH 密钥登录分为以下的步骤。
预备步骤,客户端通过ssh-keygen
生成自己的公钥和私钥。
第一步,手动将客户端的公钥放入远程服务器的指定位置。
第二步,客户端向服务器发起 SSH 登录的请求。
第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。
第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。
3、ssh-key
命令:生成密钥
3.1 基本用法
密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen
命令,用来生成密钥。
直接输入ssh-keygen 【注意要用管理员权限登录 cmd】
,程序会询问一系列问题,然后生成密钥。
通常做法是使用-t
参数,指定密钥的加密算法。
$ ssh-keygen -t dsa
上面示例中,-t
参数用来指定密钥的加密算法,一般会选择dsa
算法或rsa
算法。注意,这个参数没有默认值。
输入上面的命令以后,ssh-keygen
会要求用户回答一些问题。
$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_dsa): press ENTER
Enter passphrase (empty for no passphrase): ********
Enter same passphrase again: ********
Your identification has been saved in /home/username/.ssh/id_dsa.
Your public key has been saved in /home/username/.ssh/id_dsa.pub.
The key fingerprint is:
14:ba:06:98:a8:98:ad:27:b5:ce:55:85:ec:64:37:19 username@shell.isp.com
第一个问题,询问密钥保存的文件名,默认是~/.ssh/id_dsa
文件,这个是私钥的文件名,对应的公钥文件~/.ssh/id_dsa.pub
是自动生成的。用户的密钥一般都放在主目录的.ssh
目录里面。
如果选择rsa
算法,生成的密钥文件默认就会是~/.ssh/id_rsa
(私钥)和~/.ssh/id_rsa.pub
(公钥)。
接着,就会是第二个问题,询问是否要为私钥文件设定密码保护(passphrase)。这样的话,即使入侵者拿到私钥,还是需要破解密码。如果为了方便,不想设定密码保护,可以直接按回车键,密码就会为空。后面还会让你再输入一次密码,两次输入必须一致。注意,这里“密码”的英文单词是 passphrase,这是为了避免与 Linux 账户的密码单词 password 混淆,表示这不是用户系统账户的密码。
最后,就会生成私钥和公钥,屏幕上还会给出公钥的指纹,以及当前的用户名和主机名作为注释,用来识别密钥的来源。
公钥文件和私钥文件都是文本文件,可以用文本编辑器看一下它们的内容。公钥文件的内容类似下面这样。
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com
上面示例中,末尾的username@shell.isp.com
是公钥的注释,用来识别不同的公钥,表示这是哪台主机(shell.isp.com
)的哪个用户(username
)的公钥,不是必需项。
下面的命令可以列出用户所有的公钥。
$ ls -l ~/.ssh/id_*.pub
生成密钥以后,建议修改它们的权限,防止其他人读取。
$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub
3.2 配置项
ssh-keygen
的命令行配置项,主要有下面这些。
(1)-b
-b
参数指定密钥的二进制位数。这个参数值越大,密钥就越不容易破解,但是加密解密的计算开销也会加大。
一般来说,-b
至少应该是1024
,更安全一些可以设为2048
或者更高。
......
4、手动上传公钥
生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。
OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys
文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys
文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。
用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。
$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
上面示例中,user@host
要替换成你所要登录的用户名和主机名。
注意,authorized_keys
文件的权限要设为644
,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。
$ chmod 644 ~/.ssh/authorized_keys
【说明:服务器上SSH服务不用重启】
只要公钥上传到服务器,下次登录时,OpenSSH 就会自动采用密钥登录,不再提示输入密码。
$ ssh -l username shell.isp.com
Enter passphrase for key '/home/you/.ssh/id_dsa': ************
Last login: Mon Mar 24 02:17:27 2014 from ex.ample.com
shell.isp.com>
上面例子中,SSH 客户端使用私钥之前,会要求用户输入密码(passphrase),用来解开私钥。
5、ssh-copy-id 命令:自动上传公钥
OpenSSH 自带一个ssh-copy-id
命令【但是windows上的openssh不自带,需要另外下载】,可以自动将公钥拷贝到远程服务器的~/.ssh/authorized_keys
文件。如果~/.ssh/authorized_keys
文件不存在,ssh-copy-id
命令会自动创建该文件。
用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器。
$ ssh-copy-id -i key_file user@host
上面命令中,-i
参数用来指定公钥文件,user
是所要登录的账户名,host
是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。
注意,公钥文件可以不指定路径和.pub
后缀名,ssh-copy-id
会自动在~/.ssh
目录里面寻找。
$ ssh-copy-id -i id_rsa user@host
上面命令中,公钥文件会自动匹配到~/.ssh/id_rsa.pub
。
ssh-copy-id
会采用密码登录,系统会提示输入远程服务器的密码。
注意,ssh-copy-id
是直接将公钥添加到authorized_keys
文件的末尾。如果authorized_keys
文件的末尾不是一个换行符,会导致新的公钥添加到前一个公钥的末尾,两个公钥连在一起,使得它们都无法生效。所以,如果authorized_keys
文件已经存在,使用ssh-copy-id
命令之前,务必保证authorized_keys
文件的末尾是换行符(假设该文件已经存在)。
6、ssh-agent 命令,ssh-add 命令
私钥设置了密码以后,每次使用都必须输入密码,有时让人感觉非常麻烦。比如,连续使用scp
命令远程拷贝文件时,每次都要求输入密码。
ssh-agent
命令就是为了解决这个问题而设计的,它让用户在整个 Bash 对话(session)之中,只在第一次使用 SSH 命令时输入密码,然后将私钥保存在内存中,后面都不需要再输入私钥的密码了。
省略...
7、关闭密码登录
为了安全性,启用密钥登录之后,最好关闭服务器的密码登录。
对于 OpenSSH,具体方法就是打开服务器 sshd 的配置文件/etc/ssh/sshd_config
,将PasswordAuthentication
这一项设为no
。
PasswordAuthentication no
修改配置文件以后,不要忘了重新启动 sshd,否则不会生效。
SSH服务器
1、简介
SSH 的架构是服务器/客户端模式,两端运行的软件是不一样的。OpenSSH 的客户端软件是 ssh,服务器软件是 sshd。本章介绍 sshd 的各种知识。
如果没有安装 sshd,可以用下面的命令安装。
# Debian
$ sudo aptitude install openssh-server
# Red Hat
$ sudo yum install openssh-server
一般来说,sshd 安装后会跟着系统一起启动。如果当前 sshd 没有启动,可以用下面的命令启动。
$ sshd
上面的命令运行以后,sshd 自动进入后台,
2、sshd配置文件
sshd 的配置文件在/etc/ssh
目录,主配置文件是sshd_config
,此外还有一些安装时生成的密钥。
/etc/ssh/sshd_config
:配置文件/etc/ssh/ssh_host_ecdsa_key
:ECDSA 私钥。/etc/ssh/ssh_host_ecdsa_key.pub
:ECDSA 公钥。/etc/ssh/ssh_host_key
:用于 SSH 1 协议版本的 RSA 私钥。/etc/ssh/ssh_host_key.pub
:用于 SSH 1 协议版本的 RSA 公钥。/etc/ssh/ssh_host_rsa_key
:用于 SSH 2 协议版本的 RSA 私钥。/etc/ssh/ssh_host_rsa_key.pub
:用于 SSH 2 协议版本的 RSA 公钥。/etc/pam.d/sshd
:PAM 配置文件。
注意,如果重装 sshd,上面这些密钥都会重新生成,导致客户端重新 ssh 连接服务器时,会跳出警告,拒绝连接。为了避免这种情况,可以在重装 sshd 时,先备份/etc/ssh
目录,重装后再恢复这个目录。
配置文件sshd_config
的格式是,每个命令占据一行。每行都是配置项和对应的值,配置项的大小写不敏感,与值之间使用空格分隔。
Port 2034
上面的配置命令指定,配置项Port
的值是2034
。Port
写成port
也可。
配置文件还有另一种格式,就是配置项与值之间有一个等号,等号前后的空格可选。
Port = 2034
注意,注释只能放在一行的开头,不能放在一行的结尾。
Port 2034 # 此处不允许注释
上面的写法是错误的。
修改配置文件以后,可以用 sshd 命令的-t
(test)检查有没有语法错误。
$ sshd -t
配置文件修改以后,并不会自动生效,必须重新启动 sshd。
$ sudo systemctl restart sshd.service
3、sshd密钥
sshd 有自己的一对或多对密钥。它使用密钥向客户端证明自己的身份。所有密钥都是公钥和私钥成对出现,公钥的文件名一般是私钥文件名加上后缀.pub
。
DSA 格式的密钥文件默认为/etc/ssh/ssh_host_dsa_key
(公钥为ssh_host_dsa_key.pub
),RSA 格式的密钥为/etc/ssh/ssh_host_rsa_key
(公钥为ssh_host_rsa_key.pub
)。如果需要支持 SSH 1 协议,则必须有密钥/etc/ssh/ssh_host_key
。
如果密钥不是默认文件,那么可以通过配置文件sshd_config
的HostKey
配置项指定。默认密钥的HostKey
设置如下。
# HostKey for protocol version 1
# HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
# HostKey /etc/ssh/ssh_host_rsa_key
# HostKey /etc/ssh/ssh_host_dsa_ke
上面命令前面的#
表示这些行都是注释,因为这是默认值,有没有这几行都一样。
如果要修改密钥,就要去掉行首的#
,指定其他密钥。
HostKey /usr/local/ssh/my_dsa_key
HostKey /usr/local/ssh/my_rsa_key
HostKey /usr/local/ssh/my_old_ssh1_key
4、sshd 配置项
/etc/ssh/sshd_config
文件里面的配置项,省略......
- PasswordAuthentication
PasswordAuthentication
指定是否允许密码登录,默认值为yes
(PasswordAuthentication yes
),建议改成no
(禁止密码登录,只允许密钥登录)。
- Port
Port
指定 sshd 监听的端口,即客户端连接的端口,默认是22(Port 22
)。出于安全考虑,可以改掉这个端口(比如Port 8822
)。
配置文件可以使用多个Port
命令,同时监听多个端口。
Port 22
Port 80
Port 443
Port 8080
上面的示例表示同时监听4个端口。
5、sshd 的命令行配置项
sshd 命令有一些配置项。这些配置项在调用时指定,可以覆盖配置文件的设置。
(1)-d
-d
参数用于显示 debug 信息。
$ sshd -d
(7)-p
-p
参数指定 sshd 的服务端口。
$ sshd -p 2034
上面命令指定 sshd 在2034
端口启动。
-p
参数可以指定多个端口。
$ sshd -p 2222 -p 3333
(8)-t
-t
参数检查配置文件的语法是否正确。
SSH端口转发
1、简介
SSH 除了登录服务器,还有一大用途,就是作为加密通信的中介,充当两台服务器之间的通信加密跳板,使得原本不加密的通信变成加密通信。这个功能称为端口转发(port forwarding),又称 SSH 隧道(tunnel)。
端口转发有两个主要作用:
(1)将不加密的数据放在 SSH 安全连接里面传输,使得原本不安全的网络服务增加了安全性,比如通过端口转发访问 Telnet、FTP 等明文服务,数据传输就都会加密。
(2)作为数据通信的加密跳板,绕过网络防火墙。
端口转发有三种使用方法:动态转发,本地转发,远程转发。下面逐一介绍。
2、本地转发
本地转发(local forwarding)指的是,SSH 服务器作为中介的跳板机,建立本地计算机与特定目标网站之间的加密连接。本地转发是在本地计算机的 SSH 客户端建立的转发规则:它会指定一个本地端口(local-port),所有发向那个端口的请求,都会转发到 SSH 跳板机(tunnel-host),然后 SSH 跳板机作为中介,将收到的请求发到目标服务器(target-host)的目标端口(target-port)。
$ ssh -L local-port:target-host:target-port tunnel-host
上面命令中,-L
参数表示本地转发,local-port
是本地端口,target-host
是你想要访问的目标服务器,target-port
是目标服务器的端口,tunnel-host
是 SSH 跳板机【即 SSH服务器所在的主机, root@ip】。
举例来说,现在有一台 SSH 跳板机tunnel-host
,我们想要通过这台机器,在本地2021
端口与目标网站www.example.com
的80端口之间建立 SSH 隧道,就可以写成下面这样。
$ ssh -L 2021:www.example.com:80 tunnel-host -N
然后,访问本机的2021
端口,就是访问www.example.com
的80端口。
$ curl http://localhost:2021 或者在浏览器中直接输入此地址
注意,本地端口转发采用 HTTP 协议,不用转成 SOCKS5 协议。
-N
参数,表示不在 SSH 跳板机执行远程命令,让 SSH 只充当隧道。另外还有一个-f
参数表示 SSH 连接在后台运行。
采用上面的中介方式,只有本机到 tunnel-host 的这一段是加密的,tunnel-host 到mail.example.com
的这一段并不加密。
解释:
http://localhost:2021
,数据会发送到本机2021端口,再在本机开一个随机端口,充当ssh客户端,再把数据流量发送到22端口的ssh服务端,收到数据以后,解密数据,临时开一个随机端口充当客户端,再把流量发送到80端口hutan.vip如果经常使用本地转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
Host test.example.com
LocalForward client-IP:client-port server-IP:server-port
3、动态转发
动态转发指的是,本机与 SSH 服务器之间创建了一个加密连接,然后本机内部针对某个端口的通信,都通过这个加密连接转发。它的一个使用场景就是,访问所有外部网站,都通过 SSH 转发。
动态转发需要把本地端口绑定到 SSH 服务器。至于 SSH 服务器要去访问哪一个网站,完全是动态的,取决于原始通信,所以叫做动态转发。
$ ssh -D local-port tunnel-host -N
上面命令中,-D
表示动态转发,local-port
是本地端口,tunnel-host
是 SSH 服务器,-N
表示这个 SSH 连接只进行端口转发,不登录远程 Shell,不能执行远程命令,只能充当隧道。
举例来说,如果本地端口是2121
,那么动态转发的命令就是下面这样。
$ ssh -D 2121 tunnel-host -N
注意,这种转发采用了 SOCKS5 协议。访问外部网站时,需要把 HTTP 请求转成 SOCKS5 协议,才能把本地端口的请求转发出去。
下面是 SSH 隧道建立后的一个使用实例。
$ curl -x socks5://localhost:2121 http://www.example.com
上面命令中,curl 的-x
参数指定代理服务器,即通过 SOCKS5 协议的本地2121
端口,访问http://www.example.com
。
如果经常使用动态转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
DynamicForward tunnel-host:local-port
SSH证书登录
SSH 是服务器登录工具,一般情况下都采用密码登录或密钥登录。
但是,SSH 还有第三种登录方法,那就是证书登录。某些情况下,它是更合理、更安全的登录方法。
1、非证书登录的缺点
密码登录需要输入服务器密码,这非常麻烦,也不安全,存在被暴力破解的风险。
密钥登录需要服务器保存用户的公钥,也需要用户保存服务器公钥的指纹。这对于多用户、多服务器的大型机构很不方便,如果有员工离职,需要将他的公钥从每台服务器删除。
2、证书登录是什么?
证书登录就是为了解决上面的缺点而设计的。它引入了一个证书颁发机构(Certificate Authority,简称 CA),对信任的服务器颁发服务器证书,对信任的用户颁发用户证书。
登录时,用户和服务器不需要提前知道彼此的公钥,只需要交换各自的证书,验证是否可信即可。
证书登录的主要优点有两个:
(1)用户和服务器不用交换公钥,这更容易管理,也具有更好的可扩展性。
(2)证书可以设置到期时间,而公钥没有到期时间。针对不同的情况,可以设置有效期很短的证书,进一步提高安全性。
3、证书登录的流程
SSH 证书登录之前,如果还没有证书,需要生成证书。具体方法是:
(1)用户和服务器都将自己的公钥,发给 CA;
(2)CA 使用服务器公钥,生成服务器证书,发给服务器;
(3)CA 使用用户的公钥,生成用户证书,发给用户。
有了证书以后,用户就可以登录服务器了。整个过程都是 SSH 自动处理,用户无感知。
第一步,用户登录服务器时,SSH 自动将用户证书发给服务器。
第二步,服务器检查用户证书是否有效,以及是否由可信的 CA 颁发。证实以后,就可以信任用户。
第三步,SSH 自动将服务器证书发给用户。
第四步,用户检查服务器证书是否有效,以及是否由信任的 CA 颁发。证实以后,就可以信任服务器。
第五步,双方建立连接,服务器允许用户登录。
4、生成 CA 的密钥
证书登录的前提是,必须有一个 CA,而 CA 本质上就是一对密钥,跟其他密钥没有不同,CA 就用这对密钥去签发证书。
虽然 CA 可以用同一对密钥签发用户证书和服务器证书,但是出于安全性和灵活性,最好用不同的密钥分别签发。所以,CA 至少需要两对密钥,一对是签发用户证书的密钥,假设叫做user_ca
,另一对是签发服务器证书的密钥,假设叫做host_ca
。
使用下面的命令,生成user_ca
。
# 生成 CA 签发用户证书的密钥
$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/user_ca -C user_ca
上面的命令会在~/.ssh
目录生成一对密钥:user_ca
(私钥)和user_ca.pub
(公钥)。
这个命令的各个参数含义如下。
-t rsa
:指定密钥算法 RSA。-b 4096
:指定密钥的位数是4096位。安全性要求不高的场合,这个值可以小一点,但是不应小于1024。-f ~/.ssh/user_ca
:指定生成密钥的位置和文件名。-C user_ca
:指定密钥的识别字符串,相当于注释,可以随意设置。
使用下面的命令,生成host_ca
。
# 生成 CA 签发服务器证书的密钥
$ ssh-keygen -t rsa -b 4096 -f host_ca -C host_ca
上面的命令会在~/.ssh
目录生成一对密钥:host_ca
(私钥)和host_ca.pub
(公钥)。
现在,~/.ssh
目录应该至少有四把密钥。
~/.ssh/user_ca
~/.ssh/user_ca.pub
~/.ssh/host_ca
~/.ssh/host_ca.pub
5、CA 签发服务器证书
有了 CA 以后,就可以签发服务器证书了。
签发证书,除了 CA 的密钥以外,还需要服务器的公钥。一般来说,SSH 服务器(通常是sshd
)安装时,已经生成密钥/etc/ssh/ssh_host_rsa_key
了。如果没有的话,可以用下面的命令生成。
$ sudo ssh-keygen -f /etc/ssh/ssh_host_rsa_key -b 4096 -t rsa
上面命令会在/etc/ssh
目录,生成ssh_host_rsa_key
(私钥)和ssh_host_rsa_key.pub
(公钥)。然后,需要把服务器公钥ssh_host_rsa_key.pub
,复制或上传到 CA 所在的服务器。
上传以后,CA 就可以使用密钥host_ca
为服务器的公钥ssh_host_rsa_key.pub
签发服务器证书。
$ ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w ssh_host_rsa_key.pub
上面的命令会生成服务器证书ssh_host_rsa_key-cert.pub
(服务器公钥名字加后缀-cert
)。这个命令各个参数的含义如下。
-s
:指定 CA 签发证书的密钥。-I
:身份字符串,可以随便设置,相当于注释,方便区分证书,将来可以使用这个字符串撤销证书。-h
:指定该证书是服务器证书,而不是用户证书。-n host.example.com
:指定服务器的域名,表示证书仅对该域名有效。如果有多个域名,则使用逗号分隔。用户登录该域名服务器时,SSH 通过证书的这个值,分辨应该使用哪张证书发给用户,用来证明服务器的可信性。-V +52w
:指定证书的有效期,这里为52周(一年)。默认情况下,证书是永远有效的。建议使用该参数指定有效期,并且有效期最好短一点,最长不超过52周。ssh_host_rsa_key.pub
:服务器公钥。
生成证书以后,可以使用下面的命令,查看证书的细节。
$ ssh-keygen -L -f ssh_host_rsa_key-cert.pub
最后,为证书设置权限。
$ chmod 600 ssh_host_rsa_key-cert.pub
6、CA 签发用户证书
下面,再用 CA 签发用户证书。这时需要用户的公钥,如果没有的话,客户端可以用下面的命令生成一对密钥。
$ ssh-keygen -f ~/.ssh/user_key -b 4096 -t rsa
上面命令会在~/.ssh
目录,生成user_key
(私钥)和user_key.pub
(公钥)。
然后,将用户公钥user_key.pub
,上传或复制到 CA 服务器。接下来,就可以使用 CA 的密钥user_ca
为用户公钥user_key.pub
签发用户证书。
$ ssh-keygen -s user_ca -I user@example.com -n user -V +1d user_key.pub
上面的命令会生成用户证书user_key-cert.pub
(用户公钥名字加后缀-cert
)。这个命令各个参数的含义如下。
-s
:指定 CA 签发证书的密钥-I
:身份字符串,可以随便设置,相当于注释,方便区分证书,将来可以使用这个字符串撤销证书。-n user
:指定用户名,表示证书仅对该用户名有效。如果有多个用户名,使用逗号分隔。用户以该用户名登录服务器时,SSH 通过这个值,分辨应该使用哪张证书,证明自己的身份,发给服务器。-V +1d
:指定证书的有效期,这里为1天,强制用户每天都申请一次证书,提高安全性。默认情况下,证书是永远有效的。user_key.pub
:用户公钥。
生成证书以后,可以使用下面的命令,查看证书的细节。
$ ssh-keygen -L -f user_key-cert.pub
最后,为证书设置权限。
$ chmod 600 user_key-cert.pub
7、服务器安装(服务器)证书
CA 生成服务器证书ssh_host_rsa_key-cert.pub
以后,需要将该证书发回服务器,可以使用下面的scp
命令,将证书拷贝过去。
$ scp ~/.ssh/ssh_host_rsa_key-cert.pub root@host.example.com:/etc/ssh/
然后,将下面一行添加到服务器配置文件/etc/ssh/sshd_config
。
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
上面的代码告诉 sshd,服务器证书是哪一个文件。
重新启动 sshd。
$ sudo systemctl restart sshd.service
# 或者
$ sudo service sshd restart
8、服务器安装 CA 公钥
为了让服务器信任用户证书,必须将 CA 签发用户证书的公钥user_ca.pub
,拷贝到服务器。
$ scp ~/.ssh/user_ca.pub root@host.example.com:/etc/ssh/
上面的命令,将 CA 签发用户证书的公钥user_ca.pub
,拷贝到 SSH 服务器的/etc/ssh
目录。
然后,将下面一行添加到服务器配置文件/etc/ssh/sshd_config
。
TrustedUserCAKeys /etc/ssh/user_ca.pub
上面的做法是将user_ca.pub
加到/etc/ssh/sshd_config
,这会产生全局效果,即服务器的所有账户都会信任user_ca
签发的所有用户证书。
另一种做法是将user_ca.pub
加到服务器某个账户的~/.ssh/authorized_keys
文件,只让该账户信任user_ca
签发的用户证书。具体方法是打开~/.ssh/authorized_keys
,追加一行,开头是@cert-authority principals="..."
,然后后面加上user_ca.pub
的内容,大概是下面这个样子。
@cert-authority principals="user" ssh-rsa AAAAB3Nz...XNRM1EX2gQ==
上面代码中,principals="user"
指定用户登录的服务器账户名,一般就是authorized_keys
文件所在的账户。
重新启动 sshd。
$ sudo systemctl restart sshd.service
# 或者
$ sudo service sshd restart
至此,SSH 服务器已配置为信任user_ca
签发的证书。
9、客户端安装(用户)证书
客户端安装用户证书很简单,就是从 CA 将用户证书user_key-cert.pub
复制到客户端,与用户的密钥user_key
保存在同一个目录即可。
10、客户端安装 CA 公钥
为了让客户端信任服务器证书,必须将 CA 签发服务器证书的公钥host_ca.pub
,加到客户端的/etc/ssh/ssh_known_hosts
文件(全局级别)或者~/.ssh/known_hosts
文件(用户级别)。
具体做法是打开ssh_known_hosts
或known_hosts
文件,追加一行,开头为@cert-authority *.example.com
,然后将host_ca.pub
文件的内容(即公钥)粘贴在后面,大概是下面这个样子。
@cert-authority *.example.com ssh-rsa AAAAB3Nz...XNRM1EX2gQ==
上面代码中,*.example.com
是域名的模式匹配,表示只要服务器符合该模式的域名,且签发服务器证书的 CA 匹配后面给出的公钥,就都可以信任。如果没有域名限制,这里可以写成*
。如果有多个域名模式,可以使用逗号分隔;如果服务器没有域名,可以用主机名(比如host1,host2,host3
)或者 IP 地址(比如11.12.13.14,21.22.23.24
)。
然后,就可以使用证书,登录远程服务器了。
$ ssh -i ~/.ssh/user_key user@host.example.com
上面命令的-i
参数用来指定用户的密钥。如果证书与密钥在同一个目录,则连接服务器时将自动使用该证书。
11、废除证书
废除证书的操作,分成用户证书的废除和服务器证书的废除两种。
服务器证书的废除,用户需要在known_hosts
文件里面,修改或删除对应的@cert-authority
命令的那一行。
用户证书的废除,需要在服务器新建一个/etc/ssh/revoked_keys
文件,然后在配置文件sshd_config
添加一行,内容如下。
RevokedKeys /etc/ssh/revoked_keys
revoked_keys
文件保存不再信任的用户公钥,由下面的命令生成。
$ ssh-keygen -kf /etc/ssh/revoked_keys -z 1 ~/.ssh/user1_key.pub
上面命令中,-z
参数用来指定用户公钥保存在revoked_keys
文件的哪一行,这个例子是保存在第1行。
如果以后需要废除其他的用户公钥,可以用下面的命令保存在第2行。
$ ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/user2_key.pub
SCP命令
scp
是 SSH 提供的一个客户端程序,用来在两台主机之间加密传送文件(即复制文件)。
1、简介
scp
是 secure copy 的缩写,相当于cp
命令 + SSH。它的底层是 SSH 协议,默认端口是22,相当于先使用ssh
命令登录远程主机,然后再执行拷贝操作。
scp
主要用于以下三种复制操作。
- 本地复制到远程。
- 远程复制到本地。
- 两个远程系统之间的复制。
使用scp
传输数据时,文件和密码都是加密的,不会泄漏敏感信息。
2、基本语法
scp
的语法类似cp
的语法。
$ scp source destination
上面命令中,source
是文件当前的位置,destination
是文件所要复制到的位置。它们都可以包含用户名和主机名。
$ scp user@host:foo.txt bar.txt
上面命令将远程主机(user@host
)用户主目录下的foo.txt
,复制为本机当前目录的bar.txt
。可以看到,主机与文件之间要使用冒号(:
)分隔。
scp
会先用 SSH 登录到远程主机,然后在加密连接之中复制文件。客户端发起连接后,会提示用户输入密码,这部分是跟 SSH 的用法一致的。
用户名和主机名都是可以省略的。用户名的默认值是本机的当前用户名,主机名默认为当前主机。注意,scp
会使用 SSH 客户端的配置文件.ssh/config
,如果配置文件里面定义了主机的别名,这里也可以使用别名连接。
scp
支持一次复制多个文件。
$ scp source1 source2 destination
上面命令会将source1
和source2
两个文件,复制到destination
。
注意,如果所要复制的文件,在目标位置已经存在同名文件,scp
会在没有警告的情况下覆盖同名文件。
eg:
3、用法示例
(1)本地文件复制到远程
复制本机文件到远程系统的用法如下。
# 语法
$ scp SourceFile user@host:directory/TargetFile
# 示例
$ scp file.txt remote_username@10.10.0.2:/remote/directory
下面是复制整个目录的例子。
# 将本机的 documents 目录拷贝到远程主机,
# 会在远程主机创建 documents 目录
$ scp -r documents username@server_ip:/path_to_remote_directory
# 将本机整个目录拷贝到远程目录下
$ scp -r localmachine/path_to_the_directory username@server_ip:/path_to_remote_directory/
# 将本机目录下的所有内容拷贝到远程目录下
$ scp -r localmachine/path_to_the_directory/* username@server_ip:/path_to_remote_directory/
(2)远程文件复制到本地
从远程主机复制文件到本地的用法如下。
# 语法
$ scp user@host:directory/SourceFile TargetFile
# 示例
$ scp remote_username@10.10.0.2:/remote/file.txt /local/directory
下面是复制整个目录的例子。
# 拷贝一个远程目录到本机目录下
$ scp -r username@server_ip:/path_to_remote_directory local-machine/path_to_the_directory/
# 拷贝远程目录下的所有内容,到本机目录下
$ scp -r username@server_ip:/path_to_remote_directory/* local-machine/path_to_the_directory/
$ scp -r user@host:directory/SourceFolder TargetFolder
(3)两个远程系统之间的复制
本机发出指令,从远程主机 A 拷贝到远程主机 B 的用法如下。
# 语法
$ scp user@host1:directory/SourceFile user@host2:directory/SourceFile
# 示例
$ scp user1@host1.com:/files/file.txt user2@host2.com:/files
系统将提示你输入两个远程帐户的密码。数据将直接从一个远程主机传输到另一个远程主机。
参考:https://wangdoc.com/ssh/index.html