做Linux运维这些年,系统安全加固这件事一直有种奇怪的地位:嘴上都说重要,实际动手的人却没几个。很多服务器装完系统直接丢进生产,SSH还开着默认22端口,root密码照常远程登录,防火墙干脆没配或者全是放行规则。表面上看业务跑得挺顺,实际上只要暴露在公网两三天,日志里就能看到大量扫描和爆破记录。这篇文章我不打算讲那些虚的合规框架,直接整理我在实际环境里落地过的15个Linux系统安全加固关键配置,从登录认证、服务收敛、内核参数到日志审计,基本覆盖日常运维里能立刻用上的做法。
1. 安全加固的整体思路与配置清单速览
1.1 为什么安全加固总被拖到“以后再说”
搞运维的人多少都遇到过这种情况:讨论加固方案时大家拍手赞成,一说到要改配置、重启服务,就开始犹豫,怕影响业务、怕把自己关在门外、怕领导觉得小题大做。这里有一个容易被忽略的点:安全加固本质上不是装一堆安全软件,而是减少攻击面、提升攻击成本、保留攻击痕迹。真正被入侵的服务器,绝大多数问题出在最初级的地方,比如弱口令、未授权账户、不必要的服务对外开放。相比之下,很多厂商吹得天花乱坠的“下一代防护”反而不是第一道防线。
我接手过不少被攻陷的服务器,排查到最后,十有八九都是因为基础配置没做。有一个案例特别典型:一台内网测试机,上了外网之后,SSH端口是默认的22,用的是简单密码,结果不到半天就被扫描器盯上,密码被爆破,然后被拿去挖矿。其实只需要改个端口、禁掉root远程登录,就能挡住绝大部分自动化攻击。这就是我坚持推荐把这套基础配置先做扎实的原因。它不能防住顶级黑客,但能挡住99%的脚本扫描和暴力破解。
1.2 15个关键配置速查表
先给一张总览表,把15项配置串起来。方便大家对照检查,后续章节会挑重点展开。
| 序号 | 配置项 | 作用 | 推荐动作 |
|---|---|---|---|
| 1 | SSH端口修改 | 降低自动化扫描命中率 | 改为非默认端口 |
| 2 | SSH密钥认证 | 替代弱密码认证 | 禁用密码登录 |
| 3 | 禁用root远程登录 | 防止root口令被爆破 | PermitRootLogin no |
| 4 | 用户账户清理 | 减少无效入口 | 锁定/删除无用账户 |
| 5 | 密码复杂度与失败锁定 | 提升口令抗爆破能力 | 配置PAM pwquality和faillock |
| 6 | sudo权限收敛 | 防止提权和横向扩展 | 最小授权,限制命令集合 |
| 7 | 防火墙默认拒绝 | 收敛对外暴露端口 | 仅放行业务必需端口 |
| 8 | 关闭无用服务 | 减少远程攻击面 | 停用并禁用非必要服务 |
| 9 | 内核参数sysctl加固 | 缓解网络层攻击 | 开启syncookies、禁重定向等 |
| 10 | 文件权限收紧 | 保护敏感配置和密码文件 | 严格设置shadow、SUID排查 |
| 11 | SELinux/AppArmor | 限制进程越权访问 | 保持enforcing或合理策略 |
| 12 | 系统更新与补丁 | 修复已知漏洞 | 配置自动安全更新 |
| 13 | 日志持久化与轮转 | 保证审计证据不丢 | journald配置+logrotate |
| 14 | auditd与文件完整性 | 发现关键文件篡改 | 监控passwd等文件变化 |
| 15 | 内核模块与虚拟化加固 | 抵御高级rootkit | 签名校验、kvm机安全配置 |
这个表看起来内容不少,但每一项其实都不复杂。后面我会针对账号登录、服务网络、内核文件、日志审计这几个模块,把关键操作和容易踩的坑讲清楚。你在实际操作时可以按这个顺序一项项过,不用一次全改完,先从最外层的SSH和防火墙下手,效果立竿见影。
2. 账号与登录安全:门槛首先要焊牢
2.1 SSH远程登录加固实操
SSH是每台Linux服务器运维的生命线,也是最常见的攻击入口。网上99%的爆破都是针对22端口来的,所以我的习惯是上来就做三件事:改SSH监听端口、禁用root远程登录、启用密钥认证。配置文件在/etc/ssh/sshd_config,建议修改之前先备份一下原文件,养成习惯,后面能省不少事。
改监听端口很简单,找到#Port 22,改成比如Port 22522。端口范围尽量避开常用端口,也不要太冷门,免得自己都记不住。然后设置PermitRootLogin no、PasswordAuthentication no,保存前先用sshd -t检查语法。这里最关键的坑是:如果你还没把公钥放到服务器上就直接禁用密码登录,那等于亲手把自己锁在门外。所以正确顺序是先在客户端生成密钥对,用 ssh-copy-id 把公钥传到服务器,确认能密钥登录后,再动手禁用密码。
生成密钥的命令很简单:
ssh-keygen -t ed25519 -C "your_comment" ssh-copy-id -p 22 user@server_ip然后修改sshd_config。如果服务器启用了SELinux,修改了非标准端口后有可能会被SELinux拦截连接,需要执行semanage port -a -t ssh_port_t -p tcp 22522。这个问题很多人忽略,症状表现就是端口通、客户端超时。
建议在改动后不要第一时间关闭当前SSH会话,而是新开一个终端窗口测试登录,确认没问题再退出,这是避免“手滑把自己锁外面”的基本操作。如果用的是云服务器,还要记得在云平台的安全组规则里放行新端口,否则配置全对也连不上。
2.2 用户口令策略与sudo权限收敛
除了SSH,系统本身的账户策略也很重要。默认情况下很多发行版对密码复杂度要求很低,用户随手设一个123456都能通过。在CentOS/RHEL上一般通过PAM配置,编辑/etc/security/pwquality.conf,可以设置minlen = 14、minclass = 3,要求密码最少14位且包含三类以上字符。同时开启登录失败锁定,创建或调整/etc/security/faillock.conf,设置deny = 5、unlock_time = 900,这样连续输错5次就锁定15分钟,能有效拖慢暴力破解。
还需要清理系统里的无效账户。用awk -F: '$3==0{print $1}' /etc/passwd查看uid=0的账户,正常情况下只有root一个;用cat /etc/shadow | awk -F: '($2==""){print $1}'检查是否有空密码账户,发现异常账户通过usermod -L或userdel处理。另外,很多系统默认开着ftp、mail这类用户,虽然不是直接风险,但最好锁定shell,比如usermod -s /sbin/nologin。
sudo权限收敛是另一个容易忽视的点。有些团队图省事,直接给运维账户加了NOPASSWD: ALL,一旦这个账户被攻破,攻击者就直接拿到root。我的做法是通过/etc/sudoers.d/下新建规则文件,而不是直接修改sudoers主文件,比如只允许某个用户执行systemctl和指定脚本:
Cmnd_Alias ADMIN_CMDS = /usr/bin/systemctl, /usr/local/bin/deploy.sh user1 ALL=(ALL) NOPASSWD: ADMIN_CMDS这样既满足了日常操作,又限制了提权范围。修改后记得用visudo -c校验语法,避免因为语法错误导致sudo不可用。
3. 服务、网络与内核参数的收紧
3.1 最小化服务与网络端口管理
Linux系统装完默认会启动很多用不上的服务,比如postfix、cups、avahi-daemon这些,它们都属于非必要攻击面。生产环境下我强烈建议走最小化方案:安装系统时能少选包就少选包,已经装了的机器就用systemctl list-unit-files --type=service --state=enabled查看开机启动的服务列表,一项项确认哪些是业务必须的,其余全部systemctl disable --now 服务名。
检查端口可以用ss -tulnp,重点看Listen的端口对应哪个进程。有一次我在一台服务器上发现有一个奇怪的进程监听高端口,一查是被人塞了挖矿木马,就是因为在初始安装时没有收敛服务,给了攻击者横向移动的落脚点。防火墙策略应当默认拒绝,只放行业务端口。使用firewalld时,我一般先把默认zone设置为drop,再添加需要放行的端口:
firewall-cmd --set-default-zone=drop firewall-cmd --permanent --zone=drop --add-port=22522/tcp firewall-cmd --permanent --zone=drop --add-service=http firewall-cmd --reload注意顺序很重要,先设置默认拒绝,再放行必要端口,避免漏放把自己锁在门外。如果是老系统用的iptables,同样建议在INPUT链最后加一条DROP,并确保规则保存,否则重启就没了。如果你在宿主机上跑KVM,还需要额外关注虚拟机网络:尽量把虚拟机网桥和宿主机管理网络隔离开,不要在网桥上直接放行所有流量,避免虚拟机被攻破后直接横向打到宿主机。
3.2 内核参数sysctl加固:小参数解决大问题
网络层攻击一直是运维头疼的问题,合理配置sysctl内核参数可以缓解很多问题。编辑/etc/sysctl.conf,常见的加固项包括:
net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.all.log_martians = 1tcp_syncookies开启后能有效缓解SYN Flood攻击;rp_filter开启反向路径过滤,防止IP欺骗;关闭ICMP重定向可以防止路由表被篡改。改完后sysctl -p生效。在修改前先备份原文件,并且不要在远程会话里直接sysctl -w测试可能引起网络断开的项目,比如ip_forward,如果这台机器不做NAT或容器转发,通常建议保持net.ipv4.ip_forward = 0;但如果你跑Docker或KVM虚拟机,把它关掉会导致网络不通,需要根据实际用途权衡。
内核安全上还有一个容易被忽略的方向:透明加密和文件层拦截。像某些安全软件会用内核模块挂钩file_operations的 read/write 来实现透明加密或防篡改,但这类技术也可能被恶意rootkit滥用。管理层最好要求所有内核模块必须有签名验证,启用UEFI Secure Boot,这样即使攻击者拿到root权限,也无法轻易加载未签名的恶意模块。检查已加载模块可以用lsmod,发现异常模块时先modinfo查看路径,不要在生产环境乱rmmod,容易搞崩系统。
3.3 文件权限、SUID与敏感目录防护
文件权限加固是很多新手最容易忽略的。/etc/shadow这个文件里存着所有用户的密码哈希,权限应该是----------或者0400,只有root和特定系统进程能读取。不放心的话可以执行ls -l /etc/shadow确认一下。如果发现是644,多半是安装某些软件时被改过,立即恢复。还有一个经典风险是SUID文件,这类文件运行时会临时获得属主权限,一旦有漏洞,攻击者就可能利用它提权。排查命令是find / -perm -4000 -type f 2>/dev/null,重点关注非系统自带的二进制文件,比如新建的奇怪脚本。
对于/tmp、/var/tmp这类可写目录,我建议挂载时加上noexec,nosuid,nodev选项,防止攻击者把恶意二进制丢进去执行。如果系统使用systemd,用systemctl status tmp.mount查看挂载参数,不满足可以在/etc/systemd/system/tmp.mount.d/下添加override配置。需要注意:有些软件安装包依赖/tmp可执行文件,改完如果发现安装失败,需要单独调整,不要一刀切导致业务异常。
4. 日志审计与完整性监控
4.1 让日志“存得住、装得下”
日志是安全事件发生后我们还原攻击路径最重要的依据,但很多人要么没开持久化,要么没做轮转,导致日志被写满磁盘。systemd环境下的journald默认日志可能放在内存或journal目录,重启后有可能丢失。建议修改/etc/systemd/journald.conf:
Storage=persistent SystemMaxUse=500M MaxRetentionSec=1month改完systemctl restart systemd-journald。这样日志会持久化到/var/log/journal,并且限制最多500M不至于占满根分区。传统的Rsyslog日志也一样,编辑/etc/logrotate.d/syslog或者自定义轮转规则,按天或按大小切割,保留最近4周,定期执行。我的一个习惯是把安全日志同步到远程日志服务器,即使本机被清理,也有副本可以审计。
4.2 auditd、AIDE与Rootkit自查组合拳
auditd是Linux自带的审计框架,可以把关键文件变更、命令执行记录到日志。配置位于/etc/audit/rules.d/audit.rules,比如监控passwd、shadow、sshd_config:
-w /etc/passwd -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/ssh/sshd_config -p wa -k sshd_conf生效后,当这些文件被修改时,ausearch -k identity就能查到谁在什么时候动过。AIDE是文件完整性检查工具,首次用aide --init生成数据库,之后定期运行aide --check,有差异会输出检查报告。这个工具对发现被篡改的二进制很管用,特别是系统命令被替换成后门的情况。
除了文件监控,还要定期跑一下Rootkit自查,rkhunter、chkrootkit都是老牌工具。它们通过比对系统命令或检测已知rootkit特征,虽然不能穷尽所有威胁,但作为低成本巡检足够。建议配合cron每周执行一次,结果输出到日志文件。这个环节最容易出现的问题就是误报,尤其是一些内核模块或系统更新后,工具会把新模块标记为“可疑”,所以看到报告别慌,先看路径和性质,再决定是否处理。
5. 加固后常见故障与排查技巧
5.1 改完SSH配置把自己锁外面了怎么办
这个场景我敢说几乎每个运维都遇到过:改完sshd_config,保存,重启sshd,然后当前连接断掉,怎么都连不上了。原因无外乎几种:PermitRootLogin和PasswordAuthentication同时禁掉了,但密钥没配好;防火墙新端口没放行;SELinux拦截了新端口;sshd配置文件语法错误导致服务启动失败。
恢复的办法主要靠“带外通道”。云服务器一般在控制台提供VNC/管理终端,直接通过虚拟终端登录;物理服务器如果接在本地,用显示器键盘登录;实在不行还可以通过iDRC/IPMI这类带外管理。登录后先把sshd_config改回安全值,或者先临时开一个防火墙规则。这里我想强调:改动前务必先cp备份配置文件,并且保留一个已登录的会话不要退出,用于救急。测试配置可以用sshd -T验证,比直接重启稳妥得多。
5.2 firewalld和安全加固导致业务访问异常
加固后业务突然连不上,这类故障排查是有套路的。先看服务进程是否正常,再看监听端口,然后看防火墙规则和SELinux日志。如果端口明明listen,外部就是访问不了,大概率是firewalld默认zone是drop,而新业务端口没加白名单。通过firewall-cmd --list-all --zone=drop查看,缺什么补什么。
SELinux导致的异常更隐蔽。CentOS 7以后默认是enforcing,如果某个服务改过监听端口或者换了数据目录,SELinux策略会拦掉它,表现就是网络通、连接被拒或者文件打不开。排查命令是ausearch -m avc -ts recent,看有没有SELinux拒绝记录。临时验证可以用setenforce 0,如果问题消失,基本可以确定是SELinux策略问题,这时要么找对应类型的布尔值修改,要么让服务文件放在标准目录下。不要急着把SELinux整个关掉,保持enforcing并学会调整策略,才能在安全性和可用性之间找到平衡。
5.3 批量加固落地的经验
单台服务器手动改还好,几十台一起加固就需要脚本和自动化工具了。Ansible是我常用的方式,比如通过lineinfile模块修改sshd_config,通过copy模块分发配置,再统一systemctl restart。写自动化脚本时最重要的一点是幂等性:同一个脚本跑两次结果必须一致,不能让重启服务这类操作重复执行。加保护条件,比如只有当配置文件内容和预期不一致时才触发重启:
- name: update sshd config ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?PermitRootLogin' line: 'PermitRootLogin no' notify: reload sshd然后定义handlers,在变更时才reload sshd。批量操作之前一定要先在测试机灰度跑一遍,确认不会影响业务再推全量。每次加固都要先在变更窗口内做快照或备份,加固完成后还要验证业务端口、数据库连接、定时任务是不是都正常。安全加固不是一锤子买卖,把配置和检查流程固化到日常运维周期里,才真正有意义。
踩过几次坑之后我的体会是,改动越基础,越要留退路。尤其是SSH、防火墙、SELinux这三大件,要么就别动,要么就保证自己能随时通过带外方式回到机器上。我在很多项目里都给运维团队立过一条规矩:任何加固操作必须保留变更前的完整备份,并且预设回滚方案,否则不允许在生产环境执行。如果你正准备给自己的服务器做第一轮加固,建议从最外层的SSH和防火墙开始,效果立竿见影,再慢慢深入文件权限、内核参数和审计这些层面,逐步形成一套适合自己环境的加固基线。