VPS 上的梯子有时不太稳定,前两天登录上去看的时候偶然发现日志里有一些陌生的 IP 地址通过 SSH 登录失败的记录。出于好奇就仔细看了什么情况,这一吓坏了。

ssh-logLines

感觉不妙,tail -f /var/log/auth.log 直接实时到有不明 IP 一直在尝试不同的用户和密码登录。没错,有人在暴力破解 SSH 用户和密码尝试登录。

ssh-log.png

这个的时候立马去看了另一台 VPS,发现也有类似记录只是少一点,事情并不简单(汗…)。那么接下来改做什么就很简单了:加固 SSH 提升安全性,防止被他人暴力破解登录。

加固 SSH 登录安全性常见的两个方法,一是采用类似于 fail2ban 的工具主动封禁可疑 IP 地址,二是更保险的做法:关闭密码登录并采用密钥登录。

⛔️️安装配置 fail2ban

fail2ban 在 Debian 官方仓库就有,所以直接 apt 就好了。主要看配置。

fail2ban 会读取系统日志,根据设定值封禁一定时间内超过一定尝试次数的远程登录一段时间。上述 一定时间内一定尝试次数一段时间 都是可设置选项。封禁的单位是 jail,比如针对 SSH 设置一个 jail,针对 nginx 设置一个或多个 jail

fail2ban 自带的 jail 配置文件是 /etc/fail2ban/jail.conf,但是为了防止在软件更新时被覆盖,推荐做法是把自己的配置放在/etc/fail2ban/jail.local。 很多地方都推荐 sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local 然后去改,但是我自己试了一下 fail2ban 竟然跑不起来,该文件太长我又懒得一点点看所以还是直接新建了。参照网上资料我写的配置文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[DEFAULT]
# IP 地址白名单,可填 IP 或 CIDR,以空格做分割
ignoreip = 127.0.0.1/8
# 封锁时长
bantime  = 86400
# 默认在 findtime 内达到 maxretry 次尝试登录失败封锁
findtime = 36000
maxretry = 3

[sshd]
enabled = true
# 指定日志文件
logpath  = /var/log/auth.log
filter   = sshd

解读一下:这个配置文件定义了一个 sshdjail,让 fail2ban 读取位于 /var/log/auth.log 日志并过滤到 sshd 条目,当发现某个 IP 地址在 36000s(10h)内有 3 次尝试登录时实施封禁 86400s(1d),同时白名单设为本地主机。

设置完成后就可以启动 fail2ban 了。fail2ban.service 必须以 root 用户启动,所以这时候直接切到 root 用户操作比较方便。root 权限 systemctl start fail2ban.service 就可以了。这时候不出意外的话 systemctl status fail2ban.service 或者 journalctl -u fail2ban.service 都可以看到 fail2ban 成功启动的信息。另外 fail2ban 也提供了检查运行状态的命令 fail2ban-client ping,服务后台正在运行的话会返回 Server replied: pong 的字样。此时 fail2ban-client status 也会看到有一个名为 sshdjail 正在运行。fail2ban-client status sshd 则可以看到这个 jail 详细的数据,包括一共在日志里扫描到多少失败记录、已经封禁多少 IP 以及这些 IP 的列表。/var/log/fail2ban.log 日志里也能看到处理的记录。

fail2ban 发现并封禁一些 IP 后,iptables -L 查看防火墙规则列表也能看到这些 IP 记录被添加到防火墙。最后,如果自己不小心封禁了自己的 IP,可以fail2ban-client set sshd unbanip 111.23.45.678 手动解封。

🔐️ SSH 密钥登录

SSH 设置密钥登录就简单多了(以前一直以为很麻烦就没去了解)。简单来说就是本地生成 SSH 公钥和私钥,然后把公钥放到服务器上去,然后以后就可以让 SSH 直接用这一对密钥进行认证登录了。设置好后可以直接禁用账户密码登录,以后 SSH 远程登录也不再需要输入密码了。理论上来讲,SSH 改端口、禁用密码登录改为密钥登录之后,已经很难被其人破解登录了。

首先是生成密钥对,这个和设置 GitHub 那些网址一样,没有的话 sshkey-gen 直接生成默认密钥就行了。下面一步是把自己的公钥上传到远程服务器上去。最简单直接暴力的方法就是 cat ~/.ssh/id_rsa.pub 然后复制粘贴到远程机器的 ~/.ssh/authorized_keys 里(SSH 登录情况下)。不过,SSH 本身也提供了命令实现,比如下面两个效果是一样的:

1
2
3
ssh-copy-id USER@111.23.45.678 -p PORT -i ~/.ssh/id_rsa.pub
# 或者
cat ~/.ssh/id_rsa.pub |ssh USER@111.23.45.678 -p PORT "cat > ~/.ssh/authorized_keys"`

这时候远程服务器已经有了公钥,接下来需要修改 SSH 配置文件,禁用密码登录并启用密钥登录(注意修改前一定要保留一个 SSH 登录会话,以防修改后文件出错自己无法再登录上)。修改完后可以检查文件所有配置项 grep -v '#' /etc/ssh/sshd_config,比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Port xx
PermitRootLogin no
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys .ssh/authorized_keys2

PasswordAuthentication no
PermitEmptyPasswords no

ChallengeResponseAuthentication no
UsePAM no

确保文件无误后 systemctl restart sshd.service 重启 SSH 服务,这时候本地再

1
ssh USER@111.23.45.678 -p PORT

就发现不输入密码就直接登录上了,再换用 root 登录会直接提示 Permission denied (publickey) 登录失败。

至此,SSH 经历了换用非默认端口、fail2ban 和密钥登录三重安全加固,普通攻击应该都能有效抵挡了,peace✌。