創建私人登入憑證 - 幾種安全的SSH驗證方式

最近不少友人開始使用自己的VPS,也遇上各種各樣的問題。不過拿到伺服器的第一件事,就是要保證自己伺服器的安全性。
端口掃描腳本是一個很厲害的東西,也十分讓人煩惱。初次購買的VPS默認SSH端口為22,如果有看登入記錄會發現一旦IP地址暴露到網絡,每時每刻都有人在嘗試破解密碼。
所以,當拿到VPS之後,務必第一時間進行一些安全防範的操作,update所有軟件包倒是其次了。
本文介紹以下方式

  • 修改端口
  • 公鑰 / 私鑰
  • fail2ban
  • port knocking

1 修改端口

修改ssh配置文件並重啟ssh服務

vi /etc/ssh/sshd_config

找到Port行,去掉頭部的#,修改為自定義端口

# Debian / Ubuntu
service ssh restart
# CentOS / RHEL
service sshd restart

這是最簡單的一種方式,也是效率最高的一種方式。90%以上的通過腳本的暴力破解都盯著22端口去,很少有人願意耗費成本去掃描其他的端口。如果是防範專門盯著你的伺服器去的人,下文將介紹其他方法。

2 使用公鑰/私鑰密鑰對登入

公鑰/私鑰對是很安全的登入方式之一,用戶只需要在伺服器創建公鑰/私鑰對,然後將私鑰用於身份驗證即可。
依賴openssl,一般系統自帶,在生成之前可以upgrade一下。
可以透過

 man ssh-keygen

查看具體操作命令。這裡提供一個配置ECC 521bit登入憑證的配置樣例。

vi /etc/ssh/sshd_config

找到

#AuthorizedKeysFile     .ssh/authorized_keys

將頭部的#去掉,保存退出。
之後進入用戶目錄(可以通過命令cd直接進入),創建一個.ssh目錄(如果不存在)。然後使用命令

ssh-keygen -t ecdsa -b 521

提示保存位置時,直接保存在默認目錄下即可。passphrase也不是必須的,只需要保證自己的私鑰保存在安全的位置。
生成完成之後進入.ssh目錄

cp id_ecdsa.pub authorized_keys

將id_ecdsa保存至本地,推薦刪除位於伺服器的私鑰。最後重啟ssh保存設置,就可以使用私鑰登入了。

3 使用fail2ban防止暴力破解密碼

如果不希望使用密鑰對登入(因為不可能隨身攜帶私鑰),可以透過fail2ban防止暴力破解。fail2ban是一個被廣泛使用的入侵保護開源框架,透過分析日誌文件來對特定入侵來源進行封鎖。期間需要使用iptables。

安裝

一般自帶rpm包,可以透過

# Debian / Ubuntu
apt-get install fail2ban iptables-persistent
# CentOS / RHEL
yum install fail2ban iptables
cd /etc/fail2ban

可以看到,fail2ban配置文件包括了filter,action,jail,config四個部分。filter為監控log文件的部分,透過正則匹配日誌文件找到攻擊源。action為操作部分,進行fail2ban被激活之後的操作。fail2ban.conf無需進行修改。jail.d為監獄的配置文件,默認配置文件為jail.local,下面提供一個防止ssh暴力破解的範例。

配置

iptables

首先配置iptables。fail2ban用的是黑名單的模式,所以如果沒有使用過iptables,只需要

iptables -P INPUT ACCEPT
iptables -F

千萬不能直接全部清除!否則可能導致再也連接不上伺服器。

fail2ban

vi /etc/fail2ban/jail.local


[DEFAULT]
# 以空格分隔的列表,可以是 IP CIDR 前綴或者 rDNS
# 忽略fail2ban防護的ip地址
ignoreip = 127.0.0.1 172.31.0.0/24 10.10.0.0/24 192.168.0.0/24
# 默認禁止時間(second)
bantime = 3600

# 到達多少次後禁用
maxretry = 5

# 檢查多少時間內的日誌(second)
findtime = 600
mta = sendmail

[ssh-iptables]
enabled = true
filter = sshd
action = iptables[name=SSH, port=*SSH端口*, protocol=tcp]
sendmail-whois[name=SSH, dest=admin@example.com, sender=fail2ban@example.com]
# Debian / Ubuntu 
logpath = /var/log/auth.log
# CentOS / RHEL
logpath = /var/log/secure
# 到達多少次後禁用(優先於默認配置)
maxretry = 3

保存退出,重啟fail2ban

service fail2ban restart

檢查服務運行狀態

fail2ban-client ping

本配置文件中,檢測到ssh log中某ip十分鐘內連續登入失敗三次,就會調用iptables,把目標IP ban一個小時。

注: 配置文件中[DEFAULT]為默認配置區塊,優先度低於[ssh-iptables]。bantime,maxretry,findtime等如果衝突,以[ssh-iptables]為準。
之後可以進行隨意的鏈接來測試fail2ban服務。如果多次密碼錯誤,你就會發現無法連上目標伺服器了。

當然fail2ban的用處遠不止這些,具體可以根據filter.d和action.d內文件來編寫。

4 Port Knocking

這是一個創造性的發明,可以稱作是 '為自己開的後門'。如果說fail2ban是黑名單模式的話,port knocking就是白名單模式。服務端的SSH端口封閉,監聽部分特定端口。如果需要連接上伺服器,需要使用tcp udp或者icmp包進行 '敲打'。當符合一定的包特征和順序,服務端自動為當前IP開放指定端口。
有很多相似的程式,在這裡可以找到。這裡提供一個knockd的配置範例。

需要註意的是,這個方法需要一定的iptables知識。

安裝

部分發行版提供rpm。如果沒有(例如這台Debian8),可以到這裡下載對應的包,然後用dpkg -i安裝。也需要iptables的安裝,上文提及過。

配置

下面提供我自己配置的方法

iptables for test

Port Usage Policy
22 SSH Accept
985 for SSH test Drop
233 Listen(knockd) Accept
2333 Listen(knockd) Accept
23333 Listen(knockd) Accept

Knockd配置測試

首先為了防止誤操作導致無法連接,使用HAproxy,將985端口的請求轉發至22端口。
默認的配置文件一般包括了兩個步驟 打開和關閉。這裡稍作修改,讓它可以自動關閉端口。
已經建立的SSH連接不會因為iptables修改為DROP而被中斷。

以下是配置文件,可以根據需求修改網卡(ovz一般是venet0,阿里雲似乎是eth1),敲打端口的順序。國內骨幹網對出國的udp包似乎有特殊的嗜好,所以這裡全部使用tcp包進行認證。

部分OpenVZ主機因為網卡問題,似乎無法正常監聽

[options]
    LogFile      = /var/log/knockd.log
[opencloseSSH]
    Interface    = eth0
    sequence     = 233:tcp,2333:tcp,23333:tcp               seq_timeout = 5
    command      = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 985 -j ACCEPT
    tcpflags     = syn
    cmd_timeout  = 15
    stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 985 -j ACCEPT

配置完成之後,輸入

knockd -v -D

config: new section: 'options'
config: log file: /var/log/knockd.log
config: interface: eth0
config: new section: 'opencloseSSH'
config: opencloseSSH: sequence: 233:tcp,2333:tcp,23333:tcp
config: opencloseSSH: seq_timeout: 5
config: opencloseSSH: start_command: /sbin/iptables -A INPUT -s %IP% -p tcp --dport 985 -j ACCEPTconfig: tcp flag: SYN
config: opencloseSSH: cmd_timeout: 15
config: opencloseSSH: stop_command: /sbin/iptables -D INPUT -s %IP% -p tcp --dport 985 -j ACCEPT
ethernet interface detected
Local IP: xx.xx.xx.xx
listening on eth0...

表示正在監聽。接下來進行敲打測試。

敲打測試

如果是Linux,直接安裝knockd。Windows則下載http://www.zeroflux.org/proj/knock/files/knock-win32.zip,將Releases文件夾下的knock.exe放置在C:\Windows下。然後透過命令

knock -v xx.xx.xx.xx 233:tcp 2333:tcp 23333:tcp

hitting tcp xx.xx.xx.xx:233
hitting tcp xx.xx.xx.xx:2333
hitting tcp xx.xx.xx.xx:23333

如果成功,剛才開啟的-D模式的窗口會打印

opencloseSSH: running command: /sbin/iptables -I INPUT -s xx.xx.xx.xx -p tcp --dport 985 -j ACCEPT

這時迅速連接上SSH即可。

開啟服務

測試成功後,就可以透過

service knockd restart
chkconfig knockd on

開啟服務
之後將knockd打開的端口指向22,設置22端口為DROP。使用時先敲打,後迅速透過xx.xx.xx.xx:22來訪問SSH

iptables(Final)

Port Usage Policy
22 SSH Drop
985 for SSH test Drop
233 Listen(knockd) Accept
2333 Listen(knockd) Accept
23333 Listen(knockd) Accept

敲打之後

Port Usage Policy
22 SSH Accept (temporarily)
985 for SSH test Drop
233 Listen(knockd) Accept
2333 Listen(knockd) Accept
23333 Listen(knockd) Accept

突發情況處理

如果knockd掛了怎麼辦?我們需要防范於未然

可以透過cron定時重啟knockd,或者在SSH端口ACCEPT時iptables-save一下,一旦出錯reboot就好了

參考資料

标签: SSH, security