服务器安全加固清单:账号、端口、补丁、权限与日志审计

安全加固这件事最尴尬的地方在于:它做得好时毫无存在感,做砸一次就可能让前面所有努力归零。很多团队的加固停留在"装了个 fail2ban 就算安全了",但真正出问题时,入口往往是三年前那个没人管的测试账号、某次临时开放的 6379 端口、或者一台从来没打过补丁的边缘机器。本文把服务器加固拆成五个可执行的模块——账号、端口、补丁、权限、日志审计——每个模块都给出具体的检查命令、合格标准和操作步骤,你可以直接拿它当基线检查表,一台一台地过。

一、账号加固:先搞清楚谁有权限进来

账号是权限的入口。加固的目标是三件事:没有多余账号、没有弱口令、没有不该有的高权限。

# 查看所有具备 root 权限(UID 为 0)的账号,正常应只有 root 一个
awk -F: '($3 == 0) {print $1, $3, $7}' /etc/passwd

# 查看空口令账号(有输出即为高危)
awk -F: '($2 == "") {print $1 " 空口令"}' /etc/shadow

# 查看可登录 shell 的账号(/sbin/nologin 与 /bin/false 属正常)
awk -F: '($7 !~ /nologin|false/) {print $1, $3, $7}' /etc/passwd

# 查看所有账号最近登录时间,长期未使用却存在即应清理
lastlog

# 查看近期登录记录
last -n 30 -i
# 锁定不再使用的账号(推荐用 -L 锁定而非直接删除,保留可追溯性)
usermod -L olduser
passwd -l olduser

# 确认需要删除时连同家目录一起清理
userdel -r olduser

# 设置口令有效期(90 天过期,提前 7 天提醒)
chage -M 90 -W 7 opsuser
chage -l opsuser

口令策略建议在 /etc/login.defs 中统一配置,常见的基线值是:PASS_MAX_DAYS 90、PASS_MIN_DAYS 1、PASS_MIN_LEN 12、PASS_WARN_AGE 7、UMASK 027。注意 login.defs 只对新创建或修改口令的账号生效,已有账号需要用 chage 逐个补齐。

登录失败锁定建议用 PAM 模块实现,以 RHEL 系的 pam_faillock 为例:

# /etc/pam.d/system-auth 与 /etc/pam.d/password-auth(Debian 系为 /etc/pam.d/common-auth)
auth required pam_faillock.so preauth silent deny=5 unlock_time=900 fail_interval=900
auth required pam_faillock.so authfail deny=5 unlock_time=900 fail_interval=900
account required pam_faillock.so

# 查看与解除某账号的失败锁定
faillock --user opsuser
faillock --user opsuser --reset

sudo 权限要遵循最小化:给具体命令而不给 ALL。例如只允许某人重启服务,就写成 opsuser ALL=(root) /bin/systemctl restart nginx,而不是 opsuser ALL=(ALL:ALL) ALL。修改 sudoers 务必用 visudo,它会做语法检查,避免写错导致所有 sudo 失效。定期用 sudo -l -U opsuser 复核实际权限。

二、端口加固:把暴露面压到最小

# 列出所有监听端口及进程
ss -lntup

# 只看监听中的 TCP
ss -lntp

# 从外部视角核对(仅对自有资产执行)
nmap -Pn -sT -sV -T4 --top-ports 1000 203.0.113.10

# 查看防火墙规则
iptables -L INPUT -n -v --line-numbers
ufw status numbered
firewall-cmd --list-all
# 建议的默认策略:默认拒绝入站
ufw default deny incoming
ufw default allow outgoing
ufw allow from 办公出口网段 to any port 22 proto tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

# 或用 iptables 的基础四件套
iptables -P INPUT DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 办公出口网段 -j ACCEPT

合格标准很明确:一台公网 Web 服务器对外开放端口应只有 80、443 和限制来源的 22;数据库(3306、5432、27017)、缓存(6379、11211)、容器管理(2375)、etcd(2379)等端口绝不允许出现在公网,只监听内网地址或 127.0.0.1。判断不了某个端口是否必需的,先关掉观察一周。

三、补丁与软件:把已知漏洞补上

绝大多数入侵利用的都是早已公布补丁的漏洞。补丁管理的关键不是"打不打",而是"有没有可持续的机制"。

# Debian / Ubuntu
apt update
apt list --upgradable
apt upgrade -y

# 配置无人值守安全更新
apt install -y unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades
cat /etc/apt/apt.conf.d/20auto-upgrades

# RHEL / CentOS / Rocky / AlmaLinux
dnf check-update
dnf update -y
dnf install -y dnf-automatic
systemctl enable --now dnf-automatic.timer

# 判断更新后是否需要重启(RHEL 系)
needs-restarting -r
# Debian 系可检查是否存在待重启标志
ls /var/run/reboot-required 2>/dev/null && echo '需要重启'
补丁策略适用对象建议频率注意事项
自动安全更新Web 服务器、边缘节点、无状态服务每天自动需配合监控,防止更新引入兼容性问题
窗口内手动更新数据库、核心业务、有状态服务每月一次维护窗口必须先在测试环境验证
紧急补丁高危漏洞(如远程代码执行)评估后 24 至 72 小时内无法立即修复时先做缓解措施(关端口、加 WAF 规则)
内核更新所有主机每季度或有高危公告时需要重启,需与业务方协调窗口

补丁之外的另一半工作是卸载不需要的软件。默认镜像里常带有 Telnet、FTP、rpcbind、avahi 等用不到却自带监听的服务。用 ss -lntup 发现后就地禁用并卸载:systemctl disable --now 服务名,再 apt purge 或 dnf remove。少一个服务就少一个攻击面。

四、权限与文件系统:避免"一处失守、全盘沦陷"

# 关键文件的标准权限
chmod 644 /etc/passwd
chmod 600 /etc/shadow
chmod 600 /etc/gshadow
chmod 644 /etc/group
chmod 600 /etc/ssh/sshd_config
ls -l /etc/passwd /etc/shadow /etc/ssh/sshd_config

# 查找全局可写的文件与目录(正常应极少)
find / -xdev -type f -perm -0002 -print 2>/dev/null | head -20
find / -xdev -type d -perm -0002 -print 2>/dev/null | head -20

# 查找 SUID / SGID 程序(权限提升的常见跳板,逐个确认必要性)
find / -xdev -type f -perm -4000 -print 2>/dev/null
find / -xdev -type f -perm -2000 -print 2>/dev/null

# 对关键文件加不可修改属性(注意:会阻止 useradd 等写操作,需评估)
chattr +i /etc/passwd /etc/shadow
lsattr /etc/passwd

# 检查无属主或无属组的文件
find / -xdev -nouser -o -nogroup 2>/dev/null | head -20

服务运行账号同样要收敛原则:绝不用 root 跑业务服务。Nginx 用 nginx 或 www-data,MySQL 用 mysql,Redis 用 redis,各自独立且不可登录(shell 设为 /sbin/nologin)。这样即使某个服务被攻破,攻击者也只拿到一个低权限账号,横向移动成本大幅上升。

Web 目录还要单独处理:代码目录属主应为部署用户而非 root,上传目录必须禁止执行脚本(Nginx 里对上传路径禁止解析 PHP),并且不要给 777 权限——这在很多"图省事"的部署里非常常见,也是后门文件能落地的直接原因。

五、SSH 与登录安全:加固的重中之重

# /etc/ssh/sshd_config 关键项
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
# AllowUsers opsuser deploy

# 校验与加载
sshd -t
systemctl reload sshd
# fail2ban sshd 监狱
[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log      # RHEL 系为 /var/log/secure
maxretry = 3
findtime = 600
bantime  = 3600
bantime.increment = true
bantime.factor    = 2
bantime.maxtime   = 604800
ignoreip = 127.0.0.1/8 办公出口网段

顺序提醒:先验证密钥能登录、保留一个活动会话,再关闭 PasswordAuthentication;先把办公出口 IP 加进 ignoreip,再启用 fail2ban。这两步做反了,最常见的后果就是把自己锁在门外。

六、日志与审计:让一切有据可查

日志是事后追溯的唯一依据,也是唯一能在"还没出事"时就发现异常的模块。加固目标是:日志要留得住、改不了、看得到。

# 开启 journald 持久化(默认可能只存在内存中,重启即丢)
mkdir -p /var/log/journal
sed -i 's/#\?Storage=.*/Storage=persistent/' /etc/systemd/journald.conf
systemctl restart systemd-journald
journalctl --disk-usage

# 常用查询
journalctl -u sshd --since '24 hours ago'
journalctl -u nginx --since '1 hour ago' -n 100
journalctl -p err -b
# /etc/audit/rules.d/hardening.rules 基础审计规则
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k priv_change
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /etc/crontab -p wa -k cron_change
-w /root/.ssh/authorized_keys -p wa -k sshkey_change
-a always,exit -F arch=b64 -S chmod -S chown -S fchmod -S fchown -F auid>=1000 -F auid!=-1 -k perm_mod
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=-1 -k delete

# 加载并验证
systemctl restart auditd
auditctl -l

# 查询审计记录
ausearch -k identity -i | tail -20
ausearch -k sshkey_change -i | tail -20
aureport --summary

日志还要做两件容易被忽略的事:集中化和防篡改。集中化可以简单地在 /etc/rsyslog.d/ 里加一行 *.* @@日志服务器IP:514,把日志实时发到独立的日志服务器——这样即使本机被攻破,攻击者也无法抹掉远程留存的那份。防篡改则依赖 auditd 对 /var/log/ 的监控,以及给日志文件设置合适的权限。

七、加固实施清单

  1. 资产盘点:列出所有服务器、用途、负责人、对外开放端口,形成清单。没在清单上的机器往往是风险最高的那台。
  2. 账号清理:删除或锁定无用账号,检查 UID 0 账号与空口令账号,配置口令有效期与失败锁定策略。
  3. SSH 加固:密钥认证、禁 root 直登、MaxAuthTries 3、fail2ban、限制来源 IP。
  4. 端口收敛:ss -lntup 盘点,服务改监听内网地址,防火墙默认拒绝,安全组同步收敛。
  5. 补丁更新:配置自动安全更新,安排维护窗口处理需要重启的内核更新,卸载无用服务。
  6. 权限收窄:修正关键文件权限,清理全局可写文件,核查 SUID/SGID,服务用独立非 root 账号运行。
  7. 日志审计:开启 journald 持久化,配置 auditd 规则,日志集中化,设置日志保留期与轮转。
  8. 建立周期巡检:把上述检查做成每月一次的例行任务,新机器上线时用同一份清单验收。
  9. 固化为镜像或配置管理:用 Ansible、cloud-init 或自定义镜像把加固项固化,避免每台机器手工操作产生偏差。

八、加固项速查表

模块检查命令合格标准
账号awk -F: '($3==0){print}' /etc/passwdUID 0 账号只有 root;无空口令账号
账号lastlog、last -n 30长期未使用账号已锁定;无异常来源登录
端口ss -lntup公网仅 80、443、22(限源);无数据库/缓存端口暴露
端口ufw status numbered默认拒绝入站,放行规则均可解释用途
补丁apt list --upgradable / dnf check-update无长期未修复的高危更新;已启用自动安全更新
权限find / -xdev -perm -4000 -type fSUID 程序逐个有明确用途,无多余项
权限ls -l /etc/shadow权限 600,属主 root
SSHsshd -T | grep -E 'permitrootlogin|passwordauth'PermitRootLogin no;PasswordAuthentication no
日志journalctl --disk-usage持久化已开启,容量与保留期符合预期
审计auditctl -l关键文件与权限变更规则已加载且持久化

小结

服务器加固不是一次性项目,而是一套需要固化进流程的基线。五个模块各有明确抓手:账号看"有没有多余的、有没有弱口令、有没有过高权限";端口看"公网只剩必需的几个";补丁看"有没有可持续的自动更新机制";权限看"服务是否用非 root 跑、关键文件权限是否正确";日志审计看"留得住、改不了、看得到"。把这五个模块写成清单,上线前验收一台、每月巡检一遍,并用 Ansible 或镜像固化,安全水位就会长期稳定在及格线以上。

避坑建议

  • 不要在远程 SSH 会话里直接启用防火墙:务必先放行 22 再加默认拒绝策略,否则会当场断连。
  • 不要给 /etc/passwd、/etc/shadow 盲目加 chattr +i:这会导致 useradd、passwd 等命令失败,加之前先确认后续是否还要改账号。
  • 不要把 sudoers 改成 ALL 了事:权限应当精确到具体命令,否则等同于给了 root。
  • 不要只加固系统不加固应用:Web 中间件、CMS、插件、后台管理页面同样是关键攻击面,弱口令后台和未修复的 CMS 漏洞非常常见。
  • 不要开了审计就不管日志容量:auditd 规则过宽会迅速写满磁盘,规则要聚焦关键文件,并配置日志轮转与磁盘告警。
  • 不要依赖一次性加固:新机器上线、新服务部署、人员变动都会让基线漂移,巡检机制比单次加固更重要。
  • 不要把备份和日志放在同一台机器上:本机被攻破时它们会一起失守,集中化和异地留存是基本要求。