跳轉到內容

OpenSSH/日誌和故障排除

100% developed
來自 Wikibooks,開放世界中的開放書籍
(從 OpenSSH/Logging 重定向)

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) 建立的自定義條目來授予這些許可權。請注意,在這些情況下,只應允許特定服務和程式,而不應允許 blanket 訪問,這是一種在 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 檔案傳輸

[編輯 | 編輯原始碼]

SFTP 檔案傳輸可以透過設定 LogLevel 為 INFO 或 VERBOSE 來記錄。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

[編輯 | 編輯原始碼]

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

以下是一個使用 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 是一個獨立的子系統,與檔案建立模式一樣,日誌級別和日誌設施是獨立於 SSH 伺服器在 sshd_config(5) 中設定的。

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

ClientAliveIntervalClientAliveCountMax 指令通常適用於連線到伺服器的所有客戶端。但是,它們可以在 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 開始,當嘗試使用有效的使用者名稱時,日誌中會顯示“authenticating user”。當嘗試使用無效的使用者名稱時,也會記錄下來。

...
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 攻擊,請聯絡攻擊者的網路塊所有者。如果攻擊給出了確切的時間和地址,那麼帶有日誌中複製貼上內容的格式化信件就足夠了。或者,網路或系統管理員團隊可以協同工作,收集資料以識別和列入黑名單參與攻擊的被入侵主機。

對無效使用者的“Failed None”

[編輯 | 編輯原始碼]

SSH 協議指定了許多可能的身份驗證方法[1]passwordkeyboard-interactivepublickey 方法比較常見。一種不太為人知的身份驗證方法是 none,它只有在伺服器不需要進一步身份驗證的情況下才能成功,例如,如果設定了 PermitEmptyPassword,並且帳戶實際上沒有密碼[2]。一些 SSH 客戶端,包括 OpenSSH 的客戶端,首先會請求 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 或其他 localhost 地址的連線

[編輯 | 編輯原始碼]

當透過反向隧道訪問 SSH 伺服器時,傳入的連線將顯示為來自 localhost 地址,通常是 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 或其他類似入侵檢測系統之類的常規對策無法使用,因為localhost地址被隧道用於所有登入嘗試,無論其真實來源。

部分解決方案是將傳入連線繫結到不同的 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執行時選項,如果沒有它則不起作用。

或者,除了使用-y選項之外,使用-E選項將日誌輸出傳送到指定的日誌檔案,而不是stderr。在執行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)。請注意,下面的機器配置將更詳細的 DEBUG 訊息(用於 AUTH 裝置)傳送到與常規 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) 的指令碼、配置或金鑰

[edit | edit source]

通常,只有在編寫和測試指令碼、新配置、一些新金鑰或同時進行所有這三項操作時才需要更改日誌級別。在使用 **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/

相同的方法可用於除錯新的伺服器配置或金鑰登入。一旦將設定調整為按需執行,就可以將日誌級別設定降低迴 **INFO** 用於 sshd(8),並降低迴 **ERROR** 用於 **internal-sftp**。此外,一旦指令碼被設定為在完全自動模式下執行,客戶端日誌資訊可以透過在啟動時設定 **-y** 選項,使用 syslog(3) 系統模組代替 **stderr**。

除錯伺服器配置

[編輯 | 編輯原始碼]

在除錯模式下執行伺服器會提供大量有關連線的資訊,以及少量有關伺服器配置的資訊。伺服器的除錯級別 (**-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) 在評估 **Host** 和 **Match** 塊之後列印其配置,然後退出。這允許檢視客戶端將對特定連線實際使用的確切配置選項。

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

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

無效或過時的密碼或 MAC

[編輯 | 編輯原始碼]

合適的客戶端會顯示故障的詳細資訊。對於錯誤的訊息認證碼 (MAC),合適的客戶端可能會在嘗試將錯誤的 MAC(如 hmac-md5-96)強加到伺服器上時顯示以下內容。

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** 檔案,或者私鑰本身。

截至撰寫本文時,看起來郵件列表和論壇上描述的幾乎所有基於金鑰的身份驗證失敗都是透過解決這兩種情況中的任何一種或兩種來解決的。因此,在遇到錯誤訊息“許可權被拒絕 (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

除了 authorized keys 檔案中篡改的公鑰和許可權不正確之外,非常罕見的情況是,如果公鑰和私鑰檔案不匹配,並且不是來自同一金鑰對。如 公鑰身份驗證 部分所述,公鑰和私鑰需要匹配,並且是同一金鑰對的一部分。這是因為即使在 SSH 客戶端在加密上使用私鑰之前,它也會檢視提議的私鑰的檔名,然後傳送與該相同檔名匹配的公鑰(如果存在)。如果客戶端上的公鑰與伺服器上 **authorized_keys** 中的公鑰不匹配,則連線將被拒絕,並顯示錯誤“許可權被拒絕 (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]

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

解決此錯誤的一種方法是使用 **-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”部分。

同樣的限制適用於透過 **stdin** 和 **stdout** 執行的 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) 中命名金鑰。如果包含公鑰的檔案丟失,可以使用-y選項使用 ssh-keygen(1) 從私鑰重新生成。

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

[edit | edit source]

作為以上內容的重述,下面是一些客戶端錯誤訊息,以及 [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 證書的問題,請參閱相應的 基於證書的身份驗證 章節。它也可能是目標系統上的AllowGroupsDenyGroups或類似配置指令的伺服器端設定問題。所有這些可能性只有透過檢查 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.
華夏公益教科書