SSH 服务
SSH 服务器
SSH 是安全的壳程序协议(Secure Shell Protocol),它可以通过数据包加密技术将等待传输的数据包加密后在网上传输。默认状态下,SSH 协议提供服务端和客户端,还带有一个类似 FTP 服务的 Sftp-Server,它们都使用 22 端口。
目前常见网络数据包加密技术通过非对称密钥系统来处理,它通过两把不一样的公钥和私钥来进行数据加密与解密:
- 公钥(Public Key):提供给远程主机进行数据加密的行为。
- 私钥(Private Key):在本地端使用私钥来解密通过公钥加密的数据。
SSH 服务端与客户端的连接步骤如下:
- 服务端第一次启动 sshd 时自动产生公钥和私钥,存放于
/etc/ssh/ssh_host_*
; - 客户端向服务端请求连接;
- 服务端给客户端发送服务端的公钥;
- 客户端将公钥记录在
~/.ssh/known_hosts
中,并发送自己的公钥给服务端; - 服务端和客户端建立连接,并各自通过对方公钥加密数据后传输。
在第 4 步客户端生成的公钥和私钥是一次性的,每次建立连接会重新生成。而服务器的公钥不变,因此客户端也会比较每次连接收到的公钥是否和 known_hosts 中的记录一致。
可以直接使用 systemctl
来控制 ssh 服务器:
[root@server1 ~]$ systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2021-10-09 03:22:48 CST; 19h ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 1242 (sshd)
CGroup: /system.slice/sshd.service
└─1242 /usr/sbin/sshd -D
SSH 客户端
默认 SSH 客户端使用 ssh
命令来运行,命令格式:ssh [-f] [-o 参数项目] [-p 端口号] [账号@]IP [命令]
选项说明:
选项 | 说明 |
---|---|
-f | 配合后面的命令,不登录主机直接发送命令过去执行。 |
-o | 参数项目,常用的有: ConnectTimeout=秒数:控制超时时间 StrictHostKeyChecking=yes|no|ask:加入新公钥时的操作,默认 ask 询问 |
-p | 指定非标准 SSH 连接端口。 |
如果连接时不指定账号,使用的是本地端账号尝试登录。例如以 user1 账号登录远程 10.1.1.2:10022 服务器:
[root@server1 ~]$ ssh -p 10022 user1@10.1.1.2
ssh: connect to host 10.1.1.2 port 10022: Connection refused
例如通过 ssh
运行指定命令:
[root@server1 ~]$ ssh -f 127.0.0.1 find / &> find.log
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
假设服务器重新安装过系统,密钥更新后会造成客户端认证失败。客户端清空掉 known_hosts
文件内容即可:
[root@server1 ~]$ rm -f /etc/ssh/ssh_host*
[root@server1 ~]$ systemctl restart sshd
[root@server1 ~]$ ssh 127.0.0.1
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:jNdAaJuldv+NT40ULeK7lEre4ro8OE/teafAM/bBibg.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /root/.ssh/known_hosts:2
ECDSA host key for 127.0.0.1 has changed and you have requested strict checking.
Host key verification failed.
[root@server1 ~]$ echo "" > /root/.ssh/known_hosts
[root@server1 ~]$ ssh 127.0.0.1
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:jNdAaJuldv+NT40ULeK7lEre4ro8OE/teafAM/bBibg.
ECDSA key fingerprint is MD5:8f:86:05:da:66:c3:d8:fd:cf:09:d4:21:bc:84:80:be.
Are you sure you want to continue connecting (yes/no)?
SFTP 文件传输
可以通过 sftp
或 scp
命令向服务器上传或下载文件。
用 sftp
命令连接和 ssh
类似,连接以后可以使用一些如 cd
、ls
、pwd
、mkdir
之类的命令来在远程服务器操作。而针对本机的命令在针对服务器的命令前加上 l
,比如 lcd
、lls
、lpwd
等。
上传文件使用 put
命令。例如将本地 find.log
文件传输到服务器端:
[root@server1 ~]$ sftp 10.1.1.2
root@10.1.1.2's password:
Connected to 10.1.1.2.
sftp> put find.log /tmp
Uploading find.log to /tmp/find.log
find.log 100% 8958KB 56.2MB/s 00:00
下载文件或目录使用 get
命令:
[root@server1 ~]$ sftp 10.1.1.2
root@10.1.1.2's password:
Connected to 10.1.1.2.
sftp> get html/
Fetching /root/html/ to html
Cannot download non-regular file: /root/html/
sftp> get html/*
Fetching /root/html/index.html to index.html
/root/html/index.html 100% 81 46.8KB/s 00:00
Fetching /root/html/index.html.1 to index.html.1
/root/html/index.html.1 100% 81 48.0KB/s 00:00
Fetching /root/html/index.html.2 to index.html.2
/root/html/index.html.2 100% 81 42.1KB/s 00:00
sftp> exit
注意,上传或下载目录时,要想保持文件夹结构,需要使用 -r
参数。
如果要让新建用户 user01
能够使用 sftp
,需要修改配置文件:
[root@server2 ~]$ vi /etc/ssh/sshd_config
Match User user01
[root@server2 ~]$ systemctl restart sshd
也可以配置匹配的用户组,并强制用户只能停留在自己的主目录。要定义多个用户组,使用逗号分隔:
[root@server2 ~]$ vi /etc/ssh/sshd_config
#Subsystem sftp /usr/libexec/openssh/sftp-server
Subsystem sftp internal-sftp
Match Group sftpgroup
ChrootDirectory %h
ForceCommand internal-sftp
SCP 文件传输
如果已知服务器上存在的文件信息,可以使用 scp
命令来上传和下载。
上传命令:scp [-pr] [-l 速率] 本地文件路径 [账号@]主机:远程目录名
下载命令:scp [-pr] [-l 速率] [账号@]主机:远程文件路径 本地目录名
选项说明:
选项 | 说明 |
---|---|
-p | 保留文件权限信息 |
-r | 递归目录 |
-l | 限制传输速率,单位为 Kbits/s。例如 -l 800 代表 100 KB/s |
例如,将本地 /etc/hosts*
上传到 10.1.1.2 的 /root/html
目录中:
[root@server1 ~]$ scp /etc/hosts* root@10.1.1.2:/root/html/
root@10.1.1.2's password:
hosts 100% 801 533.0KB/s 00:00
hosts.allow 100% 370 281.4KB/s 00:00
hosts.deny 100% 460 391.2KB/s 00:00
将远程主机 10.1.1.2 中的 /boot/
目录下载到本地 /tmp
目录下:
[root@server1 ~]$ scp -r root@10.1.1.2:/boot /tmp
root@10.1.1.2's password:
device.map 100% 84 16.4KB/s 00:00
gcry_rmd160.mod 100% 8068 2.4MB/s 00:00
acpi.mod 100% 9932 5.0MB/s 00:00
gcry_rsa.mod 100% 2068 1.3MB/s 00:00
SSH 服务器配置文件
sshd 服务器配置文件存放在 /etc/ssh/sshd_config
。一些重要的配置选项如下:
- Port 22:默认端口为 22,也可以使用多个端口,在配置中多定义一个 Port 选项即可。
- Protocol 2:SSH 协议版本。可以指定为 Protocol 2, 1 来同时支持 v1 和 v2 版本。
- ListenAddress 0.0.0.0:默认监听所有端口。
- PidFile /var/run/sshd.pid:放置 PID 文件的路径。
- LoginGraceTime 2m:连接超时时间,包括密码输入等待时间。
- HostKey /etc/ssh/ssh_host_key:SSH v1 使用的私钥。
- HostKey /etc/ssh/ssh_host_rsa_key:SSH v2 使用的 RSA 私钥。
- HostKey /etc/ssh/ssh_host_dsa_key:SSH v2 使用的 DSA 私钥。
- LogLevel INFO:日志的等级。
- PermitRootLogin yes:是否允许 root 登录。
- StrictModes yes:是否让 sshd 检查用户主目录或相关文件的权限。
- PubkeyAuthentication yes:是否允许通过密钥登录。
- AuthorizedKeysFile .ssh/authorized_keys:自定义公钥数据存放位置。
- PasswordAuthentication yes:是否允许通过密码登录。
- PermitEmptyPasswords no:是否允许以空密码登录。
- IgnoreUserKnowHosts no:是否忽略 known_hosts 文件。
- UsePAM yes:利用 PAM 管理用户认证。
- X11Forwarding yes:让窗口数据通过 SSH 连接来传送。
- PrintLastLog yes:是否显示上次登录信息。
- TCPKeepAlive yes:是否一直发送 TCP 数据包给客户端,来检测连接状态。
- UseDNS yes:是否使用 DNS 去反查客户端的主机名。在内网可以设为 no 加速连接。
通过密钥登录
可以将客户端用户的公钥复制到服务器端用户目录内的 SSH 认证文件中,这样就可以实现免密码使用 SSH 和 SFTP。
首先,客户端需要生成密钥对(id_rsa 私钥和 id_rsa.pub 公钥),可以使用 -t
参数指定 RSA 或 DSA 算法:
[root@server1 ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
然后,使用 ssh-copy-id
命令将公钥 id_rsa.pub
的内容传送到 root@192.168.2.254
:
[root@server1 ~]$ ssh-copy-id root@192.168.2.254
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.2.254's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.2.254'"
and check to make sure that only the key(s) you wanted were added.
现在就可以通过 SSH 免密码登录到 192.168.2.254
了:
[root@server1 ~]$ ssh root@192.168.2.254
Last login: Sat Oct 9 20:00:00 2021 from 192.168.2.101
通过使用密钥登录,可以提高安全性并简化 SSH 连接过程。
修改 SSH 端口
在启用 SELinux 的情况下,修改 SSH 配置文件中的端口配置可能导致 SSH 无法启动。
当出现类似以下错误信息时,表示在绑定端口时遇到了权限拒绝的问题:
[root@server1 ~]$ journalctl -xe
Oct 10 01:22:37 server1 sshd[10905]: error: Bind to port 20000 on :: failed: Permission denie
Oct 10 01:22:37 server1 sshd[10905]: fatal: Cannot bind any address.
Oct 10 01:22:37 server1 systemd[1]: sshd.service: main process exited, code=exited, status=25
Oct 10 01:22:37 server1 systemd[1]: Failed to start OpenSSH server daemon.
-- Subject: Unit sshd.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit sshd.service has failed.
--
-- The result is failed.
Oct 10 01:22:37 server1 systemd[1]: Unit sshd.service entered failed state.
Oct 10 01:22:37 server1 systemd[1]: sshd.service failed.
Oct 10 01:22:37 server1 polkitd[963]: Unregistered Authentication Agent for unix-process:1088
[root@server1 ~]$ cat /var/log/audit/audit.log | grep AVC | grep ssh
type=AVC msg=audit(1633800192.050:404): avc: denied { name_bind } for pid=10954 comm="sshd" src=20000 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0
通过安装 setroubleshoot
诊断套件后,可以查询 SELinux 日志信息以了解详细情况:
[root@server1 ~]$ yum -y install setroubleshoot
[root@server1 ~]$ tail /var/log/messages
Oct 10 01:48:40 server1 setroubleshoot: SELinux is preventing /usr/sbin/sshd from name_bind access on the tcp_socket port 20000. For complete SELinux messages run: sealert -l 04603a0d-6723-417a-839a-d0974457f614
[root@server1 ~]$ sealert -l 04603a0d-6723-417a-839a-d0974457f614
SELinux is preventing /usr/sbin/sshd from name_bind access on the tcp_socket port 20000.
***** Plugin bind_ports (92.2 confidence) suggests ************************
If you want to allow /usr/sbin/sshd to bind to network port 20000
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 20000
where PORT_TYPE is one of the following: ssh_port_t, vnc_port_t, xserver_port_t.
根据提示,有三种解决方法:
- 修改默认绑定端口的设置:
semanage port -a -t ssh_port_t -p tcp 20000
- 修改 NIS 的设置:
setsebool -P nis_enabled 1
- 强制允许动作:
ausearch -c 'sshd' --raw | audit2allow -M my-sshd; semodule -i my-sshd.pp
通过以上任意一种方法,都可以解决端口绑定的问题。
使用 SSH 通道
您可以使用 SSH 来开启一个加密的通道,以供其他不支持加密的应用程序使用。
例如,要在本地开启一个端口为 8888 的通道,连接到远程服务器 192.168.2.234 的 22 端口,可以执行以下命令:
[root@server2 ~]$ ssh -L 8888:127.0.0.1:22 -N 192.168.2.234
[root@server2 ~]$ netstat -ntulp | grep 8888
tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN 78842/ssh
[root@server2 ~]$ ssh -p 8888 127.0.0.1
Last login: Sun Oct 10 02:20:31 2021 from localhost
在本地,端口 8888 将保持监听状态,而本地的 SSH 端口将直接连接到远程服务器 192.168.2.234 的 22 端口。要中断通道,只需关闭相应的 SSH 进程即可。