跳轉到內容

OpenSSH/Cookbook/負載均衡

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

 

MaxStartups

[編輯 | 編輯原始碼]

可以透過指定三個冒號分隔的值 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 中設定的,可以全域性應用於來自該帳戶的所有連線,也可以使用 HostMatch 塊選擇性地應用於特定連線。

確保非活動互動式會話超時

[編輯 | 編輯原始碼]

如果伺服器在達到 ClientAliveInterval 選項配置的超時時間時不再斷開空閒的 SSH 帳戶,則解決方法是將 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 變數。

TCP Wrappers,也稱為 tcpd(8)

[編輯 | 編輯原始碼]

從 6.7 版本開始,OpenSSH 的 sshd(8) 不再支援 TCP Wrappers,也稱為 tcpd(8)。因此,本小節僅適用於 6.6 及更早版本。可以使用 tcpd(8) 的其他選項包括資料包過濾器,如 PF [1]、ipf、NFTables,甚至舊的 IPTables。特別是,OpenSSH 伺服器的 Match 指令支援透過 CIDR 地址進行過濾。使用這些替代方案,並牢記短語“等效的安全控制”,這可以平息由安全審計人員造成的麻煩,這些審計人員可能仍在他們的工作表上保留著一個“tcpwrappers”複選框,這些工作表來自 20 世紀 90 年代。

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 Wrappers,首先搜尋白名單 /etc/hosts.allow,然後搜尋黑名單 /etc/hosts.deny。應用第一個匹配項。如果未找到任何適用的規則,則預設情況下授予訪問許可權。它不應該再被使用,應該使用更好的替代方案。另請參閱 sshd_config(5) 中關於 CIDR 地址的 Match 指令,或者 AllowUsersDenyUsers 指令。

使用 TCP Wrappers 僅允許來自特定子網的連線

[編輯 | 編輯原始碼]

可以使用 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) 進行相應設定,並使用 OpenSSH 伺服器中的 Match 指令或作業系統本身的包過濾器來代替使用 TCP Wrappers,可以更好地實現這種限制。

擴充套件網際網路服務守護程式 (xinetd)

[編輯 | 編輯原始碼]

擴充套件網際網路服務守護程式 xinetd(8) 可以提供多種型別的訪問控制。其中包括但不限於遠端主機的名稱、地址或網路以及時間。它可以限制每個服務的服務數量,並在負載超過一定限制時停止服務。

超級伺服器監聽傳入請求,並根據需要啟動 sshd(8),因此有必要先停止 sshd(8) 作為獨立守護程式執行。這可能意味著修改 System V 初始化指令碼或 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 來重新載入配置。


參考文獻

[編輯 | 編輯原始碼]
  1. Peter N M Hansteen (2011). "使用 PF 防火牆".

 

華夏公益教科書