Linux 服务器上线前的 12 项安全加固
一、为什么"能跑就行"不够
一台刚装好的 Linux 服务器,暴露到公网后平均能撑多久?
不用猜。看 /var/log/secure 或 auth.log 就知道——几小时内就会有成千上万次 SSH 爆破尝试,来自全球各地的扫描器。它们不需要针对你,只是在批量找"root + 弱密码"这种软柿子。
所以上线前的加固不是"等出事再说"的事,而是一份必须走完的清单。下面 12 项按优先级排列,前 6 项做完能挡掉绝大多数自动化攻击。
二、第 1 项:先搞清楚开了哪些门
动手改配置之前,先摸清现状:
# 哪些端口在监听(重点看 0.0.0.0 和 :: 的)
ss -lntup
# 哪些服务开机自启
systemctl list-unit-files --type=service --state=enabled
# 最近谁登录过
last -n 20
lastb -n 20 # 失败记录
判断标准很简单:每一条 0.0.0.0:PORT 都要能说出理由。说不出来的,要么关掉,要么改成只监听 127.0.0.1。
# 关掉不需要的服务
systemctl disable --now cups # 打印服务
systemctl disable --now avahi-daemon # 局域网发现
三、第 2 项:SSH 加固(收益最大)
SSH 是攻击面最集中的地方,也是加固收益最高的一处。编辑 /etc/ssh/sshd_config:
# 禁止 root 直接登录
PermitRootLogin no
# 只允许密钥认证,关掉密码登录
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
# 限制可登录用户
AllowUsers deploy ops
# 减少认证尝试次数与时间
MaxAuthTries 3
LoginGraceTime 20
# 空闲超时
ClientAliveInterval 300
ClientAliveCountMax 2
改完先验证再重启,这一步错了会把自己锁在外面:
sshd -t # 语法检查
# 另开一个终端保持连接,再执行:
systemctl reload sshd
# 用新终端测试能登录后,再关掉旧连接
顺序很重要:先配好密钥登录并验证成功,再关 PasswordAuthentication。反过来做,你就只能去控制台救援了。
四、第 3 项:账号最小化
# 找出可登录的账号(shell 不是 nologin/false 的)
awk -F: '($7 !~ /(nologin|false|sync|shutdown|halt)$/) {print $1, $3, $7}' /etc/passwd
# 锁定不需要的账号
usermod -L games
# 检查空密码账号(应该没有任何输出)
awk -F: '($2 == "") {print $1}' /etc/shadow
sudo 权限也要收:
# 只允许特定命令,而不是 ALL
echo "deploy ALL=(root) NOPASSWD: /bin/systemctl restart myapp" > /etc/sudoers.d/deploy
chmod 440 /etc/sudoers.d/deploy
visudo -c # 校验语法
NOPASSWD: ALL 写起来省事,但等于给了第二个 root。能限定到具体命令就别偷懒。
五、第 4 项:防火墙默认拒绝
原则只有一条:默认 DROP,按需放行。
firewalld:
firewall-cmd --permanent --set-default-zone=public
firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
firewall-cmd --permanent --zone=public --add-service=ssh
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload
firewall-cmd --list-all
ufw:
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 443/tcp
ufw enable
ufw status verbose
云服务器别忘了安全组。主机防火墙和安全组是两层,任何一层配错都可能导致"本地通、外网不通",排查时两边都要看。
六、第 5 项:补丁策略
漏洞利用大多数打的是没打补丁的已知漏洞。
# Debian/Ubuntu
apt update && apt list --upgradable
unattended-upgrade --dry-run -d
# RHEL/CentOS
dnf check-update
dnf updateinfo list security
建议开启自动安全更新(只装安全补丁,不升大版本):
# Ubuntu
dpkg-reconfigure --priority=low unattended-upgrades
# RHEL 系
dnf install -y dnf-automatic
sed -i 's/^apply_updates.*/apply_updates = yes/' /etc/dnf/automatic.conf
systemctl enable --now dnf-automatic.timer
内核更新后需要重启才生效,记得安排窗口,别让机器"打了补丁但没生效"跑上半年。
七、第 6 项:时间同步
时间不准会带来一堆诡异问题:TLS 证书校验失败、日志时间线错乱、分布式锁失效、TOTP 验证码永远对不上。
timedatectl # 看当前状态
timedatectl set-timezone Asia/Shanghai
# 启用 chrony
systemctl enable --now chronyd
chronyc sources -v
chronyc tracking
System clock synchronized: yes 才算正常。
八、第 7 项:日志与审计
出事后最怕的是"没有日志"。
# 确认 journald 是持久化存储,而不是只存内存
grep -E "^Storage" /etc/systemd/journald.conf
# 改成 Storage=persistent 后
systemctl restart systemd-journald
# 限制日志占用,防止撑爆磁盘
journalctl --vacuum-size=500M
关键文件单独留档:
# 记录当前所有关键文件的校验和,便于日后比对是否被篡改
rpm -Va > /root/baseline-rpm.txt 2>&1 # RHEL 系
debsums -c > /root/baseline-debsums.txt 2>&1 # Debian 系
需要合规审计的话再上 auditd,监控敏感文件的读写:
auditctl -w /etc/passwd -p wa -k identity
auditctl -w /etc/sudoers -p wa -k privilege
九、第 8 项:文件权限体检
# 全局可写的文件(排除 /tmp /proc /sys)
find / -xdev -type f -perm -0002 \
! -path "/tmp/*" ! -path "/var/tmp/*" ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null
# 无主文件(属主已被删除)
find / -xdev \( -nouser -o -nogroup \) 2>/dev/null | head -20
# 关键文件权限
ls -l /etc/passwd /etc/shadow /etc/sudoers
# 期望:passwd 644,shadow 600 或 640,sudoers 440
.ssh 目录权限错了会导致密钥登录莫名失败:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
十、第 9 项:内核与网络参数
/etc/sysctl.d/99-hardening.conf:
# 禁止 IP 转发(除非这台机器是网关/跑容器)
net.ipv4.ip_forward = 0
# 关闭 ICMP 重定向,防路由劫持
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# 开启 SYN Cookie,缓解 SYN Flood
net.ipv4.tcp_syncookies = 1
# 记录伪造源地址的包
net.ipv4.conf.all.log_martians = 1
# 忽略 ICMP 广播
net.ipv4.icmp_echo_ignore_broadcasts = 1
sysctl --system # 生效并校验
注意:如果这台机器要跑 Docker,
ip_forward = 0会让容器上不了网。跑容器的机器请保留为 1。
十一、第 10 项:爆破防护
即使关了密码登录,日志也会被刷满,不如直接挡掉:
# fail2ban:连续失败 N 次就封 IP
apt install -y fail2ban # 或 dnf install -y fail2ban
cat > /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
EOF
systemctl enable --now fail2ban
fail2ban-client status sshd
bantime = 1h 对持续扫描的 IP 效果有限,可以调成 1d 甚至 1w。
十二、第 11 项:备份要能恢复
没验证过的备份不算备份。
# 备份脚本示例:数据库 + 配置
mysqldump --single-transaction --all-databases | gzip > /backup/db-$(date +%F).sql.gz
tar czf /backup/etc-$(date +%F).tar.gz /etc
# 定期检查备份是否可读
gzip -t /backup/db-*.sql.gz && echo "OK"
三条底线:
- 异地:备份不能和源数据在同一块盘上;
- 保留多份:至少保留 7 天日备 + 4 周周备;
- 定期演练:每季度真的恢复一次,否则你不知道备份是不是坏的。
十三、第 12 项:上线检查清单
把上面的内容固化成一张表,每次上线照着走:
| # | 检查项 | 命令/验证方式 | 通过标准 | ||
|---|---|---|---|---|---|
| 1 | 监听端口 | ss -lntup |
每个端口都有明确用途 | ||
| 2 | SSH | `sshd -T \ | grep -E "permitrootlogin\ | passwordauth"` | 均为 no |
| 3 | 可登录账号 | awk -F: '$7!~/nologin/' /etc/passwd |
只有预期账号 | ||
| 4 | 防火墙 | firewall-cmd --list-all |
默认拒绝,仅放行必要端口 | ||
| 5 | 补丁 | apt list --upgradable |
无安全更新待装 | ||
| 6 | 时间 | timedatectl |
已同步 | ||
| 7 | 日志 | journalctl --disk-usage |
持久化且容量受控 | ||
| 8 | 权限 | ls -l /etc/shadow |
600 或 640 | ||
| 9 | 内核参数 | sysctl net.ipv4.tcp_syncookies |
= 1 | ||
| 10 | 爆破防护 | fail2ban-client status sshd |
运行中 | ||
| 11 | 备份 | ls -lh /backup |
有近期备份且校验通过 | ||
| 12 | 监控 | 探针/告警 | 能收到测试告警 |
十四、小结
这 12 项不是"做完一次就永久有效"的。真实的运维节奏是:
- 上线前:全套走一遍;
- 每周:看补丁、看日志异常、看备份;
- 每季度:复核账号权限、演练恢复;
- 变更后:重新核对端口和防火墙。
加固的本质不是把系统改成"谁都进不来",而是让每一个入口都是你有意留下的。凡是你说不出为什么开着的端口、账号、权限,都该关掉。
下一篇会讲 systemd 怎么把服务托管做对——那是上线之后马上要用到的。
- 点赞
- 收藏
- 关注作者
评论(0)