Linux系统安全基线检查与加固实战指南:从CIS标准到自动化脚本
1. 项目概述:为什么我们需要系统安全基线检查?
干了这么多年运维和安全,我见过太多因为基础配置疏忽导致的“血案”。服务器被悄无声息地挖矿、数据库被勒索、核心业务数据被拖库,追根溯源,往往不是什么高深的0day漏洞,而是SSH弱口令、Redis未授权访问、或者一个本该关闭的匿名FTP服务。这些问题的根源,就在于系统没有一个清晰、统一且被严格执行的“安全基线”。
所谓Linux系统安全基线检查,你可以把它理解为一套针对Linux服务器的“安全体检标准手册”。它不像漏洞扫描那样去发现未知的软件缺陷(CVE),而是去检查那些已知的、但容易被忽略的不安全配置。比如,你的密码策略是不是太弱?关键服务的日志审计开了吗?不必要的网络端口是不是还开着?这些配置项如果不符合安全最佳实践,就会给攻击者留下可乘之隙,成为他们入侵系统的“捷径”。
入侵防范测试,则是基于这套基线标准进行的主动验证。光有标准不行,你得去查、去测,看看实际环境到底有没有达标。这不仅仅是合规(比如等保二级、三级)的要求,更是实战防御的基石。一个配置牢固的系统,能有效抵御大部分自动化攻击和低水平黑客的渗透尝试。
而漏洞修复,则是另一个维度。它针对的是软件本身存在的缺陷,比如最近常被问到的CVE-2021-3618(Apache HTTP Server漏洞)或CVE-2016-2183(SSL/TLS协议信息泄露漏洞)。基线检查管“配置”,漏洞修复管“代码”。两者相辅相成,共同构成服务器安全防护的左右手。
所以,无论你是运维工程师、安全工程师,还是需要自己维护服务器的开发者,掌握一套行之有效的安全基线检查与加固方法,都是必备技能。这不仅能让你睡得更安稳,也是应对各种安全审计和合规检查的“硬通货”。接下来,我就结合自己多年的踩坑经验,带你从零开始,建立一套可落地、可复现的Linux系统安全基线检查与加固实战流程。
2. 安全基线核心框架与检查标准解析
在做具体操作之前,我们必须先搞清楚要检查什么、依据什么标准来检查。盲目地执行命令而没有全局观,很容易遗漏重点或者做无用功。
2.1 主流安全基线框架与分类
目前业界并没有一个唯一的“圣经”,而是存在多套被广泛认可的安全基线框架。我们需要根据自身业务场景和合规要求进行选择和组合。主要可以分为以下几类:
- 国际通用安全最佳实践:例如CIS(互联网安全中心)Benchmarks。这是最权威、最细致的行业标准之一,CIS为CentOS、Ubuntu、Docker、Kubernetes等提供了数百条具体的检查项。它的特点是极其全面和严格,通常用于对安全性要求极高的环境。
- 国家/行业合规标准:在中国,最典型的就是网络安全等级保护2.0标准。等保二级、三级对操作系统、数据库、中间件等都有明确的安全配置要求。很多企业做基线检查的首要驱动力就是为了满足等保合规。
- 云厂商最佳实践:如阿里云、腾讯云、AWS等都会基于其庞大的实战经验,发布针对自家云平台和常用系统的安全基线建议。这些建议往往更贴近云上实际运维场景,实操性很强。
- 企业自定义基线:每个公司的业务架构、技术栈和风险承受能力都不同。在参考上述标准的基础上,企业需要制定自己的自定义基线。例如,规定所有业务服务器必须禁用root的SSH直接登录,或者统一使用某个特定版本的OpenSSH。
从你提供的资料看,一个完整的基线检查体系通常会覆盖以下维度:
- 账号与口令安全:检查弱口令、密码复杂度策略、账户锁定策略、不必要的默认账户等。
- 权限与访问控制:检查文件与目录权限(如
/etc/passwd、/etc/shadow的权限应为644和400)、SUID/SGID特殊权限文件、sudoers配置等。 - 服务与端口管理:检查不必要的服务是否被启用(如
telnet、rpcbind)、网络监听端口是否最小化。 - 日志与审计:检查syslog、auditd等审计服务是否启用,关键操作(如用户登录、特权命令执行)是否被记录。
- 内核与系统参数安全:检查
/etc/sysctl.conf中的网络参数(如禁止IP转发、开启SYN Cookie)、文件系统挂载参数(如noexec、nosuid)等。 - 应用配置安全:针对SSH、MySQL、Redis、Nginx等具体应用,检查其配置文件中的安全选项(如SSH的
Protocol 2、PermitRootLogin no)。
2.2 如何选择适合你的检查标准?
对于大多数场景,我建议采用“合规打底,最佳实践增强”的策略:
- 如果面临等保测评:优先严格按照等保二级或三级检查项列表来执行。这是硬性要求,没有商量余地。你需要关注等保标准中“安全计算环境”部分对身份鉴别、访问控制、安全审计、入侵防范、恶意代码防范等方面的具体要求,并将其转化为具体的Linux配置检查点。
- 如果追求极致安全(如金融、核心数据库):在满足合规基础上,深度融合CIS Benchmarks。虽然有些条款可能过于严格(比如会禁用某些运维便利功能),但对于核心资产,严格一点是值得的。
- 如果是普通业务服务器:可以采用云厂商的最佳实践基线作为起点,再根据业务需要增加一些自定义条款。这样既能保证基础安全水位,又不会带来过高的管理成本。
一个重要的实操心得:不要试图一次性应用所有最严格的标准。安全是平衡的艺术,过度安全可能影响业务可用性和运维效率。我建议分阶段实施:先解决“高危”和“中危”项(如弱口令、未授权访问),再逐步细化到“低危”项和审计类配置。
3. 手工检查与脚本自动化实战
了解了标准,我们就要动手了。我将从手工检查和脚本自动化两个层面,带你走一遍核心检查项。
3.1 关键安全配置手工检查要点
在引入任何自动化工具前,手动检查能帮你建立最直观的理解。打开你的终端,我们逐一排查。
3.1.1 账号与口令安全
这是入侵的第一道防线,也是被攻破的重灾区。
检查弱口令:这是最紧急的。虽然手工无法直接爆破,但可以检查系统是否使用了默认或极简单的口令。
# 查看/etc/shadow文件,关注密码哈希字段(第二个字段),如果为`!`或`*`表示未设置密码或登录被禁用,为空或简单哈希则是危险的。 sudo cat /etc/shadow | awk -F: '($2 == "" ) { print $1 " 未设置密码!"}'注意:
/etc/shadow文件权限必须为400或更严格,检查命令:ls -l /etc/shadow。检查密码策略:
# 查看PAM密码复杂度配置(CentOS/RHEL系列) cat /etc/security/pwquality.conf # 查看密码过期策略 cat /etc/login.defs | grep -E \"PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_WARN_AGE\"修复建议:编辑
/etc/login.defs,设置PASS_MAX_DAYS 90(密码最长90天过期),PASS_WARN_AGE 7(过期前7天警告)。检查不必要的系统账户:许多服务会创建非登录账户(如
bin、daemon),确保它们的登录shell是/sbin/nologin或/bin/false。sudo cat /etc/passwd | awk -F: '($7 != \"/sbin/nologin\" && $7 != \"/bin/false\") {print $1 \" -> \" $7}'
3.1.2 SSH服务安全配置
SSH是Linux服务器的命门,必须严防死守。
# 查看SSH主配置文件 cat /etc/ssh/sshd_config | grep -v \"^#\" | grep -v \"^$\"你需要重点关注并确认以下参数是否已按安全要求设置:
| 参数 | 安全值 | 说明与理由 |
|---|---|---|
Protocol | 2 | 禁用老旧的、不安全的SSHv1协议。 |
PermitRootLogin | no | 禁止root用户直接登录。应使用普通用户登录后su或sudo提权。这是防止暴力破解root账户的最有效方法之一。 |
PasswordAuthentication | no | 禁用密码认证,强制使用密钥对认证。这是比复杂密码更安全的登录方式。如果业务上必须用密码,则此项可设为yes,但务必配合强密码策略和Fail2ban等防爆破工具。 |
PermitEmptyPasswords | no | 禁止空密码登录。 |
X11Forwarding | no | 除非必要,否则禁用X11转发,减少攻击面。 |
MaxAuthTries | 3或4 | 限制每次连接的最大认证尝试次数,减缓暴力破解。 |
ClientAliveInterval和ClientAliveCountMax | 例如300和2 | 设置客户端活跃间隔(300秒)和最大次数(2次),用于自动断开无响应的会话,防止僵尸连接占用资源。 |
修改后务必重启SSH服务:sudo systemctl restart sshd。但强烈建议在重启前,先开一个新的终端窗口用现有连接测试新配置是否生效,或者使用sshd -t测试配置文件语法,避免配置错误导致自己无法登录。
3.1.3 服务与端口最小化
“最小的权限,最少的服务”是安全的核心原则。
# 1. 查看系统启动的服务 systemctl list-unit-files --type=service --state=enabled # 或使用老式系统命令 chkconfig --list | grep \"3:on\" # 2. 查看网络监听端口 sudo netstat -tunlp # 或使用更现代的ss命令 sudo ss -tunlp检查思路:对每一个监听在0.0.0.0(即所有接口)上的端口,问自己三个问题:1. 这个服务是业务必需的吗?2. 它只能监听在本地回环127.0.0.1吗?3. 它的版本是否最新,有无已知漏洞?
常见可关闭的非必要服务:telnet-server、rpcbind(如果不用NFS)、vsftpd(如果不用FTP)、postfix(如果不用本地邮件发送)。禁用命令:sudo systemctl disable <service_name>。
3.1.4 文件系统与权限检查
错误的权限可能导致敏感信息泄露或提权。
# 检查关键系统文件的权限 ls -l /etc/passwd /etc/shadow /etc/group # 应为:-rw-r--r--, -r--------, -rw-r--r-- # 查找所有SUID/SGID文件(这些文件在执行时会以文件所有者或组的权限运行,风险较高) sudo find / -type f \\( -perm -4000 -o -perm -2000 \\) -exec ls -l {} \\; 2>/dev/null对于发现的SUID/SGID文件,需要逐一甄别。像/bin/passwd、/bin/su是正常的,但如果发现/tmp目录下或某个web目录下有莫名其妙的SUID文件,那极有可能是后门。
3.2 自动化检查脚本编写与使用
手工检查适合单台服务器或深度排查,对于成百上千的服务器,必须依靠自动化。你可以使用开源的自动化检查脚本,也可以自己编写。
3.2.1 使用成熟的开源工具
Lynis:一款老牌、强大、开源的Linux安全审计工具。它几乎涵盖了CIS基准的所有检查点,并给出详细的加固建议。
# 下载并运行(需要root权限) sudo wget -O - https://downloads.cisofy.com/lynis/lynis-3.0.8.tar.gz | tar -xzf - cd lynis sudo ./lynis audit system运行后,它会生成一份非常详细的报告,包括警告、建议和已通过的检查项。它的建议(
suggestion)部分尤其有价值。OpenSCAP:这是一个框架,配合SCAP(安全内容自动化协议)标准的安全基线文件(如CIS的XML格式基准)使用,可以进行非常规范的合规性扫描。
# 在RHEL/CentOS上安装 sudo yum install openscap-scanner scap-security-guide # 使用CIS基准进行扫描 sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis --results scan-results.xml --report scan-report.html /usr/share/xml/scap/ssg/content/ssg-centos7-ds.xml它会生成HTML格式的报告,明确指出哪些项不符合基准。
3.2.2 编写自己的Shell检查脚本
对于高度定制化的需求,自己写脚本更灵活。下面是一个极简的示例框架,用于检查几个关键项:
#!/bin/bash # 文件名:quick_baseline_check.sh # 描述:Linux安全基线快速检查脚本 # 作者:Your Name # 使用:sudo bash quick_baseline_check.sh echo \"========== Linux安全基线快速检查 ==========\" echo \"检查时间:$(date)\" echo \"主机名:$(hostname)\" echo \"===========================================\" # 1. 检查SSH配置 echo -e \"\\n[1] 检查SSH配置\" ssh_protocol=$(sudo grep -i \"^Protocol\" /etc/ssh/sshd_config | awk '{print $2}') ssh_root_login=$(sudo grep -i \"^PermitRootLogin\" /etc/ssh/sshd_config | awk '{print $2}') ssh_password_auth=$(sudo grep -i \"^PasswordAuthentication\" /etc/ssh/sshd_config | awk '{print $2}') echo \"SSH Protocol: ${ssh_protocol:-未配置,默认可能为2}\" [[ \"$ssh_protocol\" != \"2\" ]] && echo \" [警告] 建议设置 Protocol 2\" echo \"PermitRootLogin: ${ssh_root_login:-未配置,默认可能为yes}\" [[ \"$ssh_root_login\" != \"no\" ]] && echo \" [高危] 建议设置 PermitRootLogin no\" echo \"PasswordAuthentication: ${ssh_password_auth:-未配置,默认可能为yes}\" [[ \"$ssh_password_auth\" != \"no\" ]] && echo \" [中危] 建议使用密钥认证,设置 PasswordAuthentication no\" # 2. 检查密码策略 echo -e \"\\n[2] 检查密码过期策略\" pass_max_days=$(grep \"^PASS_MAX_DAYS\" /etc/login.defs | awk '{print $2}') if [[ -n \"$pass_max_days\" && $pass_max_days -gt 90 ]]; then echo \" [中危] 密码最大有效期(${pass_max_days}天)超过90天,建议修改\" else echo \" 密码最大有效期: ${pass_max_days:-未配置} 天 (符合<=90天要求)\" fi # 3. 检查监听端口 echo -e \"\\n[3] 检查非本地回环监听端口\" echo \"以下服务监听在非127.0.0.1地址,请确认其必要性:\" sudo ss -tunlp | grep -v \"127.0.0.1\" | grep -v \"::1\" | head -20 # 4. 检查关键文件权限 echo -e \"\\n[4] 检查关键文件权限\" shadow_perm=$(stat -c \"%a\" /etc/shadow 2>/dev/null) if [[ \"$shadow_perm\" != \"0\" && \"$shadow_perm\" != \"400\" && \"$shadow_perm\" != \"600\" ]]; then echo \" [高危] /etc/shadow 文件权限为 ${shadow_perm},应为400或600\" else echo \" /etc/shadow 文件权限 ${shadow_perm} 正常\" fi echo -e \"\\n========== 检查结束 ==========\"你可以根据需要,无限扩展这个脚本的功能,比如加入对sysctl参数、日志配置、sudoers文件、特定服务(如MySQL、Redis)配置的检查。
编写自动化脚本的注意事项:
- 兼容性:你的脚本可能需要运行在CentOS 7、Ubuntu 18.04/20.04、Alibaba Cloud Linux等多种发行版上,要注意命令和配置文件的路径差异。
- 错误处理:使用
2>/dev/null屏蔽无关错误,但关键命令失败时应有明确提示。 - 输出清晰:像上面的例子一样,分等级([高危]、[中危]、[建议])输出结果,方便后续处理。
- 不要造成破坏:检查脚本原则上只读不写。任何修复操作都应单独、谨慎地进行。
4. 专项入侵防范测试与漏洞修复
基线检查是筑墙,入侵防范测试就是“攻防演练”,主动验证这堵墙是否结实。这里我们聚焦两个最常被利用的入口:未授权访问和特定软件漏洞。
4.1 未授权访问漏洞检测与修复
未授权访问意味着攻击者不需要密码就能直接连接你的服务,危害极大。Redis和Docker是重灾区。
Redis未授权访问检测:
# 假设目标Redis在本地6379端口 redis-cli -h 127.0.0.1 -p 6379 # 如果直接进入了,显示 `127.0.0.1:6379>`,则存在未授权访问! # 或者使用nc命令测试 echo \"INFO\" | nc -nv 127.0.0.1 6379修复方法:
- 绑定IP:在
redis.conf中设置bind 127.0.0.1(如果只有本机需要访问)或内网IP。 - 设置密码:在
redis.conf中取消requirepass foobared的注释,并将foobared改为强密码。 - 重命名危险命令:在
redis.conf中,通过rename-command FLUSHALL \"\"等方式禁用或重命名FLUSHALL、CONFIG、EVAL等危险命令。 - 以低权限用户运行:不要用root运行Redis,创建一个专用用户如
redis。
- 绑定IP:在
Docker Daemon未授权访问检测: Docker守护进程默认监听在Unix Socket (
/var/run/docker.sock),如果被错误地暴露在TCP端口(如2375)且无认证,攻击者就能完全控制主机。# 检查Docker是否在监听TCP端口 sudo netstat -tunlp | grep :2375 # 或使用Docker客户端直接测试 docker -H tcp://目标IP:2375 version修复方法:
- 立即停止暴露在TCP端口:修改Docker服务启动配置(如
/lib/systemd/system/docker.service),移除-H tcp://0.0.0.0:2375这类参数。 - 如必须远程访问,启用TLS认证:这是官方推荐的安全方式,需要配置CA证书、服务器证书和客户端证书。步骤稍复杂,但必不可少。
- 使用SSH隧道:更简单的方法是通过SSH隧道访问远程Docker:
ssh -N -L /tmp/docker.sock:/var/run/docker.sock user@remote_host,然后本地设置DOCKER_HOST=unix:///tmp/docker.sock。
- 立即停止暴露在TCP端口:修改Docker服务启动配置(如
4.2 常见CVE漏洞修复实战:以CVE-2021-3618为例
CVE-2021-3618是Apache HTTP Server 2.4.48及之前版本的一个路径穿越漏洞,攻击者可能利用它读取Web目录外的文件。修复方法就是升级到安全版本。
修复流程:
- 确认当前版本与受影响范围:
如果版本号小于2.4.49,则受影响。httpd -v # 或 apache2 -v - 备份现有配置:
sudo cp -rp /etc/httpd /etc/httpd.backup.$(date +%Y%m%d) # 对于Ubuntu/Debian,路径可能是 /etc/apache2 - 通过包管理器升级:
- CentOS/RHEL/Alibaba Cloud Linux:
sudo yum clean all sudo yum update httpd - Ubuntu/Debian:
sudo apt update sudo apt upgrade apache2
- CentOS/RHEL/Alibaba Cloud Linux:
- 验证升级:
httpd -v systemctl restart httpd systemctl status httpd - 测试业务:重启服务后,务必对网站的主要功能进行回归测试,确保升级没有引入兼容性问题。
通用漏洞修复原则:
- 优先级:先修复远程代码执行(RCE)、权限提升、严重信息泄露漏洞,再修复其他中低危漏洞。
- 来源:优先使用操作系统官方仓库(yum/apt)提供的安全更新。如果官方仓库滞后,再考虑从软件官网下载源码包编译,但需自行管理后续更新。
- 回滚方案:对于核心业务服务,升级前一定要有明确的、测试过的回滚方案(如快照、备份的安装包和配置文件)。
5. 基线加固实操、问题排查与持续运营
检查出问题只是第一步,如何安全、稳定地修复,并在修复后验证,才是更考验人的地方。
5.1 安全加固操作指南与避坑指南
加固操作必须谨慎,一个错误的配置可能导致服务不可用。以下是一些核心操作的指南和常见坑点:
修改SSH配置禁用密码登录:错误做法:直接在
sshd_config里把PasswordAuthentication改成no,然后重启服务。如果你还没有配置好密钥对,你会立刻被锁在服务器外面!正确流程:- 先在服务器上为你的账户配置SSH公钥认证,并测试用密钥可以登录。
- 在
sshd_config中,将PasswordAuthentication设置为no,同时确保PubkeyAuthentication为yes。 - 执行
sudo sshd -t测试配置文件语法。 - 保持当前SSH会话窗口不关闭,新开一个终端窗口,用密钥登录测试。确认无误后,再回到原窗口重启
sshd服务。
批量修改密码策略: 修改
/etc/login.defs对新建用户生效。对于已存在用户,需要使用chage命令。# 修改现有用户user1的密码最大有效期 sudo chage -M 90 user1 # 查看用户的密码策略详情 sudo chage -l user1关闭不必要的服务: 不要直接用
systemctl stop停掉一个不认识的服务就完事。先查清楚它是干什么的。systemctl status <service_name> # 查看服务状态和描述 rpm -qf `which <service_binary>` # 或 dpkg -S, 查看是哪个包安装的确认该服务确实与业务无关后,先
stop,再disable,并考虑是否mask(彻底屏蔽启动)。
5.2 基线检查与修复常见问题排查
在实施过程中,你肯定会遇到各种“妖魔鬼怪”。这里记录几个我踩过的坑:
问题1:基线扫描工具(如Lynis)提示某项检查失败,但手动检查配置明明是对的。
- 原因:扫描工具可能基于某个特定版本或发行版的默认配置路径进行判断,而你的系统可能做了自定义。
- 排查:仔细阅读工具给出的详细报告,看它具体检查了哪个文件、哪行配置。用
grep、find命令确认你的实际配置文件和路径。有时需要调整工具的检查策略或忽略此项。
问题2:修复了SSH配置并重启后,自动化运维工具(如Ansible)连接失败。
- 原因:自动化工具可能配置的是密码认证,或者使用的密钥对权限、格式有问题。
- 排查:
- 检查Ansible主机清单(inventory)中该主机的连接变量,确认
ansible_ssh_private_key_file指向正确的密钥文件。 - 在目标服务器上,检查对应用户的
~/.ssh/authorized_keys文件权限(应为600),以及.ssh目录权限(应为700)。 - 在Ansible端,使用
-vvv参数运行一个简单命令(如ansible all -m ping -vvv),查看详细的SSH连接调试信息。
- 检查Ansible主机清单(inventory)中该主机的连接变量,确认
问题3:升级了OpenSSL以修复某个漏洞(如CVE-2016-2183),但依赖它的Nginx/PHP等服务启动报错。
- 原因:服务在编译时链接了旧版本的OpenSSL动态库,升级后库文件路径或符号链接可能发生了变化。
- 排查:
- 使用
ldd命令检查服务的二进制文件依赖了哪些库:lddwhich nginx``。 - 使用
strings命令查看二进制文件编译时链接的库路径:stringswhich nginx| grep openssl。 - 如果服务是通过包管理器安装的,尝试重新安装或升级该服务包,让它自动链接到新库:
sudo yum reinstall nginx。 - 如果服务是源码编译的,可能需要在源码目录中重新
./configure并make install一次。
- 使用
5.3 建立持续的安全基线运营体系
安全不是一次性的任务,而是一个持续的过程。你需要建立一个闭环:
- 制定基线标准文档:将你最终确定的安全配置(SSH参数、内核参数、服务清单等)写成文档,作为所有服务器的“安全宪法”。
- 自动化检查与报告:将前面提到的自动化脚本或工具(如Lynis)集成到CI/CD流水线中,或者通过Ansible/SaltStack等配置管理工具定期(如每周)在所有服务器上执行,并生成差异报告。
- 自动化修复(谨慎!):对于风险极高且修复动作简单的项(如某个文件权限不对),可以通过自动化工具进行修复。但对于可能影响服务的配置(如修改SSH端口),建议先人工审核报告,再手动或半自动操作。
- 定期审计与更新:每季度或每半年,回顾一次你的安全基线标准。随着系统版本升级、新漏洞出现、业务架构变化,基线也需要相应调整。
- 将安全左移:最理想的状态是,在服务器镜像模板(如Packer制作的AMI、Docker基础镜像)中就打好安全补丁、应用好安全基线配置。这样所有新启动的服务器从一开始就是安全的。
最后,我想说的是,安全基线检查这项工作,三分靠工具,七分靠经验和责任心。工具能帮你发现问题,但判断问题的优先级、设计修复方案、平衡安全与稳定,这些都需要你在实践中不断积累。从今天起,挑一台非核心的服务器,按照上面的步骤亲手操作一遍,你会对“服务器安全”有完全不一样的理解。真正的安全,就藏在这些看似枯燥的配置细节里。