共计 5540 个字符,预计需要花费 14 分钟才能阅读完成。
背景
只要使用服务器搭建项目,难免使用到 ssh,那么就可能遇到 ssh 版本过低,需要升级修复漏洞的情况。
以下提供一些编译安装并升级 openssh 和 openssl 的思路。
编译安装升级
1. openssl
openssl 在系统中的运用访问广泛,作为系统的底层库,被 systemd、apt、curl、ssh 等应用大量使用,所以基本不可能进行大版本的替换原系统的 openssl。
例如原系统使用的 openssl 版本为 1.1.1,其动态库为 libssl.so.1.1
和 libcrypto.so.1.1
。如果将 openssl 命令和动态库替换,仅仅只是让 openssl 这个命令可以运行而已,这种方式会导致系统无法启动。
因此,对于低版本(1.x)的 openssl,方案是编译一个高版本的动态库与其动态库共存。对于高版本(3.x)的 openssl,则是编译一个比其更高版本的动态库,替换掉原来的动态库。
OpenSSL 1.1.1 是 1.1 系列唯一的 LTS 版本,但已于 2023 年 9 月彻底停止维护;目前官方仅维护的 LTS 版本是 OpenSSL 3.0(支持到 2026 年 9 月),OpenSSL 3.1 和 OpenSSL 3.2 不是 LTS 版本。
1.1 安装编译环境
sudo apt update && \
sudo apt install build-essential checkinstall zlib1g-dev -y
-
build-essential:gcc/g++、make 等编译工具
-
checkinstall:可选,用于安装生成的包
-
zlib1g-dev:如果启用压缩支持
1.2 下载源码包
wget https://www.openssl.org/source/openssl-3.0.16.tar.gz
1.3 编译安装
# 解压
tar -zxvf openssl-3.0.16.tar.gz && cd openssl-3.0.16/
# 生成配置
sudo ./config --prefix=/usr/local/openssl-3.0.16 --openssldir=/usr/local/openssl-3.0.16 shared zlib
--prefix=/usr/local/openssl-3.0.16
指定安装路径。编译完成后,bin/openssl
、lib/
等都会安装到这个目录下。
--openssldir=/usr/local/openssl-3.0.16
指定 OpenSSL 的运行时配置目录,主要存放证书、配置文件(如 openssl.cnf)、密钥等。通常和 --prefix
设置成一样的路径。
shared
生成 动态库 (.so
),方便系统和其他程序链接使用。如果不加这个参数,默认只会编译静态库 (.a
)。
zlib
启用 zlib 压缩支持,比如 TLS 里的压缩算法。
# 编译
make
# 安装(将生成的二进制文件和动态库安装到前面配置的目录下)
sudo make install
1.4 拷贝动态库
sudo cp /usr/local/openssl-3.0.16/lib64/libssl.so.3 /usr/lib/x86_64-linux-gnu/
sudo cp /usr/local/openssl-3.0.16/lib64/libcrypto.so.3 /usr/lib/x86_64-linux-gnu/
2. openssh
当前 openssh 修复漏洞后的版本为 openssh-10.0p1
,所以直接安装此版本。
1.1 开启 telnet
为了防止失联最好先开启 telnet。
sudo apt update && \
sudo apt install telnetd -y && \
sudo systemctl enable --now inetd
1.2 备份
sudo mv /usr/bin/ssh /usr/bin/ssh.bak
sudo mv /usr/sbin/sshd /usr/sbin/sshd.bak
sudo mv /etc/ssh /etc/ssh.bak
可以看见动态库目录下有 libssh 相关库,但是不需要备份,因为 libssh 和 openssh 没有关系,openssh 需要用到的动态库是 libcrypto.so.3
,而 libssl.so.3
这些库在 apt、curl 等工具中才会用到。
1.3 安装编译环境
sudo apt install build-essential zlib1g-dev libssl-dev libpam0g-dev libselinux1-dev -y
-
build-essential:编译工具
-
zlib1g-dev:压缩支持
-
libssl-dev:OpenSSL 库头文件
-
libpam0g-dev:PAM 支持(用户认证)
-
libselinux1-dev:SELinux 支持(可选)
可选依赖:
libaudit-dev:审计功能
libwrap0-dev:TCP Wrappers 支持
libkrb5-dev:Kerberos 支持
1.4 下载源码包
wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-10.0p1.tar.gz
1.5 编译安装
tar -zxvf openssh-10.0p1.tar.gz && cd openssh-10.0p1
# 配置
./configure --prefix=/usr/local/openssh-10.0p1 --with-ssl-dir=/usr/local/openssl-3.0.16
--prefix=/usr/local/openssh-10.0p1
指定安装路径
--with-ssl-dir=/usr/local/openssl-3.0.16
指定 openssl 位置,让 openssl 使用该版本的头文件和库文件,而不是系统默认的旧版本。
# 编译
make
# 安装(将生成的二进制文件和动态库安装到前面配置的目录下)
sudo make install
1.6 配置新版本
sudo cp /usr/local/openssh-10.0p1/bin/ssh /usr/bin/
sudo cp /usr/local/openssh-10.0p1/sbin/sshd /usr/sbin/
如果有特殊配置,比如运行 root 用户登录,请记得修改配置文件 /etc/ssh/sshd_config
1.7 重启系统
sudo reboot
1.8 关闭 telnet
重启后,系统没有异常,并且 ssh 正常连接,可以关闭 telnet。
sudo systemctl disable --now inetd
升级系统进行升级
对于 ubuntu 18.04、ubuntu 20.04 等使用 openssl 版本为 1.x
的系统来说,只能升级 openssh,而不能直接升级 openssl。
但是可以通过升级系统的方式,达到目的。比如 ubuntu 22.04 使用的 openssl 版本为 3.x
,并且 openssh 的版本也得到了升级。
sudo apt update && sudo apt upgrade -y
sudo do-release-upgrade
如果对于升级后的 openssl
和 openssh
版本仍不满意,可再使用上面提供的编译安装的方式进行丝滑升级,而不用担心对系统造成异常。
# ubuntu 18.04
root@hz:~# ssh -V
OpenSSH_7.6p1 Ubuntu-4ubuntu0.7, OpenSSL 1.0.2n 7 Dec 2017
root@hz:~# openssl version
OpenSSL 1.1.1 11 Sep 2018
root@hz:~# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.6 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.6 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
# ubuntu 20.04
root@hz:~# ssh -V
OpenSSH_8.2p1 Ubuntu-4ubuntu0.13, OpenSSL 1.1.1f 31 Mar 2020
root@hz:~# openssl version
OpenSSL 1.1.1f 31 Mar 2020
root@hz:~# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.6 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
# ubuntu 22.04
root@hz:~# ssh -V
OpenSSH_8.9p1 Ubuntu-3ubuntu0.13, OpenSSL 3.0.2 15 Mar 2022
root@hz:~# openssl version
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
root@hz:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
其他(升级 SSH)
以下仅为已经再另一台机器上编译好 openssl 和 openssh 的情况。
# 1. openssl
cd /usr/local
sudo tar czvf openssl-3.0.16.tar.gz openssl-3.0.16
scp openssl-3.0.16.tar.gz test.com:/tmp
cd /usr/local
sudo tar xzvf /tmp/openssl-3.0.16.tar.gz
# 2. openssh
cd /usr/local
sudo tar czvf openssh-10.0p1.tar.gz openssh-10.0p1
cd /usr/local
sudo tar xzvf /tmp/openssh-10.0p1.tar.gz
# 3. 拷贝动态库
sudo cp /usr/local/openssl-3.0.16/lib64/libssl.so.3 /usr/lib/x86_64-linux-gnu/
sudo cp /usr/local/openssl-3.0.16/lib64/libcrypto.so.3 /usr/lib/x86_64-linux-gnu/
# 4. 开启 telnet
# 最好进行该操作,不然可能需要本地登录
sudo apt update && \
sudo apt install telnetd -y && \
sudo systemctl enable --now inetd
# 5. 备份
sudo mv /usr/bin/ssh /usr/bin/ssh.bak
sudo mv /usr/sbin/sshd /usr/sbin/sshd.bak
sudo mv /etc/ssh /etc/ssh.bak
# 6. 使用新版本
sudo mkdir -p /etc/ssh && sudo cp -a /usr/local/openssh-10.0p1/etc/. /etc/ssh/
sudo ln -s /usr/local/openssh-10.0p1/bin/ssh /usr/bin/ssh
sudo ln -s /usr/local/openssh-10.0p1/sbin/sshd /usr/sbin/sshd
# 7. 配置 ssh 特权分离目录
sudo mkdir -p /var/empty
sudo chown root:root /var/empty
sudo chmod 755 /var/empty
# 8. 重启 ssh
systemctl reload sshd
sudo systemctl restart ssh
# 9. 关闭 telnet
sudo systemctl disable --now inetd