升級操做系統OpenSSH及其OpenSSL的正確姿式


需求說明

在本小節中,讓我花點篇幅繞個彎子解釋下文章標題是什麼意思,以及這篇文章到底講的是什麼,這將有助於理解本文的內容。shell

 

有時,可能因爲審計須要或修復漏洞的須要,咱們可能會遇到這麼一個需求:升級操做系統的openssl。vim

 

那,怎麼升級操做系統的openssl呢?那很簡單,一條命令搞定:centos

[root@gw ~]# yum update openssl -y緩存

沒錯,這的確能夠升級操做系統的openssl。這只是小版本的升級,好比將openssl從1.0.1e-43版本升級到1.0.1e-57版本,也能夠修補一些漏洞。可是,在審計時,審計人員會告訴你,這不行,他要的是跨版本的升級。好比,將操做系統的openssl從1.0.1e版本升級到1.0.2h版本,啥,新出了個1.1.0h版本,那就升級到最新的1.1.0h版本吧。他就認爲版本越高越好,漏洞越少,他也無論你到底有沒有進行跨版本升級的必要性,究竟是不是真的技術上可行。而他怎麼看openssl版本的呢?可能就是登陸到系統中,執行下面的命令:安全

[root@gw ~]# ssh -V服務器

 

就由於ssh -V命令執行後顯示出來的openssl版本較低,就說要(跨版本)升級操做系統的openssl。這裏面存在邏輯問題,讓我逐個地解釋。session

 

首先,我給個結論:跨版本升級操做系統的openssl是不可能的。app

你能夠在系統中嘗試執行下yum remove openssl命令,你就能夠看到,很是很是多的軟件是依賴於openssl軟件。openssl是一個很是基礎的軟件。假設你升級了操做系統的openssl,好比說,編譯安裝一個新版本的openssl覆蓋掉操做系統自帶的openssl。這就會致使那些依賴於openssl的軟件的openssl相關的功能變得不可用,好比說,某軟件本來是支持https的,如今可能就不支持了。除非你能將系統中全部依賴於openssl的軟件基於新版本的openssl全都編譯一遍,而這一般是不可能的。ssh

 

其次,咱們並不須要升級操做系統的openssl。tcp

我想,不少人在碰到這個需求時,可能都有去百度過,而後百度出了一大堆文章,而後瞭解到也須要從新編譯安裝openssh。可是,幾乎我看到的全部文章,都採用的是錯誤的作法,因此纔有了我這篇文章。他們的作法雖然各不相同,但大概也能夠歸納爲:先強制卸載操做系統的openssl、openssh,再編譯安裝一個新版本的openssl(和其它可能的附帶軟件),而後各類莫名其妙的操做,最後編譯安裝一個新版本的openssh。這種作法沒法達到目的嗎?那倒也不是。但可能代價就是,全部其它依賴於操做系統的openssl的軟件的openssl相關的功能都不能用了。

 

所以來講,正確的作法是什麼?這就是本文所要介紹的。

ssh命令是openssh軟件的一部分。咱們沒法升級操做系統的openssl,可是咱們能夠另外編譯一個openssl,放到單獨的應用目錄中,與操做系統的openssl互不干涉。再基於新編譯出來的openssl,將新的openssh軟件編譯出來。 而操做系統的openssh是能夠被替換的。若是你嘗試執行 yum remove openssh* 命令就能夠看到,沒有其它軟件依賴於openssh。此外,openssh軟件提供了sshd服務。因此,咱們只要還要配置並搭建好sshd服務,就能夠替代操做系統自帶的openssh了。

 

簡單來講,這篇文章講的就是,如何升級openssh及其所依賴的openssl。

 

OpenSSH升級思路

要升級openssh,咱們須要先搞懂openssl是怎麼安裝的。

 

我使用的操做系統是centos 6的,我以安裝openssh 7.5.p1爲例。

從openssh官網下載openssh 7.5.p1源碼包,查看裏面的INSTALL文件,裏面有對它的依賴關係作說明。

 

openssh 7.5.p1對下列軟件的依賴是必選的:

openssh依賴的軟件(必選)

備註

Zlib

要求1.1.4或1.2.1.2或更新的版本(1.2.x早期的版本有問題)。

libcrypto

(LibreSSL或OpenSSL)

OpenSSH依賴於libcrypto,而libcrypto能夠由LibreSSL或OpenSSL提供。若是是使用的OpenSSL,要求OpenSSL的版本要大於等於0.9.8f並小於1.1.0。因爲API不一樣,如今還不支持OpenSSL 1.1.x版本。

LibreSSL/OpenSSL應該編譯成位置無關的庫(position-independent library),好比使用-fPIC選項,不然OpenSSH會沒法連接它;若是你必須使用一個非位置無關(non-position-independent)的libcrypto,那麼你在編譯OpenSSH時必須加上--without-pie選項。

 

openssh 7.5.p1對下列軟件的依賴是可選的:

openssh依賴的軟件(可選)

備註

PAM

若是操做系統支持PAM(Pluggable Authentication Modules),那麼OpenSSH就能夠被編譯成支持PAM功能的。大多數的Linux發行版,天然也包括RedHat/CentOS系統,都是支持PAM的。因此,若是咱們要編譯出一個能夠替換操做系統自帶OpenSSH的完整功能的OpenSSH,天然也是要支持PAM的。

其它軟件:

NB

PRNGD

EGD

GNOME

S/Key

LibEdit

LDNS

Autoconf

Basic Security Module (BSM)

這些就不展開來講了。

 

基本上來講,要編譯出一個功能相似於操做系統自帶的OpenSSH軟件,咱們至少須要先準備好Zlib、OpenSSL(或LibreSSL)和PAM軟件。下面,咱們就逐個逐個地來進行安裝。

 

安裝Zlib

Zlib用於提供壓縮和解壓縮功能。操做系統已經自帶了zlib,版本也符合要求。實際上,openssl和openssh都依賴於zlib。執行下面的命令,安裝zlib開發包:

[root@gw ~]# yum install zlib-devel -y

 

安裝PAM

PAM(Pluggable Authentication Modules,可插拔認證模塊)用於提供安全控制。操做系統也已經自帶了PAM,版本也是能夠的。執行下面的命令,安裝PAM開發包:

[root@gw ~]# yum install pam-devel -y

 

安裝tcp_wrappers

tcp_wrappers是一種安全工具,一般,咱們在/etc/hosts.allow或/etc/hosts.deny文件中配置的過濾規則就是使用的tcp_wrappers的功能了。openssh在編譯時的確是能夠選擇支持tcp_wrappers的,但我不知道爲何它的安裝要求裏面沒有體現。操做系統自帶的tcp_wrappers的版本是能夠的。執行下面的命令,安裝tcp_wrappers開發包:

[root@gw ~]# yum install tcp_wrappers-devel -y

 

安裝OpenSSL

因爲OpenSSH 7.5.p1要求OpenSSL的版本大於等於0.9.8f並小於1.1.0,所以,當前(2017年6月)符合要求的最新OpenSSL版本爲1.0.2l。

 

首先,從openssl官網下載源碼包openssl-fips-2.0.16.tar.gz,將其安裝到/opt/fips-2.0.16目錄下。

 

編譯安裝FIPS模塊:

[root@gw OpenSSL]# export FIPSDIR=/opt/fips-2.0.16

[root@gw OpenSSL]# tar -xvf openssl-fips-2.0.16.tar.gz

[root@gw OpenSSL]# cd openssl-fips-2.0.16

[root@gw openssl-fips-2.0.16]# ./config

[root@gw openssl-fips-2.0.16]# make

[root@gw openssl-fips-2.0.16]# make install

說明:

  • 在編譯前先設定環境變量FIPSDIR,這是用於指定FIPS模塊的安裝目錄,這是fips軟件特有的安裝特性。軟件編譯時會檢測該環境變量是否存在。若不指定,默認會安裝在/usr/local/ssl/fips­2.0目錄。

 

從openssl官網下載源碼包openssl-1.0.2l.tar.gz,將其安裝到/opt/openssl1.0.2l_20170617目錄下。將openssl安裝到專門的目錄,這是爲了不對操做系統自帶的openssl形成影響。

 

編譯安裝OpenSSL:

[root@gw OpenSSL]# tar -xvf openssl-1.0.2l.tar.gz

[root@gw OpenSSL]# cd openssl-1.0.2l

[root@gw openssl-1.0.2l]# ./config --prefix=/opt/openssl1.0.2l_20170617 --openssldir=/opt/openssl1.0.2l_20170617/openssl fips --with-fipsdir=/opt/fips-2.0.16 zlib-dynamic shared -fPIC

[root@gw openssl-1.0.2l]# make depend

[root@gw openssl-1.0.2l]# make

[root@gw openssl-1.0.2l]# make test

[root@gw openssl-1.0.2l]# make install

下面是編譯時使用到的選項:

  • --prefix:指定openssl的安裝目錄。按本例中的安裝方式,安裝完成後該目錄下會包含bin(含二進制程序)、lib(含動態庫文件)、include/openssl(含報頭文件)及openssl(--openssldir選項指定的)這些子目錄。

  • --openssldir:指定openssl文件的安裝目錄。按本例中的安裝方式,安裝完成後該目錄下會包括certs(存放證書文件)、man(存放man文件)、misc(存放各類腳本)、private(存放私鑰文件)這些子目錄及openssl.cnf配置文件。

  • fips:集成FIPS模塊。

  • --with-fipsdir:指向FIPS模塊的安裝目錄位置。

  • zlib-dynamic:編譯支持zlib壓縮/解壓縮,讓openssl加載zlib動態庫。該選項只在支持加載動態庫的操做系統上才支持。這是默認選項。

  • shared:除了靜態庫之外,讓openssl(在支持的平臺上)也編譯生成openssl動態庫。

  • -fPIC:將openssl動態庫編譯成位置無關(position-independent)的代碼。

 

安裝完成後,將OpenSSL的庫文件目錄添加到/etc/ld.so.conf文件中,並加載到系統內存緩存中:

[root@gw openssl-1.0.2l]# echo '/opt/openssl1.0.2l_20170617/lib' >> /etc/ld.so.conf

[root@gw openssl-1.0.2l]# ldconfig

 

安裝OpenSSH

從openssl官網下載源碼包openssh-7.5p1.tar.gz,將其安裝到/opt/openssh7.5.p1_20170617目錄下。將openssh安裝到專門的目錄,這是爲了不與操做系統自帶的openssh形成沒必要要的衝突,增長複雜度。

 

編譯安裝OpenSSH:

[root@gw OpenSSH]# tar -xvf openssh-7.5p1.tar.gz

[root@gw OpenSSH]# cd openssh-7.5p1

[root@gw openssh-7.5p1]# ./configure --prefix=/opt/openssh7.5.p1_20170617 --with-ssl-dir=/opt/openssl1.0.2l_20170617 --with-pam --with-tcp-wrappers

[root@gw openssh-7.5p1]# make

[root@gw openssh-7.5p1]# make install

下面是編譯時使用到的選項:

  • --prefix:指定安裝目錄

  • --with-ssl-dir=DIR:指向LibreSSL/OpenSSL庫的安裝目錄的所在路徑。

  • --with-pam:啓用PAM支持。根據OpenSSH的安裝說明,若是在編譯時啓用了PAM,那麼在安裝完成後,也必須在sshd服務的配置文件sshd_config中啓用它(使用UsePAM指令)。

 

根據OpenSSH的安裝說明,若是有啓用PAM,那麼就須要手工安裝一個給sshd程序使用的PAM配置文件,不然安裝好OpenSSH後你可能會沒法使用密碼登陸系統。在編譯時,我使用 --with-pam 選項啓用了對PAM的支持,可是,編譯OpenSSH時並無編譯選項讓你指定PAM配置文件的位置,那麼咱們要怎麼提供這個配置文件呢?

事實上,OpenSSH有另一個編譯選項--with-pam-service=name能夠指定PAM服務名,它的默認值是sshd。而操做系統自帶的PAM軟件默認將全部PAM配置文件都放置在/etc/pam.d目錄下。結合這兩個信息,就可肯定OpenSSH的PAM配置文件應爲/etc/pam.d/sshd文件。而這個文件原來就有了,因此咱們不用額外手工建立一個。

 

設置PATH路徑:

[root@gw ~]# echo 'export PATH=/opt/openssh7.5.p1_20170617/bin:/opt/openssh7.5.p1_20170617/sbin:$PATH' >> /etc/profile.d/path.sh

[root@gw ~]# . /etc/profile.d/path.sh

 

此時,使用ssh -V命令就能夠看到新版本號了:

[root@gw ~]# ssh -V

OpenSSH_7.5p1, OpenSSL 1.0.2l-fips  25 May 2017

 

配置OpenSSH

前面已經安裝好了openssh,可是咱們還須要配置它,以保證sshd服務能夠啓起來。

 

咱們能夠先看一下原有的sshd服務(屬於openssh-server軟件包)都有哪些配置文件:

[root@gw ~]# rpm -ql openssh-server | grep -i --color etc

/etc/pam.d/ssh-keycat

/etc/pam.d/sshd

/etc/rc.d/init.d/sshd

/etc/ssh/sshd_config

/etc/sysconfig/sshd

能夠看到,sshd服務的配置文件爲/etc/ssh/sshd_config,它的pam配置文件爲/etc/pam.d/sshd和/etc/pam.d/ssh-keycat,啓動腳本文件爲/etc/rc.d/init.d/sshd,啓動腳本里面有引用到文件/etc/sysconfig/sshd。

 

參照系統原有的配置文件修改咱們軟件的sshd_config配置文件,這是sshd服務的配置文件(紅色字體的爲新增或修改的部分):

[root@gw ~]# vim /opt/openssh7.5.p1_20170617/etc/sshd_config

Protocol 2

SyslogFacility AUTHPRIV

PermitRootLogin yes

AuthorizedKeysFile      .ssh/authorized_keys

PasswordAuthentication yes

ChallengeResponseAuthentication no

#GSSAPIAuthentication yes                                                    //該選項目前還不支持

#GSSAPICleanupCredentials yes                                            //該選項目前還不支持

UsePAM yes

 

AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES

AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT

AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE

AcceptEnv XMODIFIERS

 

X11Forwarding yes

Subsystem       sftp    /opt/openssh7.5.p1_20170617/libexec/sftp-server

注意,UsePAM必定要啓用,OpenSSH的安裝說明裏有提到,若是編譯時啓用了PAM支持,那麼就必須在sshd_config文件中啓用它。

 

拷貝系統原有的配置文件/etc/sysconfig/sshd到咱們軟件下面,這個配置文件用於設置啓動sshd服務所需的環境變量,在sshd服務的啓動腳本里有調用到該配置文件:

[root@gw ~]# cp -a /etc/sysconfig/sshd /opt/openssh7.5.p1_20170617/etc/sshd

 

接下來要修改sshd服務的啓動腳本/etc/rc.d/init.d/sshd。先將啓動腳本備份一份爲sshd.old,並添加至chkconfig管理:

[root@gw ~]# cp /etc/rc.d/init.d/sshd /etc/rc.d/init.d/sshd.old

[root@gw ~]# chkconfig --add sshd.old

再根據咱們的OpenSSH的安裝路徑,來修改原有的啓動腳本(紅色字體爲有新增或修改的部分):

[root@gw ~]# vim /etc/rc.d/init.d/sshd

### BEGIN INIT INFO

# Provides: sshd

# Required-Start: $local_fs $network $syslog

# Required-Stop: $local_fs $syslog

# Should-Start: $syslog

# Should-Stop: $network $syslog

# Default-Start: 2 3 4 5

# Default-Stop: 0 1 6

# Short-Description: Start up the OpenSSH server daemon

# Description:       SSH is a protocol for secure remote shell access.

#                    This service starts up the OpenSSH server daemon.

### END INIT INFO

 

. /etc/rc.d/init.d/functions

 

[ -f /opt/openssh7.5.p1_20170617/etc/sshd ] && . /opt/openssh7.5.p1_20170617/etc/sshd

 

RETVAL=0

prog="sshd"

lockfile=/var/lock/subsys/$prog

 

KEYGEN=/opt/openssh7.5.p1_20170617/bin/ssh-keygen

SSHD=/opt/openssh7.5.p1_20170617/sbin/sshd

RSA1_KEY=/etc/ssh/ssh_host_key

RSA_KEY=/opt/openssh7.5.p1_20170617/etc/ssh_host_rsa_key

DSA_KEY=/opt/openssh7.5.p1_20170617/etc/ssh_host_dsa_key

PID_FILE=/var/run/sshd.pid                                   # PID文件的所在路徑,這個變量的值不要改

 

runlevel=$(set -- $(runlevel); eval "echo \$$#" )

 

fips_enabled() {

       if [ -r /proc/sys/crypto/fips_enabled ]; then

               cat /proc/sys/crypto/fips_enabled

       else

               echo 0

       fi

}

 

do_rsa1_keygen() {

       if [ ! -s $RSA1_KEY -a `fips_enabled` -eq 0 ]; then

               echo -n $"Generating SSH1 RSA host key: "

               rm -f $RSA1_KEY

               if test ! -f $RSA1_KEY && $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then

                       chmod 600 $RSA1_KEY

                       chmod 644 $RSA1_KEY.pub

                       if [ -x /sbin/restorecon ]; then

                           /sbin/restorecon $RSA1_KEY.pub

                       fi

                       success $"RSA1 key generation"

                       echo

               else

                       failure $"RSA1 key generation"

                       echo

                       exit 1

               fi

       fi

}

 

do_rsa_keygen() {

       if [ ! -s $RSA_KEY ]; then

               echo -n $"Generating SSH2 RSA host key: "

               rm -f $RSA_KEY

               if test ! -f $RSA_KEY && $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then

                       chmod 600 $RSA_KEY

                       chmod 644 $RSA_KEY.pub

                       if [ -x /sbin/restorecon ]; then

                           /sbin/restorecon $RSA_KEY.pub

                       fi

                       success $"RSA key generation"

                       echo

               else

                       failure $"RSA key generation"

                       echo

                       exit 1

               fi

       fi

}

 

do_dsa_keygen() {

       if [ ! -s $DSA_KEY -a `fips_enabled` -eq 0 ]; then

               echo -n $"Generating SSH2 DSA host key: "

               rm -f $DSA_KEY

               if test ! -f $DSA_KEY && $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then

                       chmod 600 $DSA_KEY

                       chmod 644 $DSA_KEY.pub

                       if [ -x /sbin/restorecon ]; then

                           /sbin/restorecon $DSA_KEY.pub

                       fi

                       success $"DSA key generation"

                       echo

               else

                       failure $"DSA key generation"

                       echo

                       exit 1

               fi

       fi

}

 

do_restart_sanity_check()

{

       $SSHD -t

       RETVAL=$?

       if [ $RETVAL -ne  0 ]; then

               failure $"Configuration file or keys are invalid"

               echo

       fi

}

 

start()

{

       [ -x $SSHD ] || exit 5

       [ -f /opt/openssh7.5.p1_20170617/etc/sshd_config ] || exit 6

       # Create keys if necessary

       if [ "x${AUTOCREATE_SERVER_KEYS}" != xNO ]; then

               do_rsa_keygen

               if [ "x${AUTOCREATE_SERVER_KEYS}" != xRSAONLY ]; then

                       #do_rsa1_keygen                                              # 註釋掉這條語句

                       do_dsa_keygen

               fi

       fi

 

       echo -n $"Starting $prog: "

       $SSHD $OPTIONS && success || failure

       RETVAL=$?

       [ $RETVAL -eq 0 ] && touch $lockfile

       echo

       return $RETVAL

}

 

stop()

{

       echo -n $"Stopping $prog: "

       killproc -p $PID_FILE $SSHD

       RETVAL=$?

       # if we are in halt or reboot runlevel kill all running sessions

       # so the TCP connections are closed cleanly

       if [ "x$runlevel" = x0 -o "x$runlevel" = x6 ] ; then

           trap '' TERM

           killall $prog 2>/dev/null

           trap TERM

       fi

       [ $RETVAL -eq 0 ] && rm -f $lockfile

       echo

}

 

reload()

{

       echo -n $"Reloading $prog: "

       killproc -p $PID_FILE $SSHD -HUP

       RETVAL=$?

       echo

}

 

restart() {

       stop

       start

}

 

force_reload() {

       restart

}

 

rh_status() {

       status -p $PID_FILE openssh-daemon

}

 

rh_status_q() {

       rh_status >/dev/null 2>&1

}

 

case "$1" in

       start)

               rh_status_q && exit 0

               start

               ;;

       stop)

               if ! rh_status_q; then

                       rm -f $lockfile

                       exit 0

               fi

               stop

               ;;

       restart)

               restart

               ;;

       reload)

               rh_status_q || exit 7

               reload

               ;;

       force-reload)

               force_reload

               ;;

       condrestart|try-restart)

               rh_status_q || exit 0

               if [ -f $lockfile ] ; then

                       do_restart_sanity_check

                       if [ $RETVAL -eq 0 ] ; then

                               stop

                               # avoid race

                               sleep 3

                               start

                       else

                               RETVAL=6

                       fi

               fi

               ;;

       status)

               rh_status

               RETVAL=$?

               if [ $RETVAL -eq 3 -a -f $lockfile ] ; then

                       RETVAL=2

               fi

               ;;

       *)

               echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"

               RETVAL=2

esac

exit $RETVAL

因爲OpenSSH依賴的OpenSSL已不支持rsa1,因此我將啓動腳本中生成rsa1祕鑰的指令註釋掉了。

 

接下來,關鍵的一步來了,咱們要關閉舊的sshd服務,啓動新的sshd服務。這個操做若是失敗了,不會致使現有的ssh遠程鏈接斷開。因此咱們能夠先關閉舊的sshd程序,再啓動新的sshd程序:

[root@gw ~]# service sshd.old stop

[root@gw ~]# service sshd start

 

若是新的sshd服務啓動成功了,咱們能夠先簡單測試下,好比,看看普通用戶和root用戶是否能正常經過ssh登陸。若是沒有沒有問題,咱們能夠在測測其它的,好比scp、sftp是否正常。固然,若是有條件的話,可使用漏洞掃描工具掃一下,看看有沒有什麼咱們沒有注意到的地方。

 

最後,就能夠刪除掉舊sshd服務的啓動腳本了,以避免衝突:

[root@gw ~]# rm -f /etc/init.d/sshd.old

 

總結

如今,全部操做都完成了。總的來講,整個升級過程應該仍是挺明瞭的,不會有太多把系統搞掛的風險,可重複操做性強,重複升級也沒有問題,也不會影響系統中的其它軟件。

固然,也有能夠繼續完善的地方,可能有兩個方面吧。

一是,openssl和openssh的編譯選項基原本說我也只是使用了必要的選項,因爲不知道操做系統自帶的openssl和openssh本來的編譯選項是什麼,因此咱們編譯出來的openssl和openssh軟件在功能特性上只是儘量地接近原有的,安全性和性能可能也是有差別的。

二是,我複用了操做系統原有的sshd服務的配置文件和啓動腳本,這可能沒法充分利用新版本openssh的特性。openssl和openssh原本也是挺複雜的東西,一時半會可能也很難徹底弄明白。

可是,無論怎麼說,這種升級方式,應該會比強制升級openssl和openssh的方式好不少。


#######################################################################################

2020年3月20日更新:

我如今以爲實際不必定須要手工編譯升級OpenSSH,咱們使用yum update升級openssh小版本後已經能修復一些嚴重的漏洞了,固然這個時候使用漏洞掃描工具仍是能掃出一些漏洞,畢竟未編譯升級的話openssh版本仍是較低。可是,在生產環境中,咱們一般會使用堡壘機,對全部生產環境服務器的ssh訪問均需經過堡壘機進行,爲達到該目的,咱們一般會在服務器的/etc/hosts.allow文件中放通堡壘機的IP以容許堡壘機訪問,而在/etc/hosts.deny文件中拒絕全部其它IP的登陸訪問。這樣一來,即使是在服務器內網,漏洞掃描工具在對服務器進行漏洞掃描時,掃描工具根本就鏈接不上全部生產服務器的ssh端口,這樣漏洞掃描工具根本就掃不出ssh的漏洞。我不以爲這是自欺欺人,由於IP防禦也是系統防禦的一種,IP防禦已經能解決不少問題了。假設有人想要利用openssh的漏洞來黑系統的話,他就會跟漏洞掃描工具同樣,根本找不到漏洞。

相關文章
相關標籤/搜索