SSH是什么
SSH(Secure Shell 的缩写)是一种网络协议,用于加密两台计算机之间的通信,并且支持各种身份验证机制。
举个例子:登录远程服务器的时候,需要将用户输入的密码传给服务器,如果这个过程是明文通信,就意味着传递过程中,线路经过的中间计算机都能看到密码,这是很可怕的。
SSH 就是为了解决这个问题而诞生的,它能够加密计算机之间的通信,保证不被窃听或篡改。它还能对操作者进行认证(authentication)和授权(authorization)。明文的网络协议可以套用在它里面,从而实现加密。
SSH的架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH 软件分成两个部分:向服务器发出请求的部分,称为客户端(client),OpenSSH 的实现为 ssh;接收客户端发出的请求的部分,称为服务器(server),OpenSSH 的实现为 sshd。
SSH客户端 - ssh
安装和使用
OpenSSH 的客户端是二进制程序 ssh。它在 Linux/Unix 系统的位置是/usr/local/bin/ssh
。
Linux 系统一般都自带 ssh,如果没有就需要安装。
# Ubuntu 和 Debian
$ sudo apt install openssh-client
# CentOS 和 Fedora
$ sudo dnf install openssh-clients
安装以后,可以使用-V
参数输出版本号,查看一下是否安装成功。
$ ssh -V
使用客户端可以登录服务器,不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。
$ ssh hostname
如果要指定用户名,可以采用下面的语法:
$ ssh user@hostname
以下有几个常用的参数:
# -l用户名和主机名就不用写在一起了
$ ssh -l username host
# -p参数可以指定其他端口
$ ssh -p 8821 foo.com
# -i identity_file:指定身份验证文件(私钥文件)。
$ ssh -i /path/to/private_key user@hostname
# -t分派一个互动式shell
$ ssh -t server.example.com emacs
客户端连接流程的概念
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
文件中。每次连接服务器时,通过该文件判断是否为陌生主机(陌生公钥)。
在上面这段文字后面,输入yes
,就可以将当前服务器的指纹也储存在本机~/.ssh/known_hosts
文件中,并显示下面的提示。以后再连接的时候,就不会再出现警告了。
Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts
执行远程命令
SSH 登录成功后,用户就进入了远程主机的命令行环境,所看到的提示符,就是远程主机的提示符。这时,你就可以输入想要在远程主机执行的命令。
另一种执行远程命令的方法,是将命令直接写在ssh
命令的后面。
$ ssh foo@server.example.com cat /etc/hosts
使用互动式shell
$ ssh -t server.example.com emacs
加密参数
SSH 连接的握手阶段,客户端必须跟服务端约定加密参数集(cipher suite)。
加密参数集包含了若干不同的加密参数,它们之间使用下划线连接在一起,下面是一个例子。
TLS_RSA_WITH_AES_128_CBC_SHA
它的含义如下。
TLS:加密通信协议
RSA:密钥交换算法
AES:加密算法
128:加密算法的强度
CBC:加密算法的模式
SHA:数字签名的 Hash 函数
下面是一个例子,客户端向服务器发出的握手信息。
Handshake protocol: ClientHello
Version: TLS 1.2
Random
Client time: May 22, 2030 02:43:46 GMT
Random bytes: b76b0e61829557eb4c611adfd2d36eb232dc1332fe29802e321ee871
Session ID: (empty)
Cipher Suites
Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”
Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
Suite: TLS_RSA_WITH_AES_128_GCM_SHA256
Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_RSA_WITH_AES_128_CBC_SHA
Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA
Suite: TLS_RSA_WITH_RC4_128_SHA
Compression methods
Method: null
Extensions
Extension: server_name
Hostname: www.feistyduck.com
Extension: renegotiation_info
Extension: elliptic_curves
Named curve: secp256r1
Named curve: secp384r1
Extension: signature_algorithms
Algorithm: sha1/rsa
Algorithm: sha256/rsa
Algorithm: sha1/ecdsa
Algorithm: sha256/ecdsa”
上面的握手信息(ClientHello)之中,Cipher Suites
字段就是客户端列出可选的加密参数集,服务器在其中选择一个自己支持的参数集。
服务器选择完毕之后,向客户端发出回应。
Handshake protocol: ServerHello
Version: TLS 1.2
Random
Server time: Mar 10, 2059 02:35:57 GMT”
Random bytes: 8469b09b480c1978182ce1b59290487609f41132312ca22aacaf5012
Session ID: 4cae75c91cf5adf55f93c9fb5dd36d19903b1182029af3d527b7a42ef1c32c80
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Compression method: null
Extensions
Extension: server_name
Extension: renegotiation_info”
上面的回应信息(ServerHello)中,Cipher Suite
字段就是服务器最终选定的加密参数。
客户端配置文件
SSH 客户端的全局配置文件是/etc/ssh/ssh_config
,用户个人的配置文件在~/.ssh/config
,优先级高于全局配置文件。
除了配置文件,~/.ssh
目录还有一些用户个人的密钥文件和其他文件。下面是其中一些常见的文件。
~/.ssh/id_ecdsa
:用户的 ECDSA 私钥。~/.ssh/id_ecdsa.pub
:用户的 ECDSA 公钥。~/.ssh/id_rsa
:用于 SSH 协议版本2 的 RSA 私钥。~/.ssh/id_rsa.pub
:用于SSH 协议版本2 的 RSA 公钥。~/.ssh/identity
:用于 SSH 协议版本1 的 RSA 私钥。~/.ssh/identity.pub
:用于 SSH 协议版本1 的 RSA 公钥。~/.ssh/known_hosts
:包含 SSH 服务器的公钥指纹。
用户个人的配置文件~/.ssh/config
,可以按照不同服务器,列出各自的连接参数,从而不必每一次登录都输入重复的参数。下面是一个例子。
Host remoteserver
HostName remote.example.com
User neo
Port 2112
$ ssh remoteserver
# 等同于
$ ssh -p 2112 neo@remote.example.com
SSH密钥登录
密钥的概念
密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。
SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。
如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。
密钥登录过程
第一步,手动将客户端的公钥放入远程服务器的指定位置。
第二步,客户端向服务器发起 SSH 登录的请求。
第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。
第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。
获取密钥
密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen
命令,用来生成密钥。
直接输入ssh-keygen
,程序会询问一系列问题,然后生成密钥。使用-t
参数指定加密的算法
$ 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-keygen
命令以后,会出现第一个问题,询问密钥保存的文件名,默认是~/.ssh/id_dsa
文件,这个是私钥的文件名,对应的公钥文件~/.ssh/id_dsa.pub
是自动生成的。用户的密钥一般都放在主目录的.ssh
目录里面。
如果选择rsa
算法,生成的密钥文件默认就会是~/.ssh/id_rsa
(私钥)和~/.ssh/id_rsa.pub
(公钥)。
按提示输入两次密码
最后,就会生成私钥和公钥,屏幕上还会给出公钥的指纹,以及当前的用户名和主机名作为注释,用来识别密钥的来源。
公钥文件和私钥文件都是文本文件,可以用文本编辑器看一下它们的内容。公钥文件的内容类似下面这样。
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com
下面的命令可以列出用户所有的公钥。
$ ls -l ~/.ssh/id_*.pub
生成密钥以后,建议修改它们的权限,防止其他人读取。
$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub
配置对应的服务器
生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。
OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys
文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys
文件。
注意,authorized_keys
文件的权限要设为644
,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。
$ chmod 644 ~/.ssh/authorized_keys
只要公钥上传到服务器,下次登录时,OpenSSH 就会自动采用密钥登录,不再提示输入密码。
关闭密码登录
为了安全性,启用密钥登录之后,最好关闭服务器的密码登录。
对于 OpenSSH,具体方法就是打开服务器 sshd 的配置文件/etc/ssh/sshd_config
,将PasswordAuthentication
这一项设为no
。
PasswordAuthentication no
修改配置文件以后,不要忘了重新启动 sshd,否则不会生效。
SSH服务器端 - sshd
sshd服务器安装与启动
如果没有安装 sshd,可以用下面的命令安装。
# Debian
$ sudo aptitude install openssh-server
# Red Hat
$ sudo yum install openssh-server
一般来说,sshd 安装后会跟着系统一起启动。如果当前 sshd 没有启动,可以用下面的命令启动。
$ sshd
除了直接运行可执行文件,也可以通过 Systemd 启动 sshd。
# 启动
$ sudo systemctl start sshd.service
# 停止
$ sudo systemctl stop sshd.service
# 重启
$ sudo systemctl restart sshd.service
下面的命令让 sshd 在计算机下次启动时自动运行。
$ sudo systemctl enable sshd.service
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密钥
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
配置项指定。
SSH日志
journalctl 命令
如果系统使用 Systemd,可以使用journalctl
命令查看日志。
$ journalctl -u ssh
Mar 25 20:25:36 web0 sshd[14144]: Accepted publickey for ubuntu from 10.103.160.144 port 59200 ssh2: RSA SHA256:l/zFNib1vJ+64nxLB4N9KaVhBEMf8arbWGxHQg01SW8
Mar 25 20:25:36 web0 sshd[14144]: pam_unix(sshd:session): session opened for user ubuntu by (uid=0)
Mar 25 20:39:12 web0 sshd[14885]: pam_unix(sshd:session): session closed for user ubuntu
...
上面示例中,返回的日志每一行就是一次登录尝试,按照从早到晚的顺序,其中包含了登录失败的尝试。-u
参数是 Unit 单元的意思,-u ssh
就是查看 SSH 单元,有的发行版需要写成-u sshd
。
-b0
参数可以查看自从上次登录后的日志。
$ journalctl -t ssh -b0
-r
参数表示逆序输出,最新的在前面。
$ journalctl -t ssh -b0 -r
since
和until
参数可以指定日志的时间范围。
$ journalctl -u ssh --since yesterday # 查看昨天的日志
$ journalctl -u ssh --since -3d --until -2d # 查看三天前的日志
$ journalctl -u ssh --since -1h # 查看上个小时的日志
$ journalctl -u ssh --until "2022-03-12 07:00:00" # 查看截至到某个时间点的日志
下面的命令查看实时日志。
$ journalctl -fu ssh
其他命令
如果系统没有使用 Systemd,可以在/var/log/auth.log
文件中找到 sshd 的日志。
$ sudo grep sshd /var/log/auth.log
下面的命令查看最后 500 行里面的 sshd 条目。
$ sudo tail -n 500 /var/log/auth.log | grep sshd
-f
参数可以实时跟踪日志。
$ sudo tail -f -n 500 /var/log/auth.log | grep sshd
如果只是想看谁登录了系统,而不是深入查看所有细节,可以使用lastlog
命令。
$ lastlog
日志设置
sshd 的配置文件/etc/ssh/sshd_config
,可以调整日志级别。
LogLevel VERBOSE
如果为了调试,可以将日志调整为 DEBUG。
LogLevel DEBUG
SSH证书登录
概述
证书登录是第三种登录方式
证书登录的主要优点有两个:(1)用户和服务器不用交换公钥,这更容易管理,也具有更好的可扩展性。(2)证书可以设置到期时间,而公钥没有到期时间。针对不同的情况,可以设置有效期很短的证书,进一步提高安全性。
证书登录流程
SSH 证书登录之前,如果还没有证书,需要生成证书。具体方法是:(1)用户和服务器都将自己的公钥,发给 CA;(2)CA 使用服务器公钥,生成服务器证书,发给服务器;(3)CA 使用用户的公钥,生成用户证书,发给用户。
有了证书以后,用户就可以登录服务器了。整个过程都是 SSH 自动处理,用户无感知。
第一步,用户登录服务器时,SSH 自动将用户证书发给服务器。
第二步,服务器检查用户证书是否有效,以及是否由可信的 CA 颁发。证实以后,就可以信任用户。
第三步,SSH 自动将服务器证书发给用户。
第四步,用户检查服务器证书是否有效,以及是否由信任的 CA 颁发。证实以后,就可以信任服务器。
第五步,双方建立连接,服务器允许用户登录。
生成CA的流程
暂略
SSH常用命令
scp命令
scp
是 SSH 提供的一个客户端程序,用来在两台主机之间加密传送文件(即复制文件)。
scp
是 secure copy 的缩写,相当于cp
命令 + SSH。它的底层是 SSH 协议,默认端口是22,相当于先使用ssh
命令登录远程主机,然后再执行拷贝操作。
scp
主要用于以下三种复制操作。
本地复制到远程。
远程复制到本地。
两个远程系统之间的复制。
使用scp
传输数据时,文件和密码都是加密的,不会泄漏敏感信息。
scp
的语法类似cp
的语法。
$ scp user@host:foo.txt bar.txt
rsync 命令
rsync 是一个常用的 Linux 应用程序,用于文件同步。
它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cp
和mv
命令。
如果本机或者远程计算机没有安装 rsync,可以用下面的命令安装。
# Debian
$ sudo apt-get install rsync
# Red Hat
$ sudo yum install rsync
# Arch Linux
$ sudo pacman -S rsync
sftp命令
sftp
是 SSH 提供的一个客户端应用程序,主要用来安全地访问 FTP。因为 FTP 是不加密协议,很不安全,sftp
就相当于将 FTP 放入了 SSH。
下面的命令连接 FTP 主机。
$ sftp username@hostname
执行上面的命令,会要求输入 FTP 的密码。密码验证成功以后,就会出现 FTP 的提示符sftp>
,下面是一个例子。
$ sftp USER@penguin.example.com
USER@penguin.example.com's password:
Connected to penguin.example.com.
sftp>
参考文献:
https://wangdoc.com/ssh/
评论区