CentOS 发行版为了兼容各种使用场景,默认会启用相当多的系统服务。对只跑 Web 或数据库的服务器来说,这些服务里可能只有几个是真正需要的,其余都是多余的暴露面。服务数量越多,系统出现漏洞后能被利用的入口就越多,而监听端口正是攻击者扫描时最先关注的目标。CentOS 6 及更早版本使用 chkconfig 管理开机自启,CentOS 7 以后由 systemd 接管,本文主要面向 systemd 环境。

减少攻击面通常比堆叠安全软件更直接。比如一台只提供静态网站的主机,如果还开着打印服务、邮件服务和 RPC 绑定服务,等于给攻击者额外提供了探测路径。本文会从服务审计、禁用操作、恢复方法和常见可关闭服务几个层面展开,帮助在保持业务可用的前提下把系统尽量收敛。
一、为什么服务裁剪是安全加固的第一步
攻击面可以理解为系统中所有能够被外部或本地用户访问、调用、探测的入口。后台服务是攻击面的主要组成部分,每个监听端口、每个本地套接字都可能成为攻击链条中的一环。CentOS 默认安装后,有一些服务是根据桌面或通用场景启用的,例如打印服务 cups、本地邮件投递服务 postfix、零配置网络服务 avahi-daemon 等。如果服务器不需要这些功能,它们的存在只会增加风险,而不带来任何收益。
系统管理员可以使用 ss -tulnp 查看当前监听的 TCP 和 UDP 端口。输出中除了必要的 SSH 端口,如果还看到 25、631、111、5353 等端口,通常意味着存在可以关闭的服务。例如 25 端口对应邮件传输,631 对应打印服务,111 对应 rpcbind,5353 对应 mDNS 广播。这些端口在纯 Web 或数据库服务器上大多不需要。
ss -tulnp
从安全角度看,减少服务比安装补丁和防护设备更基础。因为服务没有启用时,即使该软件存在漏洞,攻击者也没有直接利用的通道。禁用服务不会改变业务代码,也不需要额外软件授权,是成本最低的加固手段之一。
二、如何准确识别哪些服务可以关闭
关闭服务前必须先做审计,不能凭感觉直接批量禁用。第一步是列出所有开机自启的服务单元。在 CentOS 7 及之后的版本中,systemd 是主要管理工具,可以使用 systemctl list-unit-files --type=service --state=enabled 查看已经被设置为开机启动的服务。这个列表通常比实际运行的进程列表更值得关注,因为它反映了重启后系统仍会开放的入口。
systemctl list-unit-files --type=service --state=enabled
拿到列表后,可以结合服务器的角色逐项判断。Web 服务器往往只需要 sshd、防火墙、审计、监控采集等基础服务。数据库服务器还需要数据库自身的守护进程。对于像 postfix、cups、avahi-daemon、rpcbind 这类与业务无关的服务,通常可以直接禁用。但要注意有些服务之间存在依赖关系,例如 rpcbind 与 NFS 相关,如果系统作为 NFS 客户端或服务端使用,就不能轻易关闭。
可以通过 systemctl list-dependencies 查看某个服务被谁依赖,或者它会拉起哪些依赖项。例如执行 systemctl list-dependencies rpcbind.service 可以看到关联关系。如果输出中只有它自己,没有业务服务引用,关闭风险就较低。
systemctl list-dependencies rpcbind.service
常见可禁用服务可以参考下表,但具体环境仍要结合实际情况确认:
| 服务名称 | 用途 | 常见判断 |
|---|---|---|
| postfix | 本地邮件传输代理 | 不用邮件发送和接收可关闭 |
| cups | 打印服务 | 服务器无打印需求可关闭 |
| avahi-daemon | 零配置网络发现 | 无 mDNS 需求可关闭 |
| rpcbind | RPC 端口映射 | 不用 NFS 等 RPC 服务可关闭 |
| chronyd | 时间同步 | 建议保留以保证时间准确 |
| firewalld | 防火墙 | 不建议关闭,应保留并配置策略 |
| sshd | 远程登录 | 务必保留,除非有带外管理手段 |
这张表的作用是提供一个判断起点,而不是绝对标准。生产环境建议先在测试机上验证禁用后的业务表现,再同步到正式服务器。
三、禁用服务的具体命令与验证方法
确定某个服务不需要后,推荐使用 systemctl disable --now 服务名 一次完成两步操作。其中 disable 表示取消开机自启,--now 表示同时停止当前正在运行的实例。以 postfix 为例,命令如下:
systemctl disable --now postfix.service
如果服务由 socket 单元触发启动,还需要处理对应的 socket 文件。例如 cups 除了有 cups.service,还可能有 cups.socket 和 cups.path。可以通过 systemctl list-unit-files | grep cups 查看完整的相关单元,然后一并禁用。
systemctl list-unit-files | grep cups systemctl disable --now cups.service cups.socket cups.path
对于已经明确不需要、并且不希望被其他依赖意外拉起的服务,可以使用 mask 命令。mask 会把服务单元链接到 /dev/null,即使后续手动执行 systemctl start 服务名 也会被拒绝。这个操作比 disable 更彻底,适合处理 avahi-daemon、rpcbind 等明确无用的服务。
systemctl mask avahi-daemon.service
完成操作后,需要用命令验证。先查看服务状态,执行 systemctl is-enabled postfix.service,如果返回 disabled 或 masked,说明开机自启已经取消。再执行 ss -tulnp 检查对应端口是否已经不再监听。对于之前监听的 25、631、111 等端口,如果不再出现,说明服务已经真正停止。
systemctl is-enabled postfix.service ss -tulnp | grep -E ':25|:631|:111'
需要注意的是,禁用服务不会删除软件包,只是停止运行和开机自启。如果误操作导致业务异常,可以快速恢复。unmask 可以解除 mask 状态,enable --now 可以重新启用并启动服务。
systemctl unmask avahi-daemon.service systemctl enable --now postfix.service
四、批量精简时的注意事项
如果管理的服务器数量较多,可以编写脚本批量执行禁用操作。但脚本中必须先定义明确的白名单,避免误关关键服务。例如下面的脚本只会处理列表中的服务,不会影响 sshd、firewalld、auditd 等基础服务。
#!/bin/bash
services="postfix cups avahi-daemon rpcbind"
for svc in $services; do
systemctl disable --now $svc 2>/dev/null
systemctl mask $svc 2>/dev/null
done
这段代码中的 2>/dev/null 表示忽略错误输出,防止某个服务不存在时中断脚本。如果要在生产环境使用,建议先去掉 2>/dev/null,让错误信息正常打印,便于确认每个服务的处理结果。
安全加固不是一次性工作。系统更新、软件安装、业务变更都可能重新引入服务。建议将服务审计纳入定期检查流程,每月或每次发布后重新执行 systemctl list-unit-files --type=service --state=enabled,并与基线列表比对。如果出现新增的自启服务,先判断来源,再决定保留或关闭。
另外,不同 CentOS 版本的服务名称可能略有差异。例如 CentOS 7 中常见的 chronyd 在部分旧版本中可能未默认启用;rpcbind 在不同小版本中可能以 rpcbind.service 或 rpcbind.socket 形式存在。所以在自动化脚本里最好先通过 systemctl list-unit-files 确认名称,再执行禁用。
归根结底,禁用不必要服务是为了减少系统暴露面,而不是追求服务数量越少越好。保持 SSH、防火墙、时间同步、系统审计这些基础能力,才能在安全和可维护性之间取得平衡。把默认服务清单逐项消化,比直接照搬别人的禁用脚本更稳妥。