服务器挂在公网上,说白了就是把家门开着睡觉。你不知道什么时候有人进来,但你可以确定的是——一定有人在试。我见过太多人觉得"我这服务器没啥重要数据,没人盯着我",然后某天发现机器在挖矿,或者带宽被打满了,账单直接炸。
所以这事不是可选项。
SSH 是被攻击最多的入口,没有之一。默认配置放在那里,基本等于在门口贴了张纸写着"欢迎进来"。
先把 root 登录关掉:
# /etc/ssh/sshd_config
PermitRootLogin no
然后是密码登录——这个必须禁掉。密码可以被暴力破解,密钥不行,这是本质区别。不过有个顺序问题,一定要先把密钥配好,再禁密码,别把自己锁外面了,这个坑我见人踩过不止一次。
# 本地生成密钥,ed25519 比老的 rsa 安全
ssh-keygen -t ed25519 -C "your_email@example.com"
# 传公钥上去
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
传完再改配置:
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
端口也改一下,22 这个端口每天被扫的次数,你看了日志真的会头皮发麻。改成非标准端口,能过滤掉绝大多数无脑扫描,不是说改了就绝对安全,但能省很多事。
Port 22222
还有一个容易被忽略的——限制哪些用户能登录:
AllowUsers deploy admin
把这些拼在一起,完整配置大概长这样:
Port 22222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers deploy admin
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
改完别急着重启,先测一下:
sshd -t
systemctl restart sshd
这块的核心逻辑就一句话:不需要的端口,一个都不开。很多人装完系统就直接用,防火墙规则乱七八糟,或者干脆没配。
Ubuntu 用 UFW,简单直接:
apt install ufw
ufw default deny incoming
ufw default allow outgoing
# 注意,先放行 SSH 再启用,顺序别搞反
ufw allow 22222/tcp
ufw allow 80/tcp
ufw allow 443/tcp
# 数据库端口只给特定 IP
ufw allow from 192.168.1.100 to any port 3306
ufw enable
ufw status verbose
CentOS 系用 firewalld:
systemctl start firewalld
systemctl enable firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=22222/tcp
# 精细控制,只允许某个 IP 访问 MySQL
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port port="3306" protocol="tcp" accept'
firewall-cmd --reload
iptables 的话,老系统或者需要精细控制才用,规则写起来麻烦但灵活:
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22222 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables-save > /etc/iptables.rules
echo "iptables-restore < /etc/iptables.rules" >> /etc/rc.local
光有防火墙还不够,Fail2ban 是用来对付那些一直在试密码的人的。原理很简单:盯着日志,某个 IP 短时间失败太多次,直接封。
apt install fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
基本配置,SSH 这块我建议封禁时间设长一点,24 小时不过分:
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
ignoreip = 127.0.0.1/8 192.168.1.0/24
[sshd]
enabled = true
port = 22222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400
跑 Web 服务的话,Nginx 也加上:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
[nginx-botsearch]
enabled = true
filter = nginx-botsearch
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
还可以自定义过滤规则,专门针对那些乱扫 404 的爬虫:
# /etc/fail2ban/filter.d/nginx-cc.conf
[Definition]
failregex = ^<HOST> .* "(GET|POST).* HTTP.*" (404|444|403|400) .*$
ignoreregex =
[nginx-cc]
enabled = true
filter = nginx-cc
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 100
findtime = 60
bantime = 3600
常用的管理命令记几个就行:
fail2ban-client status sshd # 看封了哪些 IP
fail2ban-client set sshd unbanip 1.2.3.4 # 解封,误封了自己用这个
fail2ban-client set sshd banip 1.2.3.4 # 手动封
tail -f /var/log/fail2ban.log
最小权限原则,道理大家都懂,但真正做到的不多。
创建专用部署用户,别什么都用 root 跑:
useradd -m -s /bin/bash deploy
passwd deploy
usermod -aG sudo deploy
sudo 权限这块,我见过很多人直接给 NOPASSWD:ALL,图省事,但这跟直接用 root 没太大区别。稍微细化一下,只给需要的命令:
# /etc/sudoers.d/deploy
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart php8.2-fpm
deploy ALL=(ALL) NOPASSWD: /usr/bin/docker-compose *
文件权限别乱给,敏感文件 600 就够了:
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
chmod 600 /var/www/html/.env
chmod 600 ~/.ssh/authorized_keys
装完系统默认跑着一堆没用的服务,关掉:
systemctl list-units --type=service --state=running # 先看看有什么
systemctl disable cups # 打印服务,服务器用不上
systemctl disable avahi-daemon
systemctl disable bluetooth
内核参数这块,改一下 sysctl.conf,能防一些常见的网络攻击:
# /etc/sysctl.conf
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.tcp_syncookies = 1 # 防 SYN 洪水,这个一定要开
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
sysctl -p
自动安全更新,Ubuntu 上装一下,至少安全补丁能自动打:
apt install unattended-upgrades
dpkg-reconfigure unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Mail "admin@example.com";
MySQL 装完跑一下这个,按提示操作,能解决大部分默认配置的问题:
mysql_secure_installation
业务账号单独建,不要用 root 跑应用,权限给够用的就行:
CREATE USER'app'@'localhost'IDENTIFIEDBY'strong_password';
GRANTSELECT, INSERT, UPDATE, DELETEON myapp.* TO'app'@'localhost';
FLUSHPRIVILEGES;
-- root 禁止远程登录
DELETEFROM mysql.user WHEREUser='root'AND Host NOTIN ('localhost', '127.0.0.1', '::1');
FLUSHPRIVILEGES;
Redis 这个,坦白说很多人装完就忘了,默认没密码还绑在 0.0.0.0,暴露在公网上是真的危险:
# /etc/redis/redis.conf
bind 127.0.0.1
requirepass your_strong_password
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""
Nginx 加几个安全头,顺手的事:
server_tokens off; # 别让人知道你的版本号
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
# .git、.env 这些文件绝对不能暴露
location ~ /\.(git|env|htaccess) {
deny all;
}
location ~ \.(sql|bak|log)$ {
deny all;
}
PHP 这边,禁掉危险函数,关掉错误显示:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
expose_php = Off
upload_max_filesize = 10M
max_file_uploads = 5
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
grep "Failed password" /var/log/auth.log | tail -20
grep "sudo" /var/log/auth.log | tail -20
文件完整性检查,AIDE 装上,定期跑一下,看有没有文件被动过:
apt install aide
aideinit
aide --check
一键安全检查脚本,加到 crontab 里每天跑一次,有问题早发现:
#!/bin/bash
echo"=== 安全检查报告 ==="
echo"1. SSH 配置"
grep -E "^(PermitRootLogin|PasswordAuthentication|Port)" /etc/ssh/sshd_config
echo"2. 开放端口"
ss -tulpn | grep LISTEN
echo"3. 最近登录失败"
grep "Failed password" /var/log/auth.log 2>/dev/null | tail -5
echo"4. 当前登录用户"
who
echo"5. 磁盘使用"
df -h | grep -E "^/dev"
echo"6. 内存使用"
free -h
echo"7. 待更新包"
apt list --upgradable 2>/dev/null | head -10
echo"8. Fail2ban 状态"
fail2ban-client status 2>/dev/null || echo"Fail2ban 未安装"
最后说一句,安全这事不是配完就完了。定期检查,关注漏洞公告,补丁出来及时打。很多安全事故说到底不是技术问题,是懒。
改个 SSH 端口、禁掉密码登录、装个 Fail2ban,这几步做完,能挡掉绝大多数自动化攻击。剩下的,就是保持习惯。
另:点击下方工具可免费使用阿祥自制的ICT随身工具箱↓
常用厂商指令查找、故障码查询、快捷脚本生成,一网打尽。