Linux ssh 登录安全

#前言

朋友借我一台独服,是他们实验室跑机器学习的机器,配置高,还有双路独显。这么好的机器自然要认真保护,趁此机会学习一下 Linux 安全。

#查看登录记录

玩 Linux,有事没事看看日志,了解系统的运行状态。Linux 有 3 个文件记录登录相关的信息,分别是

/var/log/wtmp #  登录成功的日志,倒序
/var/log/btmp #  登录失败的日志,倒序
/var/run/utmp #  当前登录的用户

注意他们三个所在的文件夹不同,当前登录的用户记录在 /var/run/ 下。使用last 命令查看这三个文件,last命令默认查看成功登录的日志,如果想查看其他两个记录,使用 -f 参数指定,例如查看当前登录的用户:

last -f /var/run/utmp 

可以加上参数查看指定数量的登录记录,指定用户的登录记录,例如下面这条命令查看最近 3 条 acytoo 的登录记录。

last -i -n 3 acytoo

查看失败的登录记录,除了上指定读取/var/log/btmp文件,还有一个直接的命令:lastb 默认查看登录失败的日志。有公网 ip 的服务器总有很多登录失败的记录,都是脚本小子爆破服务器密码时留下的足迹,例如查看最近 100 条登录失败的日志:

服务器被脚本小子扫描爆破

脚本小子会扫描 vps 服务商的 ip 段,甚至是扫全网。发现设备就用字典爆破,我曾经有一台弱密码的 vps 就被爆破过。

last的其他参数见附录。

#登录基本防护
#修改 ssh 端口

修改ssh端口可以挡住大部分碰运气的人,他们扫描很多机器,遇到非默认端口的机器,大概率会跳过,去下一台机器碰运气。

sudo nano /etc/ssh/sshd_config

ssh默认端口是 22,删除Port 22前面的注释,在下面添加一条新记录,别急着删除默认的端口号。试试能不能通过新端口连接,能正常连接,再删除默认端口号。

Port 22
Port 23456 # 设置一个端口号

编辑 ssh 配置后要重启 sshd 进程,应用修改:

sudo systemctl restart sshd

修改 ssh 端口可以过滤掉很大一部分试运气的脚本小子(瞎猫),如果你被人针对,nmap 扫到了 ssh 端口,还是会被人不停的尝试。

#修改默认用户名

一些系统可能会提供默认用户名,比如甲骨文的云服务, Ubuntu 系统,密钥登录,但是默认的用户名是 ubuntu。如果有人设置了简单密码,又没仅密钥登录,就很容易被爆破。强烈建议修改默认的用户名,教程在这里

#仅允许密钥登录

有密码就有被爆破的风险,目前普遍的做法是仅允许密钥登录。首先把自己的密钥添加到用户根目录的.ssh/authorized_keys中,如果没有这个文件夹与文件,要手动建文件夹,添加文件。

mkdir ~/.ssh 
cd ~/.ssh
nano authorized_keys

把公钥粘贴进去,保存。然后修改authorized_keys文件权限为 600,保护起来。

chmod 600 authorized_keys

这是已经可以通过密钥登录了,尝试一下,不需要密码就可以登录。 接下来修改 sshd 配置,禁止密码登录

sudo nano /etc/ssh/sshd_config

找到PasswordAuthentication 这一行,删除注释,把值改为 no,重启sshd服务。注意PasswordAuthentication 默认为yes,只有显性修改为no才有效,然后一定记得重启sshd服务,应用修改。很多人修改了配置却不应用……

如果修改为仅允许密钥登录,那么密钥一定要保护好,同时要备份,如果本地的密钥没了(比如电脑被抢),又没有备份,那可能会永久丢失数据。可以把密钥内容抄到纸上,放进保险箱。或者替换几个字母,混淆加密,存到网盘/GitHub等,都是能接受的做法。

#自动 ban 掉乱试的 ip

密钥登录也有限制,就是只能在存放密钥的电脑上登录,当然,你可以多台电脑共用密钥,或者设置允许多个密钥登录,但是都需要增加额外的步骤。有时候我们不能限制密码登录,比如需要在不同的机器上登录服务器,甚至在服务器登录服务器。一个简单的情境:临时需要在同学的电脑上紧急修复一个 bug。那么,增加密码登录的安全就很重要了。

最基础的操作:不适用默认用户名,禁止 root 登录,不使用弱口令,不同机器使用不同密码。除此之外,还可以使用一些工具 ban 掉疯狂尝试登录的坏 ip。其中一个是fail2ban。它可以设置在密码输错几次后,禁止某一 ip 一定的时间,增加爆破需要的时间,提高安全等级。

即使设置了仅密钥登录,也建议安装这个工具:有人想撬开你家大门,即使他撬的大门是假的,永远打不开,你也想赶走他。

sudo apt install fail2ban

fail2ban每次更新时,可能覆盖默认配置,因此先生成一个本地配置,然后再修改

sudo cp /etc/fail2ban/jail.{conf,local}
sudo nano /etc/fail2ban/jail.local

需要关系的几个配置是:

[DEFAULT]
bantime = 1d
maxretry = 3
findtime = 5m

用普通话讲一下,就是,在{findtime}内,某个ip出错{maxretry}次,就禁止他登录{bantime},上面的例子翻译出来就是,在5分钟内,如果一个 ip 出错 3 次,就禁止他登录 1 天。

fail2ban 不仅支持 ssh,还可以应用到其他服务,因此要设置 sshd 的相关设置。 在上述配置文件中找到[sshd]这一系列,加入enabled = true,开启针对 ssh 的监狱(jail)

[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

然后重启服务。

sudo systemctl restart fail2ban

然后可以通过 sudo fail2ban-client banned查看状态

被 ban 掉的 ip

看起来成功了,但是我 ban 了自己,断开全部连接,仍旧可以在 ban 时间段内连接。查看 iptables, 发现确实加入了一条 drop 规则……不知道为什么不好用。可能是有地方设置的不对,或者与ufw冲突了。

这个 fail2ban 对cpu/ram的消耗好像有点高,看前几年的 GitHub Issue,有很多关于性能消耗的。如果通过 iptables 来一个个 drop ,那么 ban 很多 ip 的话。的确会损失一些性能,而且因为 ban 时间区间,后台的服务可能要一直判断是不是到时间了,要把 ip 放出来,所以对计算资源的消耗是有的。独服还好,小一点的 vps 还是人工频繁看日志吧。

#附录
#last --help
Usage:
 last [options] [<username>...] [<tty>...]

Show a listing of last logged in users.

Options:
 -<number>            how many lines to show
 -a, --hostlast       display hostnames in the last column
 -d, --dns            translate the IP number back into a hostname
 -f, --file <file>    use a specific file instead of /var/log/wtmp
 -F, --fulltimes      print full login and logout times and dates
 -i, --ip             display IP numbers in numbers-and-dots notation
 -n, --limit <number> how many lines to show
 -R, --nohostname     don't display the hostname field
 -s, --since <time>   display the lines since the specified time
 -t, --until <time>   display the lines until the specified time
 -p, --present <time> display who were present at the specified time
 -w, --fullnames      display full user and domain names
 -x, --system         display system shutdown entries and run level changes
     --time-format <format>  show timestamps in the specified <format>:
                               notime|short|full|iso

 -h, --help           display this help
 -V, --version        display version