logo NodeSeekbeta

我没有特别的 SSH 安全配置技巧

我没有特别的 SSH 安全配置技巧

1. 前情提要

今天又在盛传SSH被暴力破解了,其实大部分都是脚本小子24小时不停扫描公网暴露的SSH端口,只要你开着常见的SSH端口就会被扫描

我很早之前摸索的一套方法,应该算是对这种情况有所缓解,主要是高位端口+仅密钥登陆+22端口ssh蜜罐+fail2ban监听蜜罐和sshd全局封禁,可以预防绝大部分自动扫描了,以下是实践步骤

2. 实践步骤

2.1 编译更新 SSH 新版本

部分系统的默认 SSH 版本过低,存在安全漏洞,如果小鸡性能不足,建议安装 Alpine 3.22 版本,自带的 openssh 已经更新到了 10以上

如果是 Debian13 这种新系统,可以不需要更新版本

一键更新命令(修改自科技Lion大佬的脚本,感谢)

wget -O upgrade_openssh.sh https://gist.github.com/Seameee/2061e673132b05e5ed8dd6eb125f1fd1/raw/upgrade_openssh.sh && sudo chmod +x ./upgrade_openssh.sh && sudo ./upgrade_openssh.sh

2.2 设置 SSH 高位端口

[!Tip]
感谢 LuckyZ 佬的提醒
由于 Ubuntu24.04 版本以后默认使用 ssh.socket 管理,你应该直接修改 /etc/ssh/sshd_config 文件中的端口字段来修改,后续步骤中需要编辑ssh配置的也都需要手动修改这个文件中的内容,当然也可以禁用ssh.socket还原默认的ssh.service具体请参考下文
https://dev.to/saishanmukkha/understanding-ssh-socket-based-activation-in-ubuntu-2404-28m

⚠️警告⚠️:此时不要关闭当前终端窗口
在目录 /etc/ssh/sshd_config.d/下,新建任意名称配置文件,文件名后缀为.conf,写入如下内容即可,端口号建议填写 10000 - 65535 以内没有被占用的端口

Port 33445 

检查端口是否被占用:

lsof -i:33445

一键命令:

echo -e "Port 33445" | sudo tee /etc/ssh/sshd_config.d/00-custom_port.conf

设置完配置文件后,使用如下命令重启 SSH 服务

sudo systemctl restart ssh.service # Debian 等使用 systemd 的使用这个命令
sudo rc-service sshd restart       # Alpine 等无法使用 systemd 的系统可以使用 openrc 管理 

⚠️警告⚠️:此时不要关闭当前终端窗口

如果有防火墙,请放行新的端口,并禁止旧的SSH端口访问

sudo ufw allow 33445 # 放行新的SSH端口
sudo ufw deny 22     # 禁用原有SSH端口

修改完 ufw 规则后,使用命令启用防火墙

sudo ufw enable 

打开一个新的终端窗口,使用旧的端口和新的端口测试是否修改成功,再关闭当前的终端窗口,否则一旦你修改出错就只能去VNC里重新开启了

2.3 设置 SSH 仅密钥登陆

一键命令:

echo -e "PasswordAuthentication no\nPubkeyAuthentication yes" | sudo tee /etc/ssh/sshd_config.d/01-custom_auth.conf

与上面的重启SSH和检查端口方式相同,我就不再赘述

2.4 配置 Fail2ban 将 SSH 访问失败的 IP 封禁

安装 fail2ban 和 ufw 防火墙

sudo apt update && sudo apt upgrade && sudo apt install fail2ban ufw -y

其他系统安装方式可以参考 How to install fail2ban packages · fail2ban/fail2ban Wiki · GitHub

配置 fail2ban 的 jail.local

nano /etc/fail2ban/jail.local

写入以下配置,注意修改里面的 port为你的 SSH 端口

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
bantime = 86400
findtime = 1800
action = %(action_)s
banaction = ufw
[sshd]
enabled = true
port = 33445
filter = sshd
action = ufw
logpath = /var/log/auth.log
maxretry = 3
findtime = 604800s
bantime = 604800s
usedns   = no

保存退出后,使用以下命令重启 fail2ban 服务,以应用配置

sudo systemctl restart fail2ban.service # Debian & Ubuntu
sudo rc-service fail2ban restart        # Alpine

ufw 防火墙注意放行你使用的端口,比如上面修改的 SSH端口、Nginx使用的80和443端口等,相关参数见

Usage: ufw COMMAND
Commands:
 enable                          enables the firewall
 disable                         disables the firewall
 default ARG                     set default policy
 logging LEVEL                   set logging to LEVEL
 allow ARGS                      add allow rule
 deny ARGS                       add deny rule
 reject ARGS                     add reject rule
 limit ARGS                      add limit rule
 delete RULE|NUM                 delete RULE
 insert NUM RULE                 insert RULE at NUM
 prepend RULE                    prepend RULE
 route RULE                      add route RULE
 route delete RULE|NUM           delete route RULE
 route insert NUM RULE           insert route RULE at NUM
 reload                          reload firewall
 reset                           reset firewall
 status                          show firewall status
 status numbered                 show firewall status as numbered list of RULES
 status verbose                  show verbose firewall status
 show ARG                        show firewall report
 version                         display version information
Application profile commands:
 app list                        list application profiles
 app info PROFILE                show information on PROFILE
 app update PROFILE              update PROFILE
 app default ARG                 set default application policy

修改完 ufw 规则后,使用命令启用防火墙

sudu ufw enable

查看 fail2ban 实时封禁日志(刚安装可能不会立刻有内容)

tail -f -n 50 /var/log/fail2ban.log

2.5 配置 SSH 蜜罐和 fail2ban 监听蜜罐实现全局封禁

⚠️警告⚠️

高级操作,请衡量你的Linux能力再研究,不确保适合每个系统

长期监听可能会影响系统性能,建议使用性能不太差的服务器

2.5.1 安装相关依赖
sudo apt update && sudo apt upgrade && sudo apt install ipset iptables -y 
2.5.2 安装简单 SSH 蜜罐fakessh

以下附上 docker-compose.yml

name: fakessh
services:
    fakessh:
        restart: always
        ports:
            - 22:22
        container_name: fakessh
        image: fffaraz/fakessh
        logging:
            driver: "json-file"
            options:
                max-size: "10m"
                max-file: "3"

使用命令 docker compose up -d运行容器

然后运行以下命令查看 docker 容器直接保存的日志路径(之前尝试将容器日志使用外挂 volume 的方式导出失败了,有知道的大佬可以楼下补充)

docker inspect fakessh | grep LogPath

需要保存的日志路径形如:/var/lib/docker/containers/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b-json.log

2.5.3 配置 fail2ban

新建/etc/fail2ban/filter.d/fakessh.conf文件,并写入以下内容

[Definition]
failregex = ^{"log":".* .* <HOST>:\d+\\n","stream":"stderr","time":".*"}$
ignoreregex =
datepattern = {^LN-BEG} ExYear (?P<_sep>[/]) Month (?P=_sep) Day 24hour:Minute:Second (?:[.,] Microseconds)?

/etc/fail2ban/jail.local 底部添加 fakessh 规则如下,注意替换 logpath为你自己的容器日志路径

[fakessh]
enabled  = true
filter   = fakessh
action   = iptables-ipset-proto6-allports[name=fakessh, bantime=1209600, chain=INPUT]
logpath  = /var/lib/docker/containers/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b-json.log
maxretry = 1
bantime  = 1209600
findtime = 604800
usedns   = no
backend  = polling
ignoreip = 127.0.0.1/8 ::1

在保证 fakessh 已经被写入外部扫描IP日志的情况下,使用下面命令测试规则是否生效

fail2ban-regex /var/lib/docker/containers/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b-json.log /etc/fail2ban/filter.d/fakessh.conf

结果只要 Lines 里 matched 里有数量说明正常,因为只匹配 TCP 传入流量

# root @ LeasewebSG in ~ [12:18:19] C:130
$ fail2ban-regex /var/lib/docker/containers/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b-json.log /etc/fail2ban/filter.d/fakessh.conf
Running tests
=============
Use   failregex filter file : fakessh, basedir: /etc/fail2ban
Use      datepattern : {^LN-BEG} ExYear (?P<_sep>[/]) Month (?P=_sep) Day 24hour:Minute:Second (?:[.,] Microseconds)? : {^LN-BEG} ExYear (?P<_sep>[/]) Month (?P=_sep) Day 24hour:Minute:Second (?:[.,] Microseconds)?
Use         log file : /var/lib/docker/containers/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b/1586b2735886350e0e6cd285c76bf1737ea597a5c7c425550e086a453c73ae1b-json.log
Use         encoding : UTF-8
Results
=======
Failregex: 36987 total
|-  #) [# of hits] regular expression
|   1) [36987] ^{"log":".* .* <HOST>:\d+\\n","stream":"stderr","time":".*"}$
`-
Ignoreregex: 0 total
Date template hits:
Lines: 73028 lines, 0 ignored, 36987 matched, 36041 missed
[processed in 1.78 sec]
Missed line(s): too many to print.  Use --print-all-missed to print all 36041 lines

重启 fail2ban 即可

如果你还需要让 docker 容器暴露的端口也服从上面的封禁规则,包括 fakessh 本体,可以运行添加下面的 iptables 规则

iptables -I DOCKER-USER 1 -m set --match-set f2b-fakessh src -j REJECT --reject-with icmp-port-unreachable
ip6tables -I DOCKER-USER 1 -m set --match-set f2b-fakessh src -j REJECT --reject-with icmp-port-unreachable

3. 效果展示

image

image

image

12345
  • @seamee #23 直接把reject改成drop就行了,fail2ban严厉的规则,用nftables,几千个ip性能都不影响。

  • 仅密钥登陆就够了

  • 22蜜罐意义不大,直接ssh 22端口+密钥+fail2ban+drop action即可

  • # cat /etc/ssh/sshd_config
    Port 22
    UsePAM yes
    GatewayPorts no
    PermitRootLogin no
    PubkeyAuthentication yes
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    
    AcceptEnv LANG LC_*
    AddressFamily any
    TCPKeepAlive yes
    X11Forwarding no
    AllowTcpForwarding yes
    ClientAliveInterval 60
    Subsystem sftp /usr/lib/openssh/sftp-server
    LogLevel INFO
    
    PrintMotd no
    Banner /etc/ssh/banner
    

    私钥带口令保护。

  • 欢迎大佬们在下面交流病情经验

  • 关闭密码登录。只允许密钥登录就行了。。

    假的22蜜罐。fail2ban。开了也是浪费资源。。

  • 我到手先dd,dd时候顺便设置一下公钥。然后别的就不管了...

    然后开启ufw,只开放ssh,https,http端口

  • 直接用科技烂的一键脚本

  • @新来的 #2 其实我实测,也没那么特别浪费资源,占用还是挺低的

  • 可以了,这样下来固若金汤

  • @最大-abc #3 我也不是所有服务器都这么设置,太麻烦了,只有主服务器搞了

  • 那假如使用24位以上的密码跟密钥登陆安全性上有什么区别么,感觉两者都无法爆破啊

12345

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有60098位seeker

🎉欢迎新用户🎉