云服务器如何进行安全基线检查?账号、端口、补丁与权限核查

买完云服务器、部署完业务,很多人的运维就止步于"能跑就行"。可服务器的安全状态不是一次配好就永远有效的:装了某个服务顺带开了一个端口、给某个账号加了 sudo 却忘了回收、系统内核停留在几年前的版本、某个关键文件权限被改成了 777……这些"基线偏移"日积月累,就是风险慢慢累积的过程。所谓安全基线检查,就是定期对照一套标准,把这台服务器的账号、端口、补丁、权限、配置逐项核对一遍,找出偏离项并修回去。

这篇文章给出一份可直接照着做的云服务器安全基线检查清单,覆盖五个方面:账号与权限(UID 0 账号、空口令、长期未登录、sudoers)、端口与服务(ss -lntp、关闭无用服务)、补丁(dnf/apt 更新、内核版本、是否需要重启)、文件权限(SUID、关键文件)、SSH 配置与日志审计。每一项都给出检查命令、判断标准和修复方向,命令区分 RHEL/CentOS/Rocky 与 Debian/Ubuntu 两套。

这份清单适用于单机或少量服务器的手工核查。如果你的服务器规模较大,建议把清单里的检查项做成脚本或接入自动化工具定期跑,把"人工巡检"变成"自动核查"。无论如何,涉及的删账号、改权限、装补丁操作都会给出风险提示和回滚方式,请在操作前确认影响范围。

一、为什么需要基线检查:从"能跑"到"可控"

安全基线这个概念听起来很正式,其实很朴素:它就是"这台服务器在一个健康状态下应该长什么样"的标准描述。账号该有哪些、端口该开哪些、补丁该打到什么程度、关键文件权限该是多少——这些就是基线。基线检查就是拿现状和标准比,找出不一样的地方。

它的价值在于"可重复"和"能发现问题"。手工凭感觉看服务器,每次关注的点和结论都可能不一样;而按固定清单逐项过一遍,就不会漏项,也便于不同人、不同时间得到一致的判断。对于只有一两台服务器的中小企业 IT 或个人站长,这就是最低成本的常态化安全运维。

基线检查最好定期做,比如每季度一次,或者每次上线新服务、改过防火墙之后再做一次。它也适合作为"接手一台老服务器"时的第一件事——在搞清楚它到底开了什么、跑了什么之前,任何优化都无从谈起。

二、账号与权限核查

账号是最容易被忽视、也最危险的一块。一个多余的账号可能就是一个后门。

检查 1:有没有非预期的 UID 0 账号

UID 为 0 的账号就是 root,拥有最高权限。系统里除了 root,不应该有第二个 UID 是 0 的账号——如果有,那几乎可以确定是被入侵后留下的后门。

# 列出所有 UID 为 0 的账号(正常应该只有 root 一个)
awk -F: '$3==0 {print $1, $3}' /etc/passwd

# 顺带看看 UID 和 GID 异常的账号
awk -F: '($3==0 || $4==0) {print $1, $3, $4}' /etc/passwd

判断标准很简单:除了 root,任何 UID 为 0 的账号都要查明来源,确认是恶意或多余的,立即处理。

检查 2:有没有空口令账号

空口令账号等于没有密码,能从某些通道直接登录,风险很大。

# 检查是否存在空口令账号(第 2 字段为空或只有 ::)
awk -F: '($2=="") {print "空口令:", $1}' /etc/shadow

# 更宽松地看:所有账号的口令字段状态
sudo awk -F: '{print $1, $2}' /etc/shadow | grep -E '^[^ ]+ *$|^[^ ]+ *!?$' | head

/etc/shadow 第二字段的含义要记住:! 或 * 表示该账号口令被锁定、无法用密码登录(这是好事,系统账号通常如此);$6$ 开头是加密后的口令哈希;空则表示可以空口令登录(危险)。

# 查看是否有账号允许空口令(部分系统可在 PAM 里检查)
sudo grep -r "nullok" /etc/pam.d/ 2>/dev/null

nullok 出现在 PAM 配置里意味着允许空口令登录,应该去掉。

检查 3:长期未登录的账号

用 lastlog 找从未登录或很久没登录的账号。长期不用的账号是"僵尸账号",一旦泄露就是隐患,应该锁定或删除。

# 查看每个账号最后一次登录时间
sudo lastlog

# 只看从未登录过的账号
sudo lastlog | grep -i "Never logged in"

处理时注意区分:系统服务账号(如 bin、daemon、sshd)本来就不会交互登录,不能用"未登录"来判断它们是多余的。真正要关注的是"人类用户"账号里长期不用的,以及能交互登录却从没登录过的。

# 锁定一个不再使用的账号(保留账号但禁止登录)
sudo usermod -L <用户名>
# 更彻底:把登录 shell 改为 nologin
sudo usermod -s /usr/sbin/nologin <用户名>

风险提示:usermod -L 锁定账号或删除账号前,务必确认该账号没有被业务、定时任务、服务进程使用。删错账号可能导致服务无法启动。回滚方式:usermod -U <用户名> 解锁;删错的账号视情况重建。生产环境操作前先备份 /etc/passwd、/etc/shadow、/etc/group。

检查 4:sudoers 与提权权限

sudoers 决定了谁能提权。要确认没有多余的提权授权,尤其要留意"免密提权"和"给普通用户全权限"的配置。

# 查看 sudoers 主文件(用 visudo 编辑,不要直接改)
sudo cat /etc/sudoers | grep -vE '^\s*#|^\s*$'

# 查看 sudoers.d 里的所有片段
sudo ls -l /etc/sudoers.d/
sudo grep -rE 'ALL' /etc/sudoers.d/ 2>/dev/null

# 找出所有能执行 sudo 的用户
sudo grep -rE '^\s*[^#].*ALL' /etc/sudoers /etc/sudoers.d/ 2>/dev/null

重点关注两类配置:一是 ALL=(ALL) NOPASSWD: ALL 这种"免密全权限",除非必要不应存在;二是给了一些不必要用户提权。编辑器一律用 visudo,它会做语法检查,避免改坏导致谁都提不了权。

# 正确编辑 sudoers 的方式
sudo visudo
# 如果 sudoers 写坏了导致无法 sudo,用 root 直接编辑(或进救援模式)修复
# 单用户/救援模式下:mount -o remount,rw / ;然后编辑 /etc/sudoers

另外也检查一下有没有非预期的 SUID 提权工具、以及 wheel/sudo 组的成员。

# 查看特权组成员
getent group sudo    # Debian/Ubuntu
getent group wheel   # RHEL 系

三、端口与服务核查

"开了哪些端口"直接等于"暴露面有多大"。用 ss 列出所有监听,逐个确认是否必要。

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

# 只列 TCP 监听(更清爽)
sudo ss -lntp

# 只列 UDP 监听
sudo ss -lnup

拿到列表后,按下面的标准逐项判断。

检查项 判断标准 处理方向
对外监听的服务 只保留业务必需的端口 关闭无用服务
监听地址 后端服务应绑 127.0.0.1 或内网 收窄到内网
数据库/缓存端口 不应出现在 0.0.0.0 绑内网 + 安全组限制
管理端口 应限制来源 白名单或走 VPN
未知进程监听 查清来源 确认恶意则清除

高风险的典型是:3306、6379、27017、9200、11211 这些后端服务监听在 0.0.0.0 且安全组放行了公网。看到这类情况,优先级最高。

同时盘一下正在运行的服务,关掉用不上的。

# 列出正在运行的服务
systemctl list-units --type=service --state=running

# 列出所有已启用(开机自启)的服务
systemctl list-unit-files --type=service --state=enabled

# 停用并禁止某个无用服务开机自启(示例)
sudo systemctl stop <服务名>
sudo systemctl disable <服务名>

风险提示:停用服务前,务必确认它不是业务依赖(尤其注意共享的中间件、监控代理、日志代理)。建议在业务低峰期操作,并记下 systemctl enable --now <服务名> 作为恢复命令。

四、补丁与内核版本核查

补丁是"用最低成本消除已知风险"的手段。一台长期不打补丁的服务器,等于把一堆已知问题原样保留着。

检查 5:查看系统版本与可用更新

# RHEL / CentOS / Rocky / AlmaLinux
cat /etc/redhat-release
sudo dnf check-update        # 列出可用更新(退出码 100 表示有更新)
sudo dnf updateinfo list security   # 只列安全相关更新(若仓库支持)

# Debian / Ubuntu
lsb_release -a
sudo apt update
sudo apt list --upgradable
# 只关注安全更新
sudo apt-get -s upgrade | grep -i security

先看有没有更新,决定是"立刻打"还是"排期打"。安全相关的更新优先级最高;内核、glibc、OpenSSL、OpenSSH 这类基础组件的更新尤其重要。

# 查看当前内核版本
uname -r
# 查看已安装的内核包
# RHEL 系:rpm -qa | grep kernel
# Debian/Ubuntu:dpkg -l | grep linux-image

检查 6:是否需要重启才能生效

打补丁后有个常见陷阱:内核和某些库的更新不会立即生效,必须重启。判断依据是有没有生成 /var/run/reboot-required 这类标记,或者当前运行内核是否与已安装的最新内核一致。

# Debian / Ubuntu:检查是否需要重启
ls -l /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs 2>/dev/null

# RHEL 系:用 needs-restarting(需 dnf-utils 包)
sudo dnf install -y dnf-utils
sudo needs-restarting -r        # -r 检查是否需要重启
sudo needs-restarting -s        # 检查哪些服务需要重启

# 通用:对比正在运行的内核与已安装的最新内核
uname -r
rpm -q kernel | sort -V | tail -1        # RHEL 系
dpkg -l | grep linux-image | tail -1     # Debian/Ubuntu

如果运行的内核比已安装的最新内核旧,就需要择期重启。重启前要安排好维护窗口,并确认服务能自动拉起。

# 打补丁(示例)
# RHEL 系:
sudo dnf update -y
# 只打安全补丁(若发行版支持)
sudo dnf update --security -y

# Debian / Ubuntu:
sudo apt update && sudo apt upgrade -y
sudo apt full-upgrade -y       # 处理依赖关系变化时使用

风险提示:dnf update/apt upgrade 可能升级内核、glibc 等基础组件,存在与业务不兼容的可能。生产环境应先在测试环境验证,或至少先做快照/备份,并安排在维护窗口执行。重启前确认有带外管理(云控制台)可用,避免重启后系统起不来却无法介入。回滚方式:RHEL 系可 dnf history undo,云服务器可回滚快照。

五、文件权限核查

权限配错是又一个高频问题。核心是找"不该有的 SUID/SGID"和"过于宽松的关键文件权限"。

检查 7:查找 SUID/SGID 文件

SUID 文件在执行时以文件属主的权限运行,如果属主是 root,就等于一个提权入口。系统自带的 SUID 程序是正常的,但多余的、可被滥用的 SUID 文件是隐患。

# 查找所有 SUID 文件(-perm -4000)
sudo find / -xdev -perm -4000 -type f -ls 2>/dev/null

# 查找所有 SGID 文件(-perm -2000)
sudo find / -xdev -perm -2000 -type f -ls 2>/dev/null

# 结合 RPM/DPKG 校验,找出"包管理之外"的 SUID 文件(更精准)
# RHEL 系:用 rpm 校验文件是否属于某个包
sudo find / -xdev -perm -4000 -type f -exec rpm -qf {} \; 2>/dev/null | grep "not owned"
# Debian/Ubuntu:
sudo find / -xdev -perm -4000 -type f -exec dpkg -S {} \; 2>/dev/null | grep "no path found"

-xdev 表示不跨越文件系统(避免扫描挂载的网络盘)。判断标准:如果一个 SUID 文件不属于任何软件包(not owned/no path found),或者它的作用你完全不清楚,就应该重点审视。常见系统 SUID 程序如 passwd、sudo、su、mount 是正常的;如果你发现某个莫名其妙的自定义二进制带 SUID,要高度警惕。

# 去掉某个不必要的 SUID 位(谨慎,确认不影响功能)
sudo chmod u-s /path/to/file

检查 8:关键文件与目录权限

下面这些文件/目录的权限如果过松,可能被篡改或读取敏感信息。

# 检查关键文件的权限(第一列是权限、属主、属组)
ls -l /etc/passwd /etc/shadow /etc/group /etc/gshadow
ls -ld /etc /root /home /var/log

# 检查是否有全局可写的目录或文件(高风险)
sudo find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/null    # 全局可写且无 sticky 位
sudo find / -xdev -type f -perm -0002 2>/dev/null | head -50       # 全局可写文件

权限的"正确值"参考:

文件/目录 期望权限 说明
/etc/passwd 644 可被读,不应被写
/etc/shadow 000 或 640(root 可读) 绝不能全局可读
/etc/group 644 —
/etc/gshadow 000 或 640 —
/root 700 只有 root 可进
/etc/ssh/sshd_config 600 含配置,不应被普通用户改
用户 ~/.ssh 700 见 SSH 密钥文章
用户 ~/.ssh/authorized_keys 600 —
# 修正关键文件权限(示例,按上表调整)
sudo chmod 644 /etc/passwd /etc/group
sudo chmod 000 /etc/shadow /etc/gshadow     # 或 640,视发行版而定
sudo chmod 700 /root

# 排查全局可写的目录(临时目录 /tmp 通常是 1777,带 sticky 位,属正常)
sudo find / -xdev -type d -perm -0002 ! -perm -1000 2>/dev/null

风险提示:修改 /etc/shadow、/etc/gshadow 的权限时,不同发行版和 PAM 配置对权限要求可能不同,改错会导致无法登录或认证失败。改之前务必确认当前值,并用另一个已登录的会话验证。建议逐项小改、改完立即验证。

六、SSH 配置与日志审计核查

SSH 是公网服务器最常被攻击的入口,它的配置要重点核查。用 sshd -T 查看实际生效的配置(比看文件更可靠,它会合并所有片段)。

# 查看 SSH 生效的关键配置
sudo sshd -T | grep -iE 'passwordauthentication|permitrootlogin|pubkeyauthentication|permitemptypasswords|maxauthtries|port'

# 期望值(加固目标):
# passwordauthentication no      (关闭密码登录)
# permitrootlogin no             (禁止 root 直登)
# pubkeyauthentication yes       (启用密钥)
# permitemptypasswords no        (禁止空口令)
# maxauthtries 3                 (限制尝试次数)

如果发现 passwordauthentication yes 且服务器在公网,应立即按密钥登录那篇的流程加固。

日志审计方面,确认日志在正常记录,并定期看失败登录的分布。

# 查看认证日志是否在记录
sudo tail -20 /var/log/secure        # RHEL 系
sudo tail -20 /var/log/auth.log      # Debian/Ubuntu
# 用 journalctl 也可
sudo journalctl -u sshd --since "1 day ago" | tail -20

# 统计失败登录 Top IP
sudo grep "Failed password" /var/log/secure 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10
# Debian/Ubuntu 换成 /var/log/auth.log

七、一份可勾选的基线检查清单

把上面所有内容整理成一张表,做成日常巡检的勾选项。

序号 检查项 检查命令(要点) 通过标准 状态
1 UID 0 账号 awk -F: '$3==0{print $1}' /etc/passwd 只有 root ☐
2 空口令账号 awk -F: '($2==""){print $1}' /etc/shadow 无空口令账号 ☐
3 长期未登录账号 lastlog 无多余人类账号 ☐
4 sudoers 授权 grep -r ALL /etc/sudoers* 无多余免密提权 ☐
5 监听端口 ss -lntup 只开业务必需端口 ☐
6 后端服务暴露 ss -lntp \| grep 3306 未监听 0.0.0.0 ☐
7 无用服务 systemctl list-unit-files --state=enabled 无多余自启服务 ☐
8 系统更新 dnf check-update / apt list --upgradable 无高危未打补丁 ☐
9 内核版本 uname -r vs 已装内核 一致或已排期重启 ☐
10 是否需要重启 needs-restarting -r / 查 reboot-required 无待重启 ☐
11 SUID 文件 find / -xdev -perm -4000 无非预期 SUID ☐
12 关键文件权限 ls -l /etc/shadow /etc/passwd 符合期望值 ☐
13 全局可写文件 find / -xdev -type f -perm -0002 无异常 ☐
14 SSH 加固 sshd -T \| grep password 关闭密码登录 ☐
15 日志审计 看失败登录 Top IP 日志正常、无异常成功登录 ☐

每次巡检时,逐项对照,把"不通过"的项列出来,安排修复并在下一次复查时确认闭环。

常见问题

Q:多久做一次基线检查?
建议每季度一次,加上"重大变更后"(上线新服务、改过防火墙/SSH、装过新软件)。对于暴露在公网的服务器,补丁检查可以更频繁,比如每月看一眼有没有安全更新。

Q:发现一个 UID 0 的可疑账号,怎么处理?
这是最高优先级的事。先不要急着删——它可能是入侵后的后门。正确做法是:保留现场、检查该账号相关的进程和登录记录、排查是否还有其他后门(新增公钥、定时任务、异常进程),确认影响范围后再清理,并考虑重装系统。删账号只是最后一步,前面的排查更重要。

Q:补丁要不要全部打?会不会影响业务?
优先打安全补丁,尤其是内核、OpenSSL、OpenSSH、glibc 这类基础组件。业务相关的更新(比如某个中间件的小版本)要评估兼容性。生产环境建议先在测试环境验证,或用云快照做好回滚准备,并安排在维护窗口执行。

Q:SUID 文件很多,哪些需要关注?
默认系统自带的 SUID 程序是正常的,不用动。需要关注的是"不属于任何软件包"的、位置奇怪的、名字陌生的 SUID 文件。用 rpm -qf/dpkg -S 判断它是否属于某个包,是个高效的筛选方法。

Q:手工逐项检查太慢,有更高效的办法吗?
可以写成一个 shell 脚本,把上面清单里的命令串起来,输出一份报告;也可以接入成熟的安全检查工具(如开源的基线核查工具或云厂商的安全中心)。核心是让"检查"这件事可重复、可自动化,而不是每次靠人重来。

总结

安全基线检查的实质,是定期把服务器现状和"健康状态的标准"做一次对照。它不复杂,但贵在坚持和覆盖全面。

账号方面,重点查 UID 0 账号、空口令账号、长期未登录账号和 sudoers 授权——这几项直接关系到"谁能提权、谁能登录",是风险最高的一类。

端口与服务方面,用 ss -lntup 盘清所有监听,只留业务必需的;后端服务必须绑内网,绝不能监听在 0.0.0.0 并放行公网。

补丁方面,定期看可用更新、优先打安全补丁、记住内核更新需要重启才生效,重启前备好快照和控制台入口。

文件权限方面,用 find -perm -4000 找 SUID、核对关键文件权限、排查全局可写文件,这些都是能被利用的薄弱点。

最后,把这份清单做成可勾选、可重复的表,甚至写成脚本自动跑。安全不是一次性配置的结果,而是持续核查、持续修正的过程。基线守住了,风险就很难悄悄积累起来。