跳轉到內容

OpenSSH/日誌和故障排除

100% developed
來自 Wikibooks,開放世界中的開放書籍

OpenSSH 客戶端和伺服器都提供了許多選擇,可以選擇日誌寫入的位置以及收集的資訊量。

日誌記錄的先決條件是使用網路時間協議 (NTP) 或等效服務擁有準確的系統時鐘,該服務提供與世界其他地區持續的時間同步。日誌中的時間戳越準確,在機器或站點或服務提供商之間協調取證的速度就越快。如果您需要聯絡外部方(例如服務提供商),通常只有在時間非常精確的情況下才能取得進展。

伺服器日誌

[編輯 | 編輯原始碼]

預設情況下,sshd(8) 使用日誌級別 INFO 和系統日誌裝置 AUTH 將日誌資訊傳送到系統日誌。因此,查詢來自 sshd(8) 的日誌資料的地方在 /var/log/auth.log 中。這些預設值可以使用 SyslogFacilityLogLevel 指令覆蓋。以下是授權日誌中典型的伺服器啟動條目。

Mar 19 14:45:40 eee sshd[21157]: Server listening on 0.0.0.0 port 22.
Mar 19 14:45:40 eee sshd[21157]: Server listening on :: port 22.

在大多數情況下,預設的日誌級別就足夠了,但在測試新服務或活動時,有時需要更多資訊。除錯資訊通常會寫入 stderr。從 OpenSSH 7.6 開始,Match 塊可以為特定條件設定備用日誌級別。

下面的日誌摘錄顯示了相同的基本伺服器啟動,但增加了詳細資訊。將下面的 DEBUG1 日誌級別與上面的預設日誌級別進行對比

debug1: sshd version OpenSSH_6.8, LibreSSL 2.1
debug1: private host key #0: ssh-rsa SHA256:X9e6YzNXMmr1O09LVoQLlCau2ej6TBUxi+Y590KVsds
debug1: private host key #1: ssh-dss SHA256:XcPAY4soIxU2IMtYmnErrVOjKEEvCc3l5hOctkbqeJ0
debug1: private host key #2: ecdsa-sha2-nistp256 SHA256:QIWi4La8svQSf5ZYow8wBHN4tF0jtRlkIaLCUQRlxRI
debug1: private host key #3: ssh-ed25519 SHA256:fRWrx5HwM7E5MRcMFTdH95KwaExLzAZqWlwULyIqkVM
debug1: rexec_argv[0]='/usr/sbin/sshd'
debug1: rexec_argv[1]='-d'
debug1: Bind to port 22 on 0.0.0.0.
Server listening on 0.0.0.0 port 22.
debug1: Bind to port 22 on ::.
Server listening on :: port 22.

以下是使用最詳細級別 DEBUG3 的相同啟動

debug2: load_server_config: filename /etc/ssh/sshd_config
debug2: load_server_config: done config len = 217
debug2: parse_server_config: config /etc/ssh/sshd_config len 217
debug3: /etc/ssh/sshd_config:52 setting AuthorizedKeysFile .ssh/authorized_keys
debug3: /etc/ssh/sshd_config:86 setting UsePrivilegeSeparation sandbox          
debug3: /etc/ssh/sshd_config:104 setting Subsystem sftp internal-sftp 
debug1: sshd version OpenSSH_6.8, LibreSSL 2.1
debug1: private host key #0: ssh-rsa SHA256:X9e6YzNXMmr1O09LVoQLlCau2ej6TBUxi+Y590KVsds
debug1: private host key #1: ssh-dss SHA256:XcPAY4soIxU2IMtYmnErrVOjKEEvCc3l5hOctkbqeJ0
debug1: private host key #2: ecdsa-sha2-nistp256 SHA256:QIWi4La8svQSf5ZYow8wBHN4tF0jtRlkIaLCUQRlxRI
debug1: private host key #3: ssh-ed25519 SHA256:fRWrx5HwM7E5MRcMFTdH95KwaExLzAZqWlwULyIqkVM
debug1: rexec_argv[0]='/usr/sbin/sshd'
debug1: rexec_argv[1]='-ddd'
debug2: fd 3 setting O_NONBLOCK
debug1: Bind to port 22 on 0.0.0.0.
Server listening on 0.0.0.0 port 22.
debug2: fd 4 setting O_NONBLOCK
debug1: Bind to port 22 on ::.

每次失敗的登入嘗試都會被記錄,一旦指令 MaxAuthTries 中的值超過,連線就會斷開。以下是日誌摘錄,顯示了一些失敗嘗試後預設日誌的外觀

...
Mar 19 11:11:06 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:06 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:07 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:08 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:09 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:10 server sshd[54798]: Failed password for root from 122.121.51.193 port 59928 ssh2
Mar 19 11:11:10 server sshd[54798]: error: maximum authentication attempts exceeded for root from 122.121.51.193 port 59928 ssh2 [preauth]
Mar 19 11:11:10 server sshd[54798]: Disconnecting authenticating user root 122.121.51.193 port 59928: Too many authentication failures [preauth]
...

通常最好不要允許 root 登入,至少不要透過密碼身份驗證進行 root 登入。阻止 root 的密碼身份驗證可以極大地簡化日誌分析,特別是它消除了耗時的疑問,即誰在試圖登入以及為什麼。需要完全 root 級許可權的人可以透過 su(1) 獲得常規活動許可權。或者,對於需要 root 級許可權的特定任務,可以透過為 sudo(8)doas(1) 建立的自定義條目授予這些許可權。請注意,在這種情況下,只應允許特定服務和程式,而不是像 sudo(8) 中常見的錯誤配置那樣,允許完全訪問許可權。或者,可以使用使用 forced-commands-only 建立的單用途金鑰,因為有些人認為提供額外的提權方法(例如 su(1)sudo(8)doas(1))比透過與特定功能繫結的金鑰或證書謹慎地提供遠端 root 訪問許可權更危險。

成功登入

[編輯 | 編輯原始碼]

預設情況下,伺服器不會儲存太多關於使用者事務的資訊。這是一件好事。認識到系統按預期執行時也是一件好事。以下是一個成功 SSH 登入的示例

Mar 14 19:50:59 server sshd[18884]: Accepted password for fred from 192.0.2.60 port 6647 ssh2

以下是一個使用金鑰進行身份驗證的示例。它顯示金鑰指紋作為 base64 中的 SHA256 雜湊。

Mar 14 19:52:04 server sshd[5197]: Accepted publickey for fred from 192.0.2.60 port 59915 ssh2: RSA SHA256:5xyQ+PG1Z3CIiShclJ2iNya5TOdKDgE/HrOXr21IdOo

以下是一個使用使用者證書成功進行身份驗證的示例。證書的標識字串為“foobar”,序列號為“9624”。在此示例中,證書使用 ECDSA,而金鑰本身使用 Ed25519。證書本身是另一個不同的金鑰,具有與身份驗證金鑰本身不同的 SHA256 指紋。

May 15 16:28:17 server sshd[50140]: Accepted publickey for fred from 192.0.2.60 port 44456 ssh2: ECDSA-CERT SHA256:qGl9KiyXrG6mIOo1CT01oHUvod7Ngs5VMHM14DTbxzI ID foobar (serial 9624) CA ED25519 SHA256:fZ6L7TlBLqf1pGWzkcQMQMFZ+aGgrtYgRM90XO0gzZ8

在 6.8 之前,金鑰的指紋是十六進位制的 MD5 雜湊。

Jan 28 11:51:43 server sshd[5104]: Accepted publickey for fred from 192.0.2.60 port 60594 ssh2: RSA e8:31:68:c7:01:2d:25:20:36:8f:50:5d:f9:ee:70:4c

在 6.3 之前的舊版本 OpenSSH 中,金鑰指紋完全缺失於身份驗證日誌記錄中。

Jan 28 11:52:05 server sshd[1003]: Accepted publickey for fred from 192.0.2.60 port 20042 ssh2

以下是一個使用伺服器的內部 sftp 子系統進行 SFTP 會話的密碼身份驗證示例。該子系統的日誌記錄設定為 INFO。

Mar 14 20:14:18 server sshd[19850]: Accepted password for fred from 192.0.2.60 port 59946 ssh2
Mar 14 20:14:18 server internal-sftp[11581]: session opened for local user fred from [192.0.2.60]

以下是一個使用 RSA 金鑰進行身份驗證的成功 SFTP 登入示例。

Mar 14 20:20:53 server sshd[10091]: Accepted publickey for fred from 192.0.2.60 port 59941 ssh2: RSA SHA256:LI/TSnwoLryuYisAnNEIedVBXwl/XsrXjli9Qw9SmwI
Mar 14 20:20:53 server internal-sftp[31070]: session opened for local user fred from [192.0.2.60]

藉助 xinetd,可以記錄其他資料,例如連線持續時間。

SSH 證書身份驗證的日誌問題

[編輯 | 編輯原始碼]

通常,不會提供太多關於哪個證書失敗的資訊,只會說明為什麼它身份驗證失敗。查詢相關帳戶或實際證書可能需要一些調查。通常不會公開客戶端資訊,所有調查都必須在伺服器端進行。

如果透過其他方式(例如密碼)再次嘗試身份驗證,那麼在連線關閉時,將有一個日誌條目記錄了哪個帳戶參與其中。這是因為連線序列的早期階段,斷開連線的程序 ID 相同,並且會包含帳戶名稱和來源地址,從而為尋求解決方案提供一些線索。有時甚至會包含帳戶名稱。

May  5 16:31:38 server sshd[252]: Connection closed by authenticating user fred 192.0.2.60 port 44470 [preauth]

但是,如果允許連線超時,而沒有首先透過其他方式進行任何其他身份驗證嘗試,那麼除了可能的時間之外,將無從得知。

May  5 16:33:00 server sshd[90593]: fatal: Timeout before authentication for 192.0.2.60 port 44718

以下是基於證書的登入嘗試失敗的一些常見日誌條目示例。證書可能存在多個問題,但每次只記錄一個錯誤。

已過期或尚未有效的證書

[編輯 | 編輯原始碼]

尚未生效或已過期的證書會生成關於原因的日誌條目,但不會生成相關帳戶或證書。

May  5 16:35:20 server sshd[252]: error: Certificate invalid: expired

以上是已過期證書,以下是尚未生效的證書。

May  5 16:58:00 server sshd[90593]: error: Certificate invalid: not yet valid

兩種型別的事件都不會提供更多資訊。

有效證書但主體無效

[編輯 | 編輯原始碼]

與已過期證書類似,不會提供太多關於實際帳戶或證書的資訊。這裡使用錯誤的帳戶嘗試了證書,該帳戶不在證書的主體中列出。

May  5 17:29:52 server sshd[98884]: error: Certificate invalid: name is not a listed principal
May  5 17:29:56 server sshd[98884]: Connection closed by authenticating user fred 192.0.2.60 port 45114 [preauth]

如果客戶端故意關閉連線,則連線關閉條目中可能包含一些資訊。

有效證書但源地址無效

[編輯 | 編輯原始碼]

如果證書僅限於從特定地址或主機名連線,則如果連線來自不同的地址或主機,日誌會抱怨並識別不正確的源地址。

May  5 17:48:54 server sshd[2420]: cert: Authentication tried for fred with valid certificate but not from a permitted source address (192.0.2.61).
May  5 17:48:54 server sshd[2420]: error: Refused by certificate options

但是,無法直接識別特定證書。

記錄 SFTP 檔案傳輸

[編輯 | 編輯原始碼]

可以使用 **LogLevel** INFO 或 VERBOSE 記錄 SFTP 檔案傳輸。SFTP 伺服器的日誌級別可以在 sshd_config(5) 中設定,與常規 SSH 伺服器設定分開。

Subsystem internal-sftp -l INFO

預設情況下,SFTP 訊息也會出現在 auth.log 中,但可以透過重新配置系統記錄器(通常是 **rsyslogd(8)** 或 **syslogd(8)**)將這些訊息過濾到它們自己的檔案。有時這可以透過將日誌工具程式碼從預設的 AUTH 更改為 LOCAL0 到 LOCAL7,以及不太常用的 DAEMON 和 USER 來實現。

Subsystem internal-sftp -l INFO -f LOCAL6

如果分配了新的系統日誌檔案,請務必記住在日誌輪換中也要包含它們。同樣,可以使用 **Match** 指令更改特定連線的日誌級別。

以下日誌摘錄是在使用日誌級別 INFO 時生成的。會話以開啟開始,以關閉結束。方括號中的數字是 SFTP 會話的程序 ID,是跟蹤日誌中會話的唯一方法。

Oct 22 11:59:45 server internal-sftp[4929]: session opened for local user fred from [192.0.2.33]
...
Oct 22 12:09:10 server internal-sftp[4929]: session closed for local user fred from [192.0.2.33]

下面是將名為 **foo** 的 928 位元組小檔案上傳到使用者“fred”的主目錄的 SFTP 上傳操作。

Oct 22 11:59:50 server internal-sftp[4929]: open "/home/fred/foo" flags WRITE,CREATE,TRUNCATE mode 0664
Oct 22 11:59:50 server internal-sftp[4929]: close "/home/fred/foo" bytes read 0 written 928

以及在同一會話中對目錄 ** /var/www ** 的目錄列表。

Oct 22 12:07:59 server internal-sftp[4929]: opendir "/var/www"
Oct 22 12:07:59 server internal-sftp[4929]: closedir "/var/www"

最後是下載與使用者“fred”主目錄中名為 **foo** 的相同 928 位元組小檔案。

Oct 22 12:08:03 server internal-sftp[4929]: open "/home/fred/foo" flags READ mode 0666
Oct 22 12:08:03 server internal-sftp[4929]: close "/home/fred/foo" bytes read 928 written 0

成功的傳輸將透過一條 close 訊息記錄。嘗試下載(開啟)不存在的檔案將緊隨其後出現一條 sent status No such file 訊息,而不是一條 close 訊息。存在但使用者無權讀取的檔案將建立一條 sent status Permission denied 訊息。

記錄 Chrooted SFTP

[編輯 | 編輯原始碼]

在 chroot 監獄(由 **ChrootDirectory** 定義)中使用內建 **sftp-subsystem** 記錄日誌需要在監獄記憶體在一個 **./dev/log** 節點。這可以透過在啟動時讓系統記錄器(如 syslogd(8))在 chrooted 目錄中新增額外的日誌套接字來實現。在某些系統上,這隻需簡單地新增更多標誌,例如“**-u -a /chroot/dev/log**”,在 ** /etc/rc.conf.local ** 中或任何等效的啟動指令碼中。

下面是使用 SFTP-subsystem 的日誌級別 DEBUG3 登入到 chroot 監獄的 SFTP 登入示例(使用密碼)。日誌顯示了檔案上傳。

Jan 28 12:42:41 server sshd[26299]: Connection from 192.0.2.60 port 47366
Jan 28 12:42:42 server sshd[26299]: Failed none for fred from 192.0.2.60 port 47366 ssh2
Jan 28 12:42:44 server sshd[26299]: Accepted password for fred from 192.0.2.60 port 47366 ssh2
Jan 28 12:42:44 server sshd[26299]: User child is on pid 21613
Jan 28 12:42:44 server sshd[21613]: Changed root directory to "/home/fred"
Jan 28 12:42:44 server sshd[21613]: subsystem request for sftp
Jan 28 12:42:44 server internal-sftp[2084]: session opened for local user fred from [192.0.2.60]
Jan 28 12:42:58 server internal-sftp[2084]: open "/docs/somefile.txt" flags WRITE,CREATE,TRUNCATE mode 0644
Jan 28 12:42:58 server internal-sftp[2084]: close “/docs/somefile.txt” bytes read 0 written 400

請記住,SFTP 是一個單獨的子系統,與檔案建立模式一樣,日誌級別和日誌工具在 sshd_config(5) 中的設定與 SSH 伺服器分開。

Subsystem internal-sftp -l ERROR

記錄客戶端連線的穩定性

[編輯 | 編輯原始碼]

當在伺服器的配置中設定 **ClientAliveInterval** 時,伺服器會定期探測已建立連線的客戶端。在正常的日誌級別下,這些探測不會在日誌中記錄,除非出現錯誤。

如果 **ClientAliveInterval** 被連續超過 **ClientAliveCountMax** 允許的次數,則客戶端將被正式宣佈斷開連線,並且連線將被斷開。在預設的日誌級別 INFO 下,將記錄一條簡短的訊息,標識已斷開的客戶端。

Sep  6 14:42:08 eee sshd[83709]: packet_write_poll: Connection from 192.0.2.97 port 57608: Host is down

在日誌級別 DEBUG 下,伺服器將記錄客戶端對輪詢的響應,表明會話仍然處於連線狀態。

Sep  6 14:27:52 eee sshd[9075]: debug1: Got 100/147 for keepalive

日誌級別 DEBUG2 和 DEBUG3 將提供有關連線的更多資訊。但是,即使在日誌級別 DEBUG3 下,特定被輪詢的客戶端也不會在日誌訊息中直接標識,必須從守護程序的程序 ID 中推斷出來(如果需要此類資訊)。

Sep  6 14:30:59 eee sshd[73960]: debug2: channel 0: request keepalive@openssh.com confirm 1
Sep  6 14:30:59 eee sshd[73960]: debug3: send packet: type 98
Sep  6 14:30:59 eee sshd[73960]: debug3: receive packet: type 100
Sep  6 14:30:59 eee sshd[73960]: debug1: Got 100/22 for keepalive

同樣,當 **ClientAliveCountMax** 被超過時,在客戶端最後一次未能響應之後,連線將斷開。以下是如何在將日誌級別設定為 DEBUG2 時的情況。

Sep  6 14:17:55 eee sshd[15780]: debug2: channel 0: request keepalive@openssh.com confirm 1
Sep  6 14:17:55 eee sshd[15780]: debug1: Got 100/22 for keepalive
Sep  6 14:18:37 eee sshd[15780]: debug2: channel 0: request keepalive@openssh.com confirm 1
Sep  6 14:18:37 eee sshd[15780]: packet_write_poll: Connection from 192.0.2.97 port 57552: Host is down
Sep  6 14:18:37 eee sshd[15780]: debug1: do_cleanup
Sep  6 14:18:37 eee sshd[48675]: debug1: do_cleanup
Sep  6 14:18:37 eee sshd[48675]: debug1: session_pty_cleanup: session 0 release /dev/ttyp0

指令 **ClientAliveInterval** 和 **ClientAliveCountMax** 通常適用於連線到伺服器的所有客戶端。但是,它們可以在 **Match** 塊內使用,因此僅適用於特定連線。

記錄被吊銷的金鑰

[編輯 | 編輯原始碼]

如果使用 **RevokedKeys** 指令指向已被吊銷的公鑰列表,則 sshd(8) 將在嘗試使用被吊銷的金鑰進行訪問時記錄日誌條目。無論使用的是公鑰的明文列表,還是已生成的二進位制金鑰吊銷列表 (KRL),該條目都將相同。

如果允許密碼身份驗證,並且使用者嘗試使用密碼身份驗證,則在金鑰身份驗證失敗後,將記錄密碼身份驗證的記錄。

Mar 14 20:36:40 server sshd[29235]: error: Authentication key RSA SHA256:jXEPmu4thnubqPUDcKDs31MOVLQJH6FfF1XSGT748jQ revoked by file /etc/ssh/ssh_revoked_keys
...
Mar 14 20:36:45 server sshd[29235]: Accepted password for fred from 192.0.2.10 port 59967 ssh2

如果不允許密碼身份驗證,則 sshd(8) 將在金鑰失敗後立即關閉連線。

Mar 14 20:38:27 server sshd[29163]: error: Authentication key RSA SHA256:jXEPmu4thnubqPUDcKDs31MOVLQJH6FfF1XSGT748jQ revoked by file /etc/ssh/ssh_revoked_keys
...

嘗試使用被吊銷的金鑰的帳戶仍然是個謎,因此,您需要使用 ssh-keygen -lf 從舊金鑰存檔中按指紋查詢金鑰,並閱讀金鑰的註釋。但是,如果有效帳戶在金鑰嘗試失敗後取消了連線而沒有嘗試密碼,則通常的訊息仍將釋出到日誌中。

Mar 14 20:44:04 server sshd[14352]: Connection closed by authenticating user fred 192.0.2.237 port 55051 [preauth]
...

這可能會提供一些線索,並允許使用簡短的 AWK 指令碼進行過濾(如果所有訊息都在同一個日誌檔案中)。

$ awk '/revoked by file/ {
        pid[$5]++; key[$5]=$9; hash[$5]=$10; next;
    }
    pid[$5] && /closed by authenticating user/ {
        print key[$5], hash[$5], $10, $11;
        delete key[$5]; delete hash[$5]; delete pid[$5];
    }' /var/log/authlog

同樣,如果客戶端沒有嘗試登入,只是超時,則訊息將只說明這一點。

Mar 18 21:40:25 server sshd[9942]: fatal: Timeout before authentication for 198.51.100.236 port 53728
...

在客戶端方面,如果嘗試使用被吊銷的金鑰,不會發出任何警告或錯誤。它只會失敗,並將嘗試下一個金鑰或方法。

暴力攻擊和 Hail Mary 攻擊

[編輯 | 編輯原始碼]

在伺服器連線到網路後,幾乎立即看到登入嘗試失敗是相當常見的。暴力攻擊(一臺機器對幾個帳戶進行錘擊以嘗試找到有效的密碼)變得越來越少見。部分原因是資料包過濾器(如 Linux 的 NFables 和 BSD 的 PF)可以限制來自單個主機的連線嘗試的數量和速率。伺服器配置指令 **MaxStartups** 可以限制同時進行的未經身份驗證的連線數量。

...
Mar 18 18:54:44 server sshd[54939]: Failed password for root from 201.179.249.231 port 52404 ssh2
Mar 18 18:54:48 server sshd[54939]: Failed password for root from 201.179.249.231 port 52404 ssh2
Mar 18 18:54:49 server sshd[54939]: Failed password for root from 201.179.249.231 port 52404 ssh2
Mar 18 18:54:49 server sshd[54939]: error: maximum authentication attempts exceeded for root from 201.179.249.231 port 52404 ssh2 [preauth]
Mar 18 18:54:49 server sshd[54939]: Disconnecting authenticating user root 201.179.249.231 port 52404: Too many authentication failures [preauth]
...

請注意,從 OpenSSH 7.5 開始,當嘗試使用有效的使用者名稱時,日誌中會出現“正在驗證使用者”。當嘗試使用無效的使用者名稱時,也會記錄此資訊。

...
Mar 18 18:55:05 server sshd[38594]: Invalid user ubnt from 201.179.249.231 port 52471
Mar 18 18:55:05 server sshd[38594]: Failed password for invalid user ubnt from 201.179.249.231 port 52471 ssh2
Mar 18 18:55:09 server sshd[38594]: error: maximum authentication attempts exceeded for invalid user ubnt from 201.179.249.231 port 52471 ssh2 [preauth]
Mar 18 18:55:09 server sshd[38594]: Disconnecting invalid user ubnt 201.179.249.231 port 52471: Too many authentication failures [preauth]
...

處理來自單個機器或網路的暴力攻擊的方法是自定義伺服器主機的資料包過濾器,以限制攻擊,甚至暫時阻止超載最大連線數量或速率的機器。或者,您還可以聯絡攻擊者網路塊的所有者,提供 IP 地址以及攻擊的確切日期和時間。

在撰寫本文時,一種常見的攻擊型別是分佈在大量受損機器上的攻擊,每臺機器在攻擊伺服器中只扮演著很小的角色。

要處理 Hail Mary 攻擊,請聯絡攻擊者網路塊的所有者。如果提供確切的時間和地址,則可以使用帶有從日誌中剪下貼上的摘錄的格式信。或者,網路或系統管理員團隊可以協同工作,彙集資料以識別並封鎖參與攻擊的受損主機。

對無效使用者的失敗的 None

[編輯 | 編輯原始碼]

SSH 協議指定了許多可能的身份驗證方法[1]。方法 passwordkeyboard-interactivepublickey 相當常見。一個鮮為人知的身份驗證方法是 none,它只有在伺服器不需要進一步的身份驗證時才會成功,例如,如果設定了 **PermitEmptyPassword**,並且帳戶實際上沒有密碼[2]。包括 OpenSSH 在內的一些 SSH 客戶端會先要求 none 身份驗證,然後使用剩餘的可能身份驗證方法列表來決定如果它不起作用下一步該怎麼做。

...
Aug 10 19:09:05 server sshd[93126]: Failed none for invalid user admin from 125.64.94.136 port 27586 ssh2
...

換句話說,這是一個嘗試使用 none 身份驗證方法的暴力攻擊。它是一種攻擊,只有在明確設定為空密碼並且還專門設定了允許訪問的帳戶才能進入,方法是同時啟用 none 身份驗證方法和伺服器上的 **PermitEmptyPasswords** 配置指令。大多數暴力攻擊只嘗試 password 身份驗證,其中一些攻擊甚至會檢查 password 方法,如果不可用,則放棄。其他攻擊者可能會無謂地反覆錘擊,即使該方法不可用。

看似來自 127.0.0.1、::1 或其他本地主機地址的連線

[edit | edit source]

當 SSH 伺服器透過反向隧道訪問另一臺機器時,傳入的連線將看起來來自本地主機地址,通常是127.0.0.1::1

Mar 23 14:16:16 server sshd[9265]: Accepted password for fred from 127.0.0.1 port 40426 ssh2

如果反向隧道另一端的埠對公眾開放,它將被探測並可能受到攻擊。由於反向隧道,攻擊也似乎來自伺服器自己的迴環地址。

Mar 23 14:20:17 server sshd[5613]: Invalid user cloud from ::1 port 57404
Mar 23 14:20:21 server sshd[5613]: Failed password for invalid user cloud from ::1 port 57404 ssh2
Mar 23 14:20:26 server sshd[5613]: Failed password for invalid user cloud from ::1 port 57404 ssh2
Mar 23 14:20:32 server sshd[5613]: Failed password for invalid user cloud from ::1 port 57404 ssh2
Mar 23 14:20:35 server sshd[5613]: Connection closed by invalid user cloud ::1 port 57404 [preauth]

因此,通常的應對措施(如 SSHGuard 或 Fail2Ban 或其他類似的入侵檢測系統)無法使用,因為本地主機地址被隧道用於所有登入嘗試,無論其真實來源如何。

一個部分解決方案是將傳入連線繫結到不同的 IP 地址。迴環介面將需要一個額外的永久地址,一個別名,為此。該別名可以在建立反向隧道時分配。

$ ssh -R 2022:127.2.2.1:22 fred@vps.example.org

因此,它將指定透過該隧道傳入的所有登入的源地址。因此,以這種方式,別名將顯示在日誌中,而不是使用反向隧道時預設的迴環地址。

Mar 23 18:00:13 server sshd[8525]: Invalid user cloud from 127.2.2.1 port 17271
Mar 23 18:00:15 server sshd[8525]: Failed password for invalid user cloud from 127.2.2.1 port 17271 ssh2
Mar 23 18:00:19 server sshd[8525]: Failed password for invalid user cloud from 127.2.2.1 port 17271 ssh2
Mar 23 18:01:23 server sshd[8525]: Failed password for invalid user cloud from 127.2.2.1 port 17271 ssh2
Mar 23 18:01:26 server sshd[8525]: Connection closed by invalid user cloud 127.2.2.1 port 17271 [preauth]

如果埠不需要對開放的網際網路可用,一個完整的解決方案就是確保它們無法從外部訪問。這可以透過在建立反向隧道時不在客戶端使用-g選項,或者透過將sshd_config(5)中的GatewayPorts指令恢復為預設的no,或者兩者都做來完成。系統的內建資料包過濾器也可以使用。然後,即使將轉發埠從外部關閉,ProxyJump選項仍然可以用來跳過跳轉主機並使用設定進行 SSH 訪問。然而,由於這些埠有時需要對外部世界可用,因此這種方法並不總是一個選擇。

客戶端日誌記錄

[edit | edit source]

OpenSSH 客戶端通常將日誌資訊傳送到stderr-y選項可用於將輸出傳送到系統日誌,由syslogd(8)或類似程式管理。客戶端日誌詳細程度可以透過更改ssh_config(5)中的LogLevel指令來增加或減少,並透過SyslogFacility指令更改日誌設施。兩者都需要使用-y執行時選項,如果沒有它,它們什麼也不做。

或者,可以使用-E選項將日誌輸出傳送到指定檔案,而不是stderr,而不是使用-y選項。當在自動指令碼中執行ssh(1)時,使用系統日誌或單獨的日誌檔案是很有用的。以下是一個連線到互動式 shell 的示例,其中包含正常級別的客戶端日誌記錄。

$ ssh -l fred server.example.org    
fred@server.example.org‘s password: 
Last login: Thu Jan 27 13:21:57 2011 from 192.168.11.1

相同連線在第一個詳細級別給出大量的除錯資訊,多 42 行。

$ ssh -v -l fred server.example.org
OpenSSH_6.8, LibreSSL 2.1
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to server.example.org [198.51.100.20] port 22.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /home/fred/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.8
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.7
debug1: match: OpenSSH_6.7 pat OpenSSH* compat 0x04000000
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr umac-64-etm@openssh.com none
debug1: kex: client->server aes128-ctr umac-64-etm@openssh.com none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:CEXGTmrVgeY1qEiwFe2Yy3XqrWdjm98jKmX0LK5mlQg
debug1: Host '198.51.100.20' is known and matches the ECDSA host key.
debug1: Found key in /home/fred/.ssh/known_hosts:2
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Trying private key: /home/fred/.ssh/id_rsa
debug1: Trying private key: /home/fred/.ssh/id_dsa
debug1: Trying private key: /home/fred/.ssh/id_ecdsa
debug1: Trying private key: /home/fred/.ssh/id_ed25519
debug1: Next authentication method: keyboard-interactive
debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Next authentication method: password
debug1: Authentication succeeded (password).
Authenticated to server.example.org ([198.51.100.20]:22).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 2 clearing O_NONBLOCK
Last login: Sat Mar 14 21:31:33 2015 from 192.0.2.111

...

相同登入使用最大詳細級別,-vvv,給出大約 150 行除錯資訊。請記住,除錯資訊傳送到stderr而不是stdout。這隻會將會話捕獲到檔案中,除錯資訊只發送到螢幕,而不是輸出日誌。

$ ssh -vvv -l fred  somehost.example.org  | tee ~/ssh-output.log

工具tee(1)就像一個 T 管,將輸出傳送到兩個方向,一個到stdout,另一個到檔案。

以下將同時捕獲除錯資訊和會話文字。

$ ssh -vvv -l fred  somehost.example.org  2>&1  | tee ~/ssh-output.log

單獨捕獲客戶端除錯資訊

[edit | edit source]

常規管道和重定向僅適用於stdout,因此如果未使用-E捕獲除錯輸出,則必須將stderr上的輸出傳送到 stdout,如果要同時捕獲它和實際會話。這是透過額外的重定向2>&1來捕獲stderr完成的。注意空格,或空格的缺乏。

在執行時或動態更改客戶端除錯級別

[edit | edit source]

在執行時,在建立新連線時,只需使用-v選項。

$ sftp -v -o "IdentityFile=~/.ssh/weblog.key_rsa" fred@server.example.org

客戶端上的除錯詳細程度可以像伺服器一樣增加。

$ sftp -vvv -o "IdentityFile=~/.ssh/weblog.key_rsa" fred@server.example.org

額外的資訊可以用來準確地檢視正在傳送到伺服器或從伺服器請求的內容。

事後,一旦連線建立,轉義序列~v~V可以用來動態增加或減少詳細程度。透過它們,可以在已建立的連線中更改客戶端的詳細程度。當增加時,客戶端會將其日誌級別提高到 VERBOSE、DEBUG、DEBUG2 和 DEBUG3,按此順序,如果從預設的 INFO 開始。相反,當降低日誌級別時,客戶端將從預設的 INFO 開始,依次降至 ERROR、FATAL 和 QUIET。

除錯和故障排除

[edit | edit source]

在故障排除時,伺服器日誌是你的好幫手。可能需要暫時提高那裡的日誌級別以獲取更多資訊。然後,在問題修復後,還需要將它們恢復到正常狀態,以避免隱私問題或過度使用磁碟空間。

例如,SFTP 子系統日誌記錄預設設定為 ERROR,僅報告錯誤。要跟蹤客戶端執行的事務,請將日誌級別更改為 INFO 或 VERBOSE。

Subsystem internal-sftp  -l INFO

注意。再次,使用更高的日誌級別將違反使用者的隱私,此外還會佔用大量的磁碟空間,因此通常不應在生產環境中使用,一旦找出更改。在收集期間,更高的日誌訊息應該真正傳送到單獨的日誌檔案。

預設情況下,一些系統只將正常訊息傳送到常規系統日誌檔案,並忽略更高的訊息。一些系統預設情況下儲存所有訊息。如果更高的系統日誌訊息沒有顯示在任何系統日誌中,則可能是前者導致的。無論哪種方式,請檢查系統日誌配置,並確保額外的訊息只發送到單獨的日誌檔案,而不是與常規系統日誌混合。如有必要,更改配置。這有助於保持日誌整潔,並保護隱私。系統日誌設定位於系統日誌守護程式的配置檔案中,其確切名稱會根據安裝的內容而有所不同,但常見的有syslog.conf(5)和 rsyslog.conf(5)。注意,以下機器配置將 AUTH 設施的更詳細的 DEBUG 訊息傳送到與常規 AUTH 訊息不同的單獨日誌檔案。

$ grep '^auth\.' /etc/syslog.conf 
auth.info                                               /var/log/authlog
auth.debug                                              /var/log/authdebug

有關日誌設施和日誌級別的資訊,請參見syslog(3)。最好限制收集除錯資訊的時間,並主動監控收集過程。但是,如果它運行了很長時間,尤其是如果它無人看管即使是短時間,請務必記住將特殊日誌檔案新增到日誌輪轉計劃中,以防止它填滿分割槽。

Match 塊可以透過為特定情況設定日誌級別來提供幫助,並避免所有內容都被密集記錄的情況。

此外,OpenSSH 手冊頁寫得非常好,很多時候可以透過在正確的手冊頁中找到正確的部分來解決問題。至少,重要的是要瀏覽所有四個主要程式手冊頁及其配置,並熟悉至少各節標題。

然後,一旦在手冊頁中找到正確的部分,就仔細閱讀它,並熟悉其內容。其他 OpenSSH 手冊頁也是如此,具體取決於活動。請務必使用適用於您系統的 OpenSSH 版本以及相應的手冊頁,最好是安裝在您系統上的手冊頁,以避免不匹配。在某些情況下,客戶端和伺服器的版本不同,因此必須分別查詢每個版本的手冊頁。在釋出新版本時,檢視 OpenSSH 的發行說明也是一個好主意。

除了以下幾個例外,故障排除的具體示例通常在與特定活動相關的食譜部分中給出。因此,例如,對身份驗證金鑰問題的排序是在公鑰身份驗證本身部分完成的。

除錯使用 sudo(8) 的指令碼、配置或金鑰

[編輯 | 編輯原始碼]

通常,只有在編寫和測試指令碼、新配置、一些新金鑰或同時進行所有操作時,才需要更改日誌級別。在使用sudo(8)時,尤其需要檢視客戶端傳送的精確資訊,以便將正確的模式輸入到/etc/sudoers中以確保安全。使用最低的詳細程度,客戶端傳送到遠端伺服器的精確字串將顯示在除錯輸出中。

$ rsync -e "ssh -v -i /home/webmaint/.ssh/bkup_key -l webmaint" \
        -a server.example.org:/var/www/ var/backup/www/
...
debug1: Authentication succeeded (publickey).
Authenticated to server.example.org ([192.0.2.20]:22).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: Sending command: rsync --server --sender -vlogDtpre.if . /var/www/
receiving incremental file list
...

假設帳戶“webmaint”位於組“webmasters”中,sudoers需要類似以下內容:

%webmasters ALL=(ALL) NOPASSWD: /usr/local/bin/rsync --server \
--sender -vlogDtpre.if . /var/www/

同樣的方法可以用來除錯新的伺服器配置或金鑰登入。一旦將設定調整到需要執行的方式,就可以將sshd(8)的日誌級別設定為INFO,將internal-sftp的日誌級別設定為ERROR。此外,一旦將指令碼留在了完全自動模式下執行,就可以使用syslog(3)系統模組來設定客戶端日誌資訊,而不是使用stderr,方法是在啟動時設定-y選項。

除錯伺服器配置

[編輯 | 編輯原始碼]

在除錯模式下執行伺服器會提供有關連線的大量資訊,以及有關伺服器配置的一小部分資訊。伺服器的除錯級別(-d)可以提高一次、兩次(-dd)或三次(-ddd)。

$ /usr/sbin/sshd -d

請注意,在這種情況下,伺服器不會分離併成為守護程序,因此當SSH連線終止時,它也會終止。必須重新啟動伺服器才能從客戶端進行後續連線。儘管在某些方面這很麻煩,但它確實確保了會話資料是唯一的集合,而不是多個會話的混合,因此可能是不同的配置。或者,另一個選項(-e)是在除錯時將除錯資料傳送到stderr以保持系統日誌清潔。

在OpenSSH的最新版本中,還可以直接將系統日誌中的除錯資料記錄到單獨的檔案,並防止系統日誌產生噪音。從OpenSSH 6.3開始,選項-E將除錯資料追加到特定的日誌檔案,而不是將其傳送到系統日誌。這便於除錯即時系統,而不會弄亂系統日誌。

$ /usr/sbin/sshd -E /home/fred/sshd.debug.log

在舊版本的OpenSSH中,如果需要將輸出儲存到檔案,同時還要在螢幕上即時檢視它,可以使用tee(1)

$ /usr/sbin/sshd -ddd 2>&1 | tee /tmp/foo

這將透過捕獲sshd(8)傳送到stderr的內容,將輸出儲存到檔案foo中。這適用於舊版本的OpenSSH,但上面提到的-E選項更可取。

如果伺服器是遠端的,並且需要降低被鎖定的風險,可以在第二個sshd(8)例項上進行配置檔案的實驗,使用單獨的配置檔案並監聽高階口,直到設定經過測試為止。

$ /usr/sbin/sshd -dd -p 22222 -f /home/fred/sshd_config.test

可以對配置檔案進行擴充套件測試(-T)。如果存在語法錯誤,它將被報告,但請記住,即使是正確的配置也可能導致你被鎖定。擴充套件測試模式可以單獨使用,但也可以指定要與-C一起使用的特定連線引數。sshd(8)將根據傳遞給它的引數處理配置檔案,並輸出結果。特別有用的是,Match指令的結果將被顯示。因此,-T選項可以與-C選項一起使用,以準確顯示哪些配置將用於各種連線。

在將特定的連線引數傳遞給sshd(8)進行評估時,userhostaddr是擴充套件測試所需的最小引數。以下內容將打印出如果使用者fred嘗試從地址192.0.2.15登入到主機server.example.org時將應用的配置。

$ /usr/sbin/sshd -T -C user=fred,host=server.example.org,addr=192.0.2.15

還可以傳遞另外兩個引數,laddrlport。它們指的是伺服器連線到的IP號和埠。

$ /usr/sbin/sshd -T -C user=fred,host=server.example.org,addr=192.0.2.15,laddr=192.0.2.2,lport=2222

這五個變數應該能夠描述任何可能的傳入連線。

除錯客戶端配置

[編輯 | 編輯原始碼]

有時,在除錯伺服器配置時,還需要跟蹤客戶端。從OpenSSH 6.8開始,-G選項使ssh(1)在評估HostMatch塊後列印其配置,然後退出。這允許檢視客戶端實際用於特定連線的確切配置選項。

$ ssh -G -l fred server.example.org

客戶端配置透過三種方式確定。第一種是執行時選項,然後是帳戶自己的配置檔案,最後是系統範圍的客戶端配置檔案。優先順序按此順序排列,找到的第一個值將被使用。對於sftp(1),這些選項也會傳遞給ssh(1)

無效或過時的密碼或MAC

[編輯 | 編輯原始碼]

正確的客戶端將顯示失敗的詳細資訊。對於錯誤的訊息認證碼(MAC),當嘗試將像hmac-md5-96這樣的錯誤MAC強加於伺服器時,正確的客戶端可能會顯示類似以下內容

no matching mac found: client hmac-md5-96 server umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1

對於錯誤的密碼,當嘗試將arcfour密碼強加於伺服器時,正確的客戶端可能會顯示類似以下內容

no matching cipher found: client arcfour server chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com

有時,在排查客戶端問題時,需要檢視伺服器日誌。OpenSSH 6.7 中刪除了不安全的MAC,在OpenSSH 7.2 中刪除了不安全的密碼,但一些第三方客戶端可能仍然嘗試使用它們來建立連線。在這種情況下,客戶端可能不會提供太多資訊,除了伺服器意外關閉網路連線的模糊訊息之外。但是,伺服器日誌將顯示發生了什麼事情。

fatal: no matching mac found: client hmac-sha1,hmac-sha1-96,hmac-md5 server hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 [preauth]

更新的版本將顯示更簡單的錯誤訊息,用於錯誤的MAC。

fatal: Unable to negotiate with 192.0.2.37 port 55044: no matching MAC found. Their offer: hmac-md5-96 [preauth]

錯誤的密碼將像這樣報告

fatal: Unable to negotiate with 192.0.2.37 port 55046: no matching cipher found. Their offer: arcfour [preauth]

伺服器日誌中的錯誤訊息可能不會說明哪些MAC或密碼實際上可用。對於這些情況,可以使用擴充套件測試模式來顯示伺服器設定,特別是允許的MAC或密碼。在最基本的用法中,擴充套件測試模式只是-T,就像/usr/sbin/sshd -T | grep -E 'cipher|macs'一樣,沒有其他選項。有關更多詳細資訊和選項,請參見上面有關“除錯伺服器配置”部分的內容。

一種解決方案是將客戶端升級到能夠處理正確密碼和MAC的版本。另一種選擇是切換到不同的客戶端,能夠處理現代密碼或MAC的客戶端。

除錯基於金鑰的身份驗證

[編輯 | 編輯原始碼]

公鑰身份驗證失敗的最常見原因似乎是以下兩種情況中的任何一種

  • 將公鑰新增到伺服器上的authorized_keys過程中出現錯誤。
  • 涉及的檔案和目錄的許可權不正確,可能是客戶端或伺服器上的。這些目錄是用於金鑰的目錄,通常是~/.ssh/,或其父目錄,或者authorized_keys檔案,或者私鑰本身。

截至撰寫本文時,看起來郵件列表和論壇上描述的幾乎所有基於金鑰的身份驗證失敗問題,都可以透過解決這兩種情況中的任何一種或兩種來解決。因此,當遇到錯誤訊息“Permission denied (publickey,keyboard-interactive)”或類似訊息時,請參閱公鑰身份驗證部分。然後檢視sshd(8)的手冊頁及其關於授權金鑰的部分。通常,儘管並不總是如此,但當私鑰的許可權不正確時,將很明顯。

$ ssh -i ~/.ssh/fred-193.ed25519 fred@192.0.2.193
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0664 for '/home/fred/.ssh/fred-193.ed25519' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/home/fred/.ssh/fred-193.ed25519": bad permissions

除了授權金鑰檔案中的公鑰被篡改以及許可權錯誤外,還有一種非常罕見的第三種情況,即公鑰和私鑰檔案不匹配,並非來自同一金鑰對。如《公鑰認證》一節所述,公鑰和私鑰需要匹配,並且屬於同一金鑰對。這是因為,即使在 SSH 客戶端使用私鑰進行加密之前,它也會檢視所提議的私鑰的檔名,然後傳送與該名稱匹配的公鑰(如果存在)。如果客戶端上的公鑰與伺服器上 authorized_keys 檔案中的公鑰不匹配,則連線將被拒絕,並出現“Permission denied (publickey,keyboard-interactive)”或類似的錯誤。僅此一項就是給公鑰檔案取唯一的描述性名稱的充分理由。請注意,如上所述,除了客戶端機器上公鑰檔案管理不當之外,通常還有其他原因會導致相同錯誤訊息。

每個金鑰對的兩個部分的檔名必須保持一致,以便內容匹配。關於解決方案,從長遠來看,需要更加仔細地管理金鑰及其檔名。短期解決方案是刪除有問題的公鑰檔案,或者使用私鑰重新生成一個新的公鑰檔案,覆蓋有問題的檔案。再次強調,這是一個不常見的情況,並不是導致該錯誤的常見原因。

SSH 身份驗證失敗次數過多

[編輯 | 編輯原始碼]

當身份驗證代理中存在多個金鑰時,客戶端將以不可預測的順序嘗試將它們與伺服器進行匹配。如果客戶端恰好在找到正確金鑰之前嘗試了足夠多的錯誤金鑰,並且超過了伺服器的 MaxAuthTries 限制,伺服器自然會斷開連線,並顯示關於身份驗證失敗次數過多的錯誤訊息。

"Received disconnect from 203.0.113.110 port 22:2: Too many authentication failures 
Authentication failed."

在提高詳細程度後,將顯示測試和拒絕的金鑰。

$ ssh -v 203.0.113.110
...
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/fred/.ssh/key.06.rsa
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Offering RSA public key: /home/fred/.ssh/key.02.rsa
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Offering RSA public key: /home/fred/.ssh/key.03.rsa
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Offering RSA public key: /home/fred/.ssh/key.04.rsa
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Offering RSA public key: /home/fred/.ssh/key.01.rsa
debug1: Authentications that can continue: publickey,keyboard-interactive
debug1: Offering RSA public key: /home/fred/.ssh/key.05.rsa
Received disconnect from 203.0.113.110 port 22:2: Too many authentication failures
Authentication failed.

代理中的每個金鑰都帶有一個註釋,說明金鑰檔案是由使用者提供的,是在配置檔案中還是作為執行時引數提供的。客戶端優先使用在配置檔案中指定的並且當前位於代理中的金鑰。然後它將按照提供的順序嘗試這些金鑰。[3]

如果您遇到“身份驗證失敗次數過多”錯誤,則有兩種解決方案。

解決此錯誤的一種方法是使用 ssh-add(1) 命令和 -d 選項從代理中逐一刪除金鑰,直到只剩下正確的金鑰。請參考每個金鑰的檔案系統路徑,例如:ssh-add -d ~/.ssh/some.key.rsa 由於要刪除的私鑰是在代理中根據相應的公鑰查詢的,因此兩個檔案都必須存在。如果沒有匹配的公鑰檔案,則無法從身份驗證代理中單獨刪除私鑰。相反,可以使用 -D 選項一次性刪除所有金鑰。但是,當頻繁使用多個遠端系統並且需要代理保持充足的金鑰時,這樣做並不總是可行。這可能不是最實用的方法。

解決此錯誤的另一種方法,也是最實用的方法,是使用 IdentitiesOnly 配置指令結合 IdentityFile 配置指令,限制客戶端只嘗試特定金鑰。後者明確指向正確的金鑰。這兩種指令都可以作為執行時選項新增到客戶端的配置檔案中。作為執行時選項,它們可以像這樣使用

$ ssh -o IdentitiesOnly=yes -i ~/.ssh/server14.example.org.rsa -l fred server14.example.org

或者,這兩個選項可以新增到客戶端配置檔案中,例如:

Host server14 server14.example.org
        HostName server14.example.org
        IdentitiesOnly yes
        IdentityFile /home/fred/.ssh/server14.example.org.rsa
        User fred

這樣,無論是使用短名稱還是完全限定的域名,都可以訪問伺服器,只要名稱在 Host 指令下列出即可。

$ ssh server14

請記住,選項是從客戶端配置檔案中根據首個匹配項進行選擇的。由於首個匹配項優先,因此特定規則必須放在更通用的規則之前。

簽名失敗 ... 代理拒絕操作

[編輯 | 編輯原始碼]

如前所述,當嘗試基於金鑰的身份驗證時,客戶端檔案或目錄的許可權錯誤是身份驗證失敗的常見原因。然而,並非所有錯誤都明確地說明這一點。以下是一個誤導性錯誤訊息的示例,實際上是由許可權錯誤引起的

$ ssh -i ~/.ssh/key-ed25519 fred@server.example.org
sign_and_send_pubkey: signing failed for ED25519 "/home/fred/.ssh/key-ed25519" from agent: agent refused operation
fred@server.example.org: Permission denied (publickey).

解決此問題的辦法是確保沒有任何其他帳戶能夠讀取或寫入私鑰,並且其他帳戶也無法寫入 .ssh 目錄或其父目錄。

除錯 chroot SFTP 帳戶

[編輯 | 編輯原始碼]

最常見的問題似乎是目錄許可權錯誤。chroot 目錄及其上方的所有目錄都必須由 root 擁有,並且任何其他使用者或組都不可寫入。即使這些目錄的組成員身份不必是 root,如果其中任何一個不是 root,那麼它也不允許組寫入。如果未使用正確的擁有權,將導致無法使用受影響的帳戶登入。從客戶端嘗試登入時,將顯示以下錯誤訊息

$ sftp fred@192.0.2.206
fred@192.02.206's password: 
packet_write_wait: Connection to 192.0.2.206: Broken pipe
Couldn't read packet: Connection reset by peer

伺服器端顯示的錯誤訊息更加清晰

Aug  4 23:52:38 server sshd[7075]: fatal: bad ownership or modes for chroot directory component "/home/fred/"

檢查 chroot 目標和其上方的所有目錄的目錄許可權。如果發現任何一個目錄許可權錯誤,則必須修復該目錄,使其由 root 擁有,並且任何其他使用者都不可寫入。修復方法有很多,這裡提供兩種方法來設定 chroot 許可權。

  • 一種快速修復許可權的方法是將目錄的擁有權和組成員身份都更改為 root。對於 chroot 目標上方的所有目錄,操作相同。
$ ls -lhd /home/ /home/fred/
drwxr-xr-x 3 root  root  4.0K Aug  4 20:47 /home/
drwxr-xr-x 8 root  root  4.0K Aug  4 20:47 /home/fred/

這將與 ChrootDirectory 指令設定為 %h 配合使用,但存在一些缺點,當新增檔案或目錄時會很快變得明顯。

  • 另一種簡單的修復許可權的方法是更改帳戶的主目錄和 ChrootDirectory 指令。將帳戶的主目錄安排在由 root 擁有的唯一目錄下,例如使用使用者名稱本身
$ ls -lhd /home/ /home/fred/ /home/fred/fred/
drwxr-xr-x 3 root  root  4.0K Aug  4 20:47 /home/
drwxr-x--- 3 root  fred  4.0K Aug  4 20:47 /home/fred/
drwxr-x--- 8 fred  fred  4.0K Aug  4 20:47 /home/fred/fred/

然後將帳戶 chroot 到父目錄,並將其與 SFTP 伺服器的 -d 選項結合使用,從使用者名稱令牌開始的備用起始目錄。

ChrootDirectory /home/%u
ForceCommand internal-sftp -d %u

然後,當帳戶連線時,它將只能看到自己的目錄,而看不到系統中的其他部分。

除錯 RC 指令碼干擾 SFTP 會話

[編輯 | 編輯原始碼]

如果在 stdin 上(來自客戶端或伺服器)存在任何多餘資料,則 SFTP 連線將斷開。這方面的一個常見錯誤是如果 /etc/ssh/sshrc~/.ssh/rc 將任何資料傳送到 stdout,而不是保持靜默。在這種情況下,輸出(將是伺服器上的 stdout)將由客戶端在 stdin 上接收,但不匹配任何正確的協議,因此導致客戶端斷開連線。因此,即使在使用 RC 指令碼的情況下,伺服器的響應也必須保持 8 位整潔,否則將發生錯誤。

$ sftp server.example.org
Received message too long 1400204832

該訊息將是主要線索。透過 -v 選項提高 SFTP 客戶端的詳細程度不會提供更多相關資訊。

此外,伺服器上的標準日誌只會顯示客戶端斷開了連線,而不會提供任何斷開連線的原因資訊。在更高級別的日誌記錄中,可能會注意到一些多餘的讀取和相應的丟棄操作,但這僅此而已。以下是 DEBUG3 詳細程度下記錄的日誌示例,顯示了這種情況。

...
debug2: subsystem request for sftp by user fred
debug1: subsystem: exec() /usr/libexec/sftp-server
Starting session: subsystem 'sftp' for fred from 198.51.100.38 port 37446 id 0
...
debug2: channel 0: read 13 from efd 12
debug3: channel 0: discard efd
debug2: channel 0: read 12 from efd 12
debug3: channel 0: discard efd
debug2: channel 0: read 15 from efd 12
debug3: channel 0: discard efd
debug2: channel 0: read 18 from efd 12
debug3: channel 0: discard efd
...

再次強調,在使用 SFTP 時,任何 RC 指令碼都不允許在 stdout 上產生任何輸出,否則會破壞連線。如果 RC 指令碼確實產生了輸出,則必須將其重定向到系統日誌、檔案或傳送到 stderr 而不是 stdout。常規的互動式 SSH 連線不會因使用 stdout 而受到干擾,客戶端只會顯示傳送的內容。有關更多資訊,請參見 sshd(8) 手冊頁中的“SSHRC”部分。

相同的限制適用於透過 stdinstdout 執行的 SSH 服務的任何其他部分,例如 ProxyJump 或某些 ProxyCommand 的用法。因此,另一個潛在干擾的示例是在使用 LocalCommand 與客戶端指定在成功連線到伺服器後在本地機器上執行的命令時。它產生的任何輸出也需要重定向到 stderr。如果 LocalCommand 最終干擾了 ProxyJump,則連線將似乎掛起,停留在 stdout 被使用的那一步。

除錯 SSH 代理擁有正確的私鑰但不使用它時的情況

[編輯 | 編輯原始碼]

在舊版本的 OpenSSH 中,私鑰載入到代理時,公鑰也必須在客戶端可用。如果沒有,代理將無法使用私鑰,除非進行其他安排。一個症狀是,雖然透過執行時引數指定金鑰可以工作,但同一個金鑰無法透過代理工作。

升級到更新的 OpenSSH 版本是更好的選擇。否則,一種解決方法是在客戶端的執行時引數中或在 ssh_config(5) 檔案中指定私鑰。客戶端會找到相應名稱的公鑰檔案。重要的是,客戶端仍然會使用代理中的金鑰,但使用指定的匹配公鑰檔案,因此私鑰檔案不必包含任何內容,甚至可以為空。

$ ssh -i some_key_ed25519 fred@server.example.org

但是,如果不想在檔案系統上訪問私鑰,或者私鑰僅在代理中,而本身無法透過檔案系統訪問,那麼可以直接指定公鑰。

$ ssh -i some_key_ed25519.pub fred@server.example.org

無論哪種方式,另一種方法是使用 **IdentityFile** 配置指令在 ssh_config(5) 中命名金鑰。如果包含公鑰的檔案丟失,可以使用 ssh-keygen(1) 以及 **-y** 選項從私鑰重新生成它。

SSH 客戶端錯誤訊息和常見原因

[編輯 | 編輯原始碼]

作為以上內容的複述,以下是客戶端的一些錯誤訊息,以及這些訊息的常見原因[4]。無論是錯誤列表還是錯誤原因都不是詳盡的。對原因的建議只涉及到一些常見的理由。沒有比檢查實際日誌更好的方法了,尤其是在伺服器上。伺服器日誌檔案通常在大多數系統上是 ** /var/log/auth.log ** 或者類似名稱。有時您會發現資訊在檔案 ** /var/log/secure ** 中。

無關聯地址

$ ssh nonesuch.example.org 
ssh: Could not resolve hostname nonesuch.example.org: no address associated with name

目標主機名在 DNS 中不存在。是否拼寫正確?

操作超時

$ ssh 198.51.100.89 
ssh: connect to host 198.51.100.89 port 22: Operation timed out

沒有與該 IP 地址關聯的系統,或者存在導致故障的包過濾器。

連線超時

$ ssh 198.51.100.89 
ssh: connect to host 198.51.100.89 port 22: Connection timed out

您無法從這裡到達那裡。目標機器可能與網路斷開連線,或者它所在的網路不可訪問。

連線拒絕

$ ssh www.example.org
ssh: connect to host www.example.org port 22: Connection refused

目標系統存在,但嘗試的埠上沒有 SSH 服務可用。目標是否正確?可能是錯誤的系統,SSH 可能根本沒有執行,SSH 可能在其他埠上監聽,或者包過濾器可能阻止連線。

許可權被拒絕

$ ssh www.example.org
fred@www.example.org: Permission denied (publickey,keyboard-interactive).

這通常是使用者名稱錯誤、身份驗證方法錯誤、SSH 金鑰或 SSH 證書錯誤或目標系統上授權金鑰檔案的檔案許可權錯誤導致的問題。如果是基於 SSH 金鑰的身份驗證,請參閱有關 公鑰身份驗證 的章節,以獲取更詳細的介紹。如果它與 SSH 證書相關,請參閱相應的 基於證書的身份驗證 章節。它也可能是目標系統中使用 **AllowGroups**、**DenyGroups** 或類似配置指令的伺服器端設定問題。任何這些可能性只能透過檢查來自 sshd(8) 的日誌輸出來識別和解決。

未找到匹配的主機金鑰型別

$ ssh www.example.org
Unable to negotiate with 198.51.100.89 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

該伺服器上的 SSH 守護程序非常過時。聯絡系統管理員進行升級並讓他們更新。使用客戶端上的 **-v** 選項可以檢視更多詳細資訊。

$ ssh -v fred@example.org
...
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: diffie-hellman-group-exchange-sha256
debug1: kex: host key algorithm: (no match)
Unable to negotiate with 198.51.100.89 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

在上面的 shell 會話中,伺服器非常需要更新,因為它嘗試使用的金鑰交換演算法已過時。再次強調,解決方案是更新過時的軟體。如果絕對必須使用特定版本的舊作業系統一段時間,請考慮獲取 SSH 守護程序的移植版本。許多 GNU/Linux 發行版甚至有專門的移植版本庫。

如果您想檢視客戶端支援哪些金鑰交換演算法,請嘗試使用 **-Q** 選項。

$ ssh -Q kex
diffie-hellman-group1-sha1
diffie-hellman-group14-sha1
diffie-hellman-group14-sha256
diffie-hellman-group16-sha512
diffie-hellman-group18-sha512
diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521
curve25519-sha256
curve25519-sha256@libssh.org
sntrup761x25519-sha512@openssh.com

 

  1. "RFC 4252: The Secure Shell (SSH) Authentication Protocol". IETF. 2006. Retrieved 2021-08-10.
  2. Tucker, Darren (2021-08-10). "Re: ssh authlog: Failed none for invalid user". OpenBSD. https://marc.info/?l=openbsd-misc&m=162858437916966&w=2. Retrieved 2021-08-10. 
  3. Tucker, Darren (2019-04-01). "IdentityFile vs IdentitiesOnly". openssh-unix-dev mailing list. https://lists.mindrot.org/pipermail/openssh-unix-dev/2019-April/037700.html. Retrieved 2019-04-04. 
  4. "SSH Troubleshooting Guide". IT Tavern. 2023-01-17. Retrieved 2023-01-26.
華夏公益教科書