OpenSSH/食譜/負載均衡
可以透過指定三個冒號分隔的值 start:rate:full 來啟用隨機早期丟棄。當未經身份驗證的連線數達到 start 指定的值後,sshd(8) 將以 rate 指定的百分比拒絕新連線。隨著 full 指定的限制接近,拒絕連線的比例線性增加,直到達到 100%。此時,所有新的連線嘗試都會被拒絕,直到連線積壓減少。
MaxStartups 10:30:100
例如,如果在 sshd_config(5) 中給出 MaxStartups 5:30:90,那麼從 5 個新的連線等待身份驗證開始,伺服器將開始丟棄 30% 的新連線。當連線積壓增加到 90 個待處理的未經身份驗證的連線時,將丟棄 100%。
在預設設定中,full 的值已增加到 100 個待處理的連線,以使其更難屈服於攻擊或負載過重導致的拒絕服務。因此,新的預設值為 10:30:100。
或者,如果傳入連線不是透過資料包過濾器或其他技巧(如迴圈 DNS)在網路級別管理的,則可以在 SSH 伺服器本身限制它。將 MaxStartups 設定為整數會將 SSH 守護程序的最大併發未經身份驗證連線數設定為硬性限制。
MaxStartups 10
其他連線將被丟棄,直到身份驗證成功或 LoginGraceTime 針對另一個連線過期。舊的預設值為 10。
在 SSH 會話期間可以跟蹤兩個連線,即網路的 TCP 連線和在其上執行的加密 SSH 會話。一些隧道和 VPN 可能並不總是處於活動狀態,因此存在會話超時甚至路由器或防火牆上的 TCP 會話超時的風險。網路連線可以使用 TCPKeepAlive 跟蹤,但這不能準確地反映實際 SSH 連線的狀態。但是,它是實際網路狀態的有用指示器。客戶端或伺服器可以透過使用心跳來保持加密連線處於活動狀態來抵消這種情況。
在客戶端,如果全域性客戶端配置尚未設定,則個人可以使用 ServerAliveInterval 選擇伺服器活動心跳的間隔(以秒為單位),並使用 ServerAliveCountMax 設定相應的最大允許錯過客戶端訊息數,在超過該限制之前,加密 SSH 會話將被視為已關閉。
ServerAliveInterval 15
ServerAliveCountMax 4
在伺服器端,ClientAliveInterval 設定客戶端活動心跳之間的間隔(以秒為單位)。ClientAliveCountMax 設定允許錯過的最大客戶端訊息數,在超過該限制之前,加密 SSH 會話將被視為已關閉。如果在此期間沒有傳送或接收其他資料,sshd(8) 將透過加密通道傳送一條訊息以請求來自客戶端的響應。如果 sshd_config(5) 將 ClientAliveInterval 設定為 15,並將 ClientAliveCountMax 設定為 4,則無響應的 SSH 客戶端將在大約 60 (= 15 x 4) 秒後斷開連線。
ClientAliveInterval 15
ClientAliveCountMax 4
如果還使用了基於時間的 RekeyLimit,但時間限制小於 ClientAliveInterval 心跳,那麼較短的重新金鑰限制將用於心跳間隔。
這與伺服器原理基本相同。同樣,這在 ~/.ssh/config 中設定,可以全域性應用於該帳戶的所有連線,也可以使用 Host 或 Match 塊選擇性地應用於特定連線。
如果伺服器不再在空閒 SSH 帳戶達到 ClientAliveInterval 選項配置的超時時斷開其連線,那麼解決方法是將 shell 的 TMOUT 變數設定為所需的超時值。當 TMOUT 設定時,它指定 shell 在關閉 shell 並關閉 SSH 會話之前等待輸入行的秒數。請注意,這意味著也必須按下 Enter 鍵,因為其他輸入不足以防止超時,並且必須實際輸入行才能重置計時器。
在伺服器上,檢查 SSH_CONNECTION 變數是否存在,該變數通常為空,除非當前處於 SSH 會話中,以區分 SSH 會話和本地 shell。如果允許該帳戶更改超時時間,那麼以下內容可以在該帳戶自己的配置檔案中,例如 ~/.profile,
if [ "$SSH_CONNECTION" != "" ]; then
# 10 minutes
TMOUT=600
export TMOUT
fi
如果該帳戶不能更改此設定,那麼它必須在全域性配置檔案中,並且必須設定為只讀,例如在 /etc/profile.d/ 下的某個位置,
if [ "$SSH_CONNECTION" != "" ]; then
# 10 minutes
TMOUT=600
readonly TMOUT
export TMOUT
fi
以上兩個示例都是針對 Bourne shell、其派生版本以及可能的一些其他 shell。一些 shell 可能有其他選項可用,例如在 tcsh(1) 中找到的實際 autologout 變數。
從 6.7 開始,OpenSSH 的 sshd(8) 不再支援 TCP 包裝器,也稱為 tcpd(8)。因此,此小節僅適用於 6.6 及更早版本。可以使用 tcpd(8) 的其他選項包括資料包過濾器,如 PF [1]、ipf、NFTables 甚至舊的 IPTables。特別是,OpenSSH 伺服器的 Match 指令支援按 CIDR 地址進行過濾。使用這些,並記住短語“等效安全控制”,這可以消除安全審計人員可能在其工作表上從 1990 年代遺留的“tcpwrappers”複選框造成的麻煩。
tcpd(8) 程式是用於傳入對網際網路服務的請求的訪問控制實用程式。它用於將一個對一對映到可執行檔案的服務,例如 sshd(8),並且這些服務已編譯為與其互動。它首先檢查白名單(/etc/hosts.allow),然後檢查黑名單(/etc/hosts.deny)以批准或拒絕訪問。與任何給定連線嘗試匹配的第一個模式將被使用。/etc/hosts.deny 中的預設行為是阻止訪問,如果 /etc/hosts.allow 中沒有匹配規則。
sshd: ALL
除了訪問控制之外,還可以將 tcpd(8) 設定為在觸發規則時使用 twist 或 spawn 執行指令碼。spawn 以 tcpd(8) 的子程序身份啟動另一個程式。來自 /etc/hosts.allow
sshd: .example.org : allow
sshd: .example.com : spawn \
/bin/date -u +"%%F %%T UTC from %h" >> /var/log/sshd.log : allow
變數 %h 展開為連線客戶端的主機名或 ip 號碼。hosts_access(5) 的手冊頁包含對可用變數的完整描述。由於示例中的程式 date 使用相同的符號來表示變數,因此必須對跳脫字元 (%) 進行轉義 (%%),這樣它就不會被 tcpd(8) 忽略,並能正確地傳遞給 date。
twist 使用另一個程式替換請求的服務。它有時用於蜜罐,但實際上可以用於任何目的。來自 /etc/hosts.deny
sshd: .example.org : deny
sshd: ALL : twist /bin/echo "Sorry, fresh out." : deny
使用 TCP 包裝器時,會首先搜尋白名單 /etc/hosts.allow,然後搜尋黑名單 /etc/hosts.deny。第一個匹配項將被應用。如果未找到任何適用的規則,則預設情況下授予訪問許可權。不應再使用它,而應使用更好的替代方案。另請參閱 sshd_config(5) 中關於 CIDR 地址的 Match 指令,或者 AllowUsers 和 DenyUsers 指令。
以前可以使用 TCP Wrappers,只需將 sshd(8) 設定為僅監聽本地地址,不接受任何外部連線。這是一種方法。要使用 TCP Wrappers 執行此操作,請在 /etc/hosts.deny 中新增一行以阻止所有內容
sshd: ALL
然後在 /etc/hosts.allow 中新增一個例外,透過使用 CIDR 表示法指定 IP 範圍或使用域名來指定例外
sshd: 192.0.32.0/20
相同的方法可用於將訪問限制為僅 localhost (127.0.0.0/8),方法是將一行新增到 /etc/hosts.allow
sshd: 127.0.0.0/8
同樣,最佳實踐是從任何地方阻止,然後開啟例外。請記住,如果使用域名而不是 IP 範圍,則 DNS 條目必須按順序排列,並且 DNS 本身必須可訪問。但是,上述方法僅具有歷史意義。相同型別的限制最好透過相應地設定 sshd_config(5) 來完成,而不是使用 TCP Wrappers,而是在 OpenSSH 伺服器中使用 Match 指令,或在作業系統本身中使用資料包過濾器。
擴充套件網際網路服務守護程序,xinetd(8),可以提供多種型別的訪問控制。其中包括但不限於遠端主機的名稱、地址或網路,以及一天中的時間。它還可以限制每個服務的服務數量,以及在負載超過一定限制時停止服務。
超級伺服器監聽傳入請求並在需要時啟動 sshd(8),因此有必要首先停止 sshd(8) 作為獨立守護程序執行。這可能意味著修改 System V init 指令碼或 Upstart 配置檔案。然後為 SSH 服務建立一個 xinetd(8) 配置檔案。它可能位於 /etc/xinetd.d/ssh 中。引數 -i 非常重要,因為它告訴 sshd(8) 它正在從 xinetd(8) 執行。
service ssh
{
socket_type = stream
protocol = tcp
wait = no
user = root
server = /usr/sbin/sshd
server_args = -i
per_source = UNLIMITED
log_on_failure = USERID HOST
access_times = 08:00-15:25
banner = /etc/banner.inetd.connection.txt
banner_success = /etc/banner.inetd.welcome.txt
banner_fail = /etc/banner.inetd.takeahike.txt
# log_on_success = PID HOST DURATION TRAFFIC EXIT
# instances = 10
# nice = 10
# bind = 192.168.0.100
# only_from = 192.168.0.0
# no_access = 192.168.54.0
# no_access += 192.168.33.0
}
最後,透過向 xinetd(8) 傳送 SIGHUP 來重新載入配置。
- ↑ Peter N M Hansteen (2011). "使用 PF 進行防火牆".