目 录CONTENT

文章目录

SSH

FatFish1
2025-04-22 / 0 评论 / 0 点赞 / 23 阅读 / 0 字 / 正在检测是否收录...

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_configHostKey配置项指定。

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

sinceuntil参数可以指定日志的时间范围。

$ 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 应用程序,用于文件同步。

它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cpmv命令。

如果本机或者远程计算机没有安装 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>

参考文献:

  1. https://wangdoc.com/ssh/

0

评论区