Linux安全加固四步法:从系统层到自动化基线

发布时间:2026/8/26 12:42:37
Linux安全加固四步法:从系统层到自动化基线 算起来我做 Linux 运维和安全这块已经超过十年了从早期的 CentOS 6 一路折腾到现在的 Rocky Linux、Ubuntu 22.04 LTS中间过手的服务器没有一千也有八百。这些年最深的感受是Linux 安全并不是某个单一工具或者某条命令能解决的问题而是一整套需要持续迭代的工程实践。今天我想结合自己实际踩过的坑聊聊怎么用四步把一台 Linux 系统的安全水位拉起来并且长期维持住。这套方法我习惯叫它“纵深防御的四个支点”系统层加固、访问控制、主动监测、自动化基线。每一步单独拿出来都不复杂但串成体系之后效果是立竿见影的。尤其是团队里同时维护几十台甚至上百台服务器的时候没有这套流程安全根本无从谈起步步为营。下面我按照从基础到进阶的顺序把这四步完整拆开讲清楚。1. 系统层加固先把攻击面收窄到最小很多刚入行的朋友拿到一台新服务器第一件事就是赶紧装上业务环境然后急着把服务跑起来。这个顺序其实是有问题的。系统层加固应该发生在业务部署之前因为这时候系统还是干净的改配置、调参数都不会影响线上服务试错成本最低。1.1 内核更新策略与镜像选择第一步不是敲命令而是选对系统的起点。我强烈建议生产环境使用 LTSLong Term Support版本的内核和发行版而不是追最新的 kernel 主线。LTS 版本意味着你会获得长达五到十年的安全补丁支持这是生产系统最需要的确定性。以 Ubuntu 22.04 为例它的内核是 5.15 LTS官方会持续推送安全更新。你需要确保 apt 源配置正确并且养成定期更新的习惯。这里有个实操细节更新之前先看更新列表别闭着眼睛apt upgrade。我的习惯是先执行apt update apt list --upgradable然后逐条确认哪些是和内核、libc、openssl 相关的安全更新这类更新必须优先处理。至于内核更新后是否需要重启我的判断标准是如果uname -r显示的内核版本和apt list --installed | grep linux-image里最新版不一致并且你用了需要加载内核模块的服务比如 Docker、IPVS那就要尽快找维护窗口重启。实测下来很多线上事故不是更新导致的而是更新之后长期不重启导致用户态和内核态版本错配。还有一个容易忽略的点系统镜像的完整性。无论你是用云厂商的镜像还是自己下载 ISO装完系统后第一件事就是校验包管理器的签名状态。Debian/Ubuntu 系可以执行apt-key listRedHat/CentOS 系用rpm -qa gpg-pubkey确认没有任何未知来源的 GPG key。这个习惯能有效防止供应链投毒尤其是团队里有人喜欢从各种第三方源拉包的时候。1.2 用 sysctl 收紧内核参数内核参数是系统安全的底层地基很多人容易忽略。它不像防火墙规则那样直观但内核参数决定了系统在极端情况下的行为。我常用的几组参数分三类说第一类是网络层防护编辑/etc/sysctl.d/99-security.conf# 禁止 IP 转发除非你是路由器 net.ipv4.ip_forward 0 # 启用反向路径过滤防 IP 欺骗 net.ipv4.conf.all.rp_filter 1 net.ipv4.conf.default.rp_filter 1 # 忽略 ICMP 重定向 net.ipv4.conf.all.accept_redirects 0 net.ipv4.conf.all.send_redirects 0 # 启用 SYN cookies防 SYN Flood net.ipv4.tcp_syncookies 1第二类是资源限制防止单点故障拖垮整机# 限制每个进程能打开的 socket 数量防止文件描述符耗尽 net.core.somaxconn 1024 # 限制并发连接跟踪表大小 net.netfilter.nf_conntrack_max 65535第三类是内核崩溃时的行为策略# 内核 panic 后 10 秒自动重启避免长时间挂起 kernel.panic 10修改完参数后用sysctl -p /etc/sysctl.d/99-security.conf生效再用sysctl -a | grep net.ipv4.ip_forward验证。我的经验是内核参数每次只改一组、验证一组不要一次性堆十几条上去否则出了问题很难定位是哪条参数引起的。1.3 文件权限和关键目录保护系统装好后文件权限默认是安全的但总有一些操作会破坏默认权限。最常见的两个坑一个是把家目录设成了 777另一个是给脚本加了过多的执行权限。我一般会执行一轮批量检查# 找出所有全局可写的文件重点关注 find / -xdev -type f -perm -0002 -print # 找出所有带 SUID 位的文件这类是提权攻击的高发点 find / -xdev -type f -perm -4000 -printSUID 文件尤其要小心。很多老系统上你会发现/usr/bin/newgrp或者/usr/bin/mount这类程序带了 SUID 位如果业务用不到建议直接去掉chmod -s /usr/bin/newgrp另外/tmp目录必须是独立的挂载点并且加上nosuid,nodev,noexec挂载选项。编辑/etc/fstab# 在挂载参数里加上 nosuid,nodev,noexec tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec,mode1777 0 0这里说明一下noexec会让/tmp下的二进制文件无法直接执行能有效阻断一波常见的 webshell 攻击路径。但要注意有些软件比如某些版本的 Java 安装包依赖/tmp执行临时文件加了noexec之后会异常。如果遇到这种情况可以单独给这类软件指定java.io.tmpdir参数而不是把noexec去掉——这是我在生产环境踩过坑后的建议。2. 访问控制与权限隔离别让一个 root 走天下系统层加固做的是基本功真正决定安全上限的是访问控制。很多团队一台服务器上所有人都用 root这在我看来是比不装防火墙更可怕的事情。Linux 的权限模型设计得非常精细问题是你用没用到位。2.1 新建用户的正确姿势和 sudo 精细化合理的方式是给每个运维人员单独建账号然后用 sudo 做提权授权。新建用户看起来简单但里面有细节useradd -m -s /bin/bash ops01 passwd ops01这里有两个细节容易被忽略。第一-m参数会自动创建家目录并复制/etc/skel下的初始文件。如果你希望新用户默认带上安全配置比如受限的 umask可以修改/etc/skel/.bashrc。第二shell 一定要指定别用/usr/sbin/nologin之外的东西给服务账号但人工运维账号必须用/bin/bash这类交互 shell。sudo 的精细化授权是重头戏。直接在/etc/sudoers里写规则或者更推荐在/etc/sudoers.d/下创建独立文件# /etc/sudoers.d/ops01 ops01 ALL(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx这条规则的意思是用户ops01只能在所有主机上以 root 身份执行 systemctl restart nginx 和 systemctl reload nginx 这两个命令。这样既满足了日常操作需求又限制了误操作风险。我见过太多人写ops01 ALL(ALL) ALL等于把整个系统交给了一个可能犯错的人。sudo 的精髓是“最小授权够用就好”。还有一个我特别推荐的参数是timestamp_timeout它决定了 sudo 密码缓存的时长。默认是 5 分钟如果你用的是共用工作站建议调成 0每次 sudo 都输密码Defaults timestamp_timeout02.2 SSH 访问管理从密钥到配置全面收紧SSH 是 Linux 服务器最常见的入口也是被扫描攻击最多的服务。我把 SSH 加固核心归成四段第一段使用密钥认证并关闭密码登录# 编辑 /etc/ssh/sshd_config PasswordAuthentication no PubkeyAuthentication yes PermitRootLogin no第二段限制可登录用户减小攻击面AllowUsers ops01 ops02这段配置的意思很直接除了名单里的人其他账号哪怕有有效密钥也登不进来。配合Match User可以做到更细粒度的控制比如限制某些用户只能从特定 IP 登录。第三段开启 SSH 会话超时防止终端挂着被滥用ClientAliveInterval 300 ClientAliveCountMax 0第四段SSH 协议和加密算法只保留强项Protocol 2 KexAlgorithms curve25519-sha256,diffie-hellman-group-exchange-sha256 Ciphers chacha20-poly1305openssh.com,aes256-gcmopenssh.com MACs hmac-sha2-512,hmac-sha2-256每次改完sshd_config都要先执行sshd -t验证语法再systemctl reload sshd平滑加载。千万别直接 restart否则如果配置写错你会发现自己被拒之门外——这个教训我印象太深刻了。为了保险起见我还会顺手跑一句ssh -t userlocalhost在本机测试一遍登录流程再退出确保万无一失。建议每次修改前先备份cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date %F)操作失误时能秒回滚。2.3 SELinux 和 AppArmor给进程戴上枷锁Linux 传统的权限模型是 DAC自主访问控制意思是文件所有者可以随意设置权限。但 DAC 挡不住一个场景web 服务被入侵后攻击者能访问 web 进程能访问的一切文件包括数据库配置文件。这时候需要 MAC强制访问控制出马SELinux 和 AppArmor 就是干这件事的。CentOS/RHEL/Rocky 系默认装 SELinuxUbuntu/Debian 系默认装 AppArmor。很多人的第一反应是“太麻烦了关掉它”我劝你千万别。SELinux 的价值在于即使进程被攻破它能做的是“把破坏范围锁在进程自己的笼子里”。SELinux 有三个模式Enforcing强制、Permissive宽容、Disabled禁用。我建议从 Permissive 模式开始先跑一段时间看审计日志# 临时切到 Permissive setenforce 0 # 查看被拒的日志确认哪些规则需要放行 ausearch -m avc -ts recent确认规则没问题后再切回 Enforcingsetenforce 1这里给 Ubuntu 用户一个对应参考AppArmor 的常用操作是aa-status查看状态、aa-enforce /path/to/profile强制加载、aa-complain /path/to/profile进入宽容模式。核心思路和 SELinux 一模一样先观察后强制。说实话SELinux 的政策编写对新手确实有学习曲线。但即便你不想深写策略至少别把它关掉保持 Enforcing 模式跑默认策略就能挡住大部分越权访问。我自己维护的 Nginx 服务器上就用默认 policy 拦截过一次 php-fpm 进程尝试读/etc/shadow的行为——如果没有 SELinux那台机器早就沦陷了。3. 运行时监测与主动防御看不见的攻击才是真正的威胁加固做得再好也只能降低被攻破的概率。做安全的人必须认同一个前提系统随时可能被攻破。所以运行时监测不是可选项而是必需品。你要能第一时间发现谁在扫我的端口谁在暴力破解 SSH谁在系统里留下了不该有的文件。3.1 用 auditd 记录关键行为Linux 原生的审计框架 auditd 是排查入侵路径的利器。它的原理是内核里挂了个钩子把指定的系统调用、文件访问、用户行为记录下来。我强烈建议至少审计这几类# 记录所有 root 执行的命令 -a always,exit -F archb64 -F euid0 -S execve -k root_cmd # 记录 /etc/passwd、/etc/shadow 的访问 -w /etc/passwd -p wa -k passwd_watch -w /etc/shadow -p wa -k shadow_watch # 记录 /etc/sudoers 的修改 -w /etc/sudoers -p wa -k sudoers_watch # 记录 SSH 配置修改 -w /etc/ssh/sshd_config -p wa -k sshd_watch规则写在/etc/audit/rules.d/audit.rules里修改后重启 auditd 服务或执行augenrules --load加载。查看审计日志ausearch -k passwd_watch -ts recentauditd 日志在/var/log/audit/audit.log文件可能会涨得很快建议配置 logrotate 轮转策略。另外我个人的习惯是每天快速扫一眼ausearch -m USER_CMD -ts today | tail -50看看今天有没有不正常的 root 命令执行记录。这一步花不了两分钟但关键时刻能救命。3.2 fail2ban 挡住暴力破解暴力破解 SSH 是最常见的攻击也是最好防的。fail2ban 的原理很简单monitor 日志文件发现某个 IP 在固定时间内失败次数超过阈值就调用防火墙把这个 IP 拉黑一段时间。安装和配置apt install fail2ban # 或者 yum install fail2ban然后编辑/etc/fail2ban/jail.local[DEFAULT] bantime 3600 findtime 600 maxretry 5 [sshd] enabled true port ssh logpath /var/log/auth.log maxretry 3这个配置的意思是10 分钟内同一个 IP 失败 3 次拉黑 1 小时。你在生产环境里会立刻看到效果——之前 sshd 日志里那些来自全世界的扫描尝试会瞬间安静下来。fail2ban 对 Nginx 的密码爆破同样有效配置一个[nginx-http-auth]的 jail 就能搞定。实测下来有个小技巧bantime 不建议设置太长。太长了容易误伤正常用户比如管理员出差换了 IP太短了又没有意义。1 小时是个折中的选择。如果某个 IP 反复被 ban那就说明有人在定向攻击你应该直接写进防火墙黑名单而不是靠 fail2ban 一次次拉黑。3.3 日志集中管理和入侵痕迹排查单机日志的价值有限因为攻击者最擅长的就是清理日志。我强烈建议条件允许的话用 rsyslog 或者 Logstash 把日志实时转发到集中的日志服务器。配置 rsyslog 客户端转发# /etc/rsyslog.d/50-remote.conf *.* 192.168.1.100:514这样即使本地日志被删远端还有一份。这个习惯帮我追查过好几次真实事故——一台机器被人把/var/log整个删掉了但日志服务器上还留着完整的记录一下子就能定位到攻击时间点和手法。日常排查入侵痕迹时我习惯按这个清单来# 1. 检查近期登录记录 last -n 30 lastb -n 30 # 2. 检查有没有新增账号 awk -F: $30 {print $1} /etc/passwd # 3. 检查 Plan 任务 crontab -l ls -la /etc/cron.d/ /var/spool/cron/ # 4. 检查异常监听端口 netstat -tunlp # 5. 检查最近修改的文件 find / -xdev -mtime -3 -type f -not -path /proc/* -not -path /sys/* 2/dev/null这套排查思路的核心是攻击者总会留下痕迹区别在于你会不会找。哪怕只是定期跑一遍也能形成对系统正常状态的敏感度出了异常你马上能感觉到。3.4 用 Lynis 做自检定期体检上面说的都是被动监测更主动的做法是定期跑一遍安全审计工具。Lynis 是我目前用过最顺手的 Linux 安全审计工具一条命令就能对系统做全面体检覆盖文件权限、内核配置、软件更新、网络设置等 200 多项检查。apt install lynis # 或者 git clone https://github.com/CISOfy/lynis cd lynis ./lynis audit system跑完之后重点看末尾的“Hardening Index”分数和“Suggestions”列表。Lynis 会给出每一条整改建议及对应的风险等级你只需要按优先级逐一处理即可。我一般会设一个每月跑一次的定时任务把它当作家常便饭。有一个容易踩的坑Lynis 查出的有些建议并不适合所有场景。比如它可能建议你禁用某个内核模块但如果你的业务恰好依赖那个模块就不能盲目执行。安全工具的价值是帮你发现问题但最终改不改、怎么改还是要基于业务判断。这个判断力只能靠对系统的深入了解来积累工具替代不了。4. 自动化基线、CVE 管理与持续加固让安全成为体系而不是偶然前三步解决的是“一台机器怎么防”但现实中的运维一定面对的是几十台、上百台机器。如果每台都要人工重复配置和巡检既浪费人力又容易遗漏。第四步的核心是把安全从手工操作变成体系化的流程让每台新机器上线时自动继承安全基线。4.1 用 Ansible 固化安全基线我对配置管理工具的定义是把安全策略变成代码让每台机器都长成同样的安全模样。Ansible 是我最常用的因为它是无代理架构走 SSH 就能批量操作上手门槛很低。下面这份 playbook 体现了 Ansible 在安全基线管理中的核心思路只需要告诉 Ansible “我要什么状态”它就会自动把每台机器的配置修正到目标状态。我通常在组网里建一个security_baseline.yml内容包含用户账号、sudo 规则、SSH 配置、sysctl 参数等--- - name: Apply security baseline to Linux servers hosts: all become: yes tasks: - name: Create deployment user user: name: ops01 groups: sudo shell: /bin/bash append: yes - name: Set up SSH key authorized_key: user: ops01 key: {{ lookup(file, files/ops01.pub) }} - name: Disable password authentication lineinfile: path: /etc/ssh/sshd_config regexp: ^#?PasswordAuthentication line: PasswordAuthentication no notify: restart sshd - name: Ensure sysctl settings sysctl: name: {{ item.name }} value: {{ item.value }} state: present loop: - { name: net.ipv4.ip_forward, value: 0 } - { name: net.ipv4.tcp_syncookies, value: 1 } handlers: - name: restart sshd systemd: name: sshd state: restarted这样做的好处是新机器加入 Ansible 管理后自动被拉齐到安全基线的状态。只要基线覆盖到位就不会出现“这台机器漏改了 SSH 配置”的情况。我把这套 playbook 放在 Git 里管理每次修改都是有记录的回滚也方便。4.2 CVE 漏洞扫描和补丁管理节奏安装一个 CVE 扫描工具能让安全水位更进一步。工具不是越贵越好关键是要用起来。我推荐两个方向如果你用 Ubuntu/Debian可以直接用自带的ubuntu-advantage-tools查看 ESM 安全补丁如果你用云主机云厂商自带的安全中心也算一个选择。不管用哪种核心是每天自动获取补丁信息看到有 CVE 修复就及时评估。补丁管理的节奏我总结了一个经验值紧急安全补丁比如 OpenSSL 的严重 RCE24 小时内处理中危补丁设置每周一次的统一维护窗口不影响业务的小补丁随月度维护一起更新。这个节奏最平衡既能快速止血又不至于被补丁搞得天天重启服务。自动化补丁更新可以用unattended-upgradesUbuntu或者yum-cronCentOS。我建议安全更新开启自动普通更新保持手工确认。apt install unattended-upgrades dpkg-reconfigure unattended-upgrades注意一个细节装了 Docker 的场景下尤其要留意。Docker 容器内部的包管理器和宿主机的系统更新是分离的OS 层面的补丁更新解决不了容器镜像里的 CVE。需要额外用 Trivy 一类的镜像扫描工具对镜像仓库做定期扫描。否则你会发现系统打了补丁但业务漏洞依然存在。4.3 定期做一次自我渗透测试前面几步做完系统安全状态应该已经不错了。但我建议每个季度至少做一次“自我渗透测试”扮演攻击者的角色去攻击自己的系统。这是最接近实战的检验能发现很多配置层面的盲区。我的最低限度检测清单包括这几项# 1. 端口扫描确认只暴露了必要端口 nmap -sS -sV -p- your-server-ip # 2. 用 hydra 模拟 SSH 密码爆破测 fail2ban 是否真的生效 hydra -l root -P rockyou.txt ssh://your-server-ip # 3. 检查 Web 服务的响应头和加密套件 nmap --script ssl-enum-ciphers -p 443 your-server-ip实测中我发现很多系统 fail2ban 配了但没生效原因大多是日志路径不对或者 jail 没启用。自我渗透测试能立刻发现这类问题。另一个容易被忽略的检查点是公网服务是否被防火墙限制在特定 IP 段例如管理后台只允许公司出口 IP 访问。这个用防火墙规则即可实现在云安全组上配置更直观# 云安全组配置示例 # 只允许 203.0.113.0/24 访问 22 端口 允许 TCP 22 来源 203.0.113.0/24 允许 TCP 443 来源 0.0.0.0/0安全组的规则组合是另一门学问但核心理念简单默认拒绝、最小放行。任何服务都不应该随意对所有公网 IP 开放。4.4 人员习惯与变更流程的配套技术手段只能解决一部分问题。我见过的安全事件里有相当比例不是技术漏洞而是人员疏忽——比如有人把服务器的 root 密码贴在工位上或者把有生产库权限的账号密码写进公开的 Git 仓库。所以安全体系里必须包含流程层面的约束密码策略至少 12 位、大小写字母数字特殊字符每 90 天轮换一次账号生命周期员工离职当天必须禁用其账号而不是等 HR 通知变更审批对生产服务器的任何配置变更必须有审批记录有回滚方案日志审计每周由专人轮值检查 sudo 日志和审计日志不留空窗这些规则听起来很基础但真正的挑战在于长期坚持。我的经验是把这些流程写进团队 wiki每次迎新培训专门过一遍让安全意识从入职第一天就建立起来。5. 实操中的记忆点三张速查表四步内容比较多为了方便大家落地我最后整理了三张速查表分别覆盖配置项速查、文件路径速查和日常命令速查。这三张表是我每次搭新机器时都会对照的备忘录你也可以打印出来贴工位上。5.1 安全配置项速查表配置类别推荐配置检查命令内核更新使用 LTS 版本启用自动安全更新uname -rSSH 密码登录关闭sshd -T | grep passwordauthenticationroot 远程登录关闭sshd -T | grep permitrootlogin防火墙策略默认拒绝最小放行iptables -L -n用户 sudo最小化授权cat /etc/sudoers.d/*SELinux/AppArmor保持 Enforcing/enforcegetenforce/aa-status内核参数启用手工配置sysctl -a | grep net.ipv4.tcp_syncookies密码策略12 位以上定期轮换cat /etc/pam.d/common-password审计规则覆盖 passwd、shadow、sudoersauditctl -l登录失败锁定fail2ban 启用fail2ban-client status sshd5.2 关键文件与日志路径速查路径用途备注/etc/ssh/sshd_configSSH 服务端配置每次修改前备份/etc/sudoers.d/sudo 规则目录必须用 visudo 校验/etc/sysctl.d/内核参数目录优先于/etc/sysctl.conf/etc/audit/rules.d/auditd 规则目录修改后需加载/etc/fail2ban/jail.localfail2ban 配置覆盖 jail.conf 默认值/var/log/audit/audit.log审计日志建议做集中备份/var/log/auth.log认证日志SSH 登录记录/var/log/secure安全日志RHEL 系对应 auth.log/etc/fstab挂载配置检查 noexec 等选项/etc/pam.d/PAM 认证配置修改前务必备份5.3 日常安全巡检命令速查场景命令预期结果确认系统更新状态apt list --upgradable或yum check-update无高危安全更新查看当前登录用户who只有预期运维人员在登录查看登录失败记录sudo lastb -n 20无明显暴力破解痕迹检查监听端口ss -tlnp只有必要服务端口开启检查系统负载uptime负载在合理范围检查磁盘空间df -h关键分区未满检查最近 24 小时审计事件ausearch -ts today无异常操作记录查看可疑进程ps -ef --sort-%cpu | head -20CPU 占用无异常检查新用户账号awk -F: $30查看授权密钥cat ~/.ssh/authorized_keys无陌生公钥6. 最后的经验分享这套四步方法论最初是我给自己维护的那批服务器设计的后来在团队里推广又根据不同业务场景迭代了很多次。如果你只记住一个核心思想我希望是安全不是某个时间点的状态而是一个持续的过程。同样的系统今天安全不等于明天安全新的 CVE、新的攻击手法、新入职的同事每一个变量都可能打破原有的平衡。在实际执行中我个人的体会是二八法则在安全领域体现得特别明显。上面写的这些步骤里最朴素但也最有效的其实是三个保持系统更新、SSH 用密钥禁密码、开启强制访问控制。这三件事能挡住绝大多数自动化攻击。剩下的技术手段更多是为了应对更有耐心的定向攻击者。还有一个常被忽略的建议是每次做安全加固的时候都要想清楚“如果这条规则误伤了业务怎么办”。安全和业务永远在博弈最好的状态是二者达到动态平衡。所以在改任何配置之前我的习惯是先读一遍日志了解业务真实的资源使用和访问模式再动手。尊重业务的稳定性安全加固才能真正落地而不是被业务部门当成“又来找麻烦的”。如果你正准备加固自己的 Linux 服务器我建议从今天开始按这四个方向逐一推进。不用追求一步到位哪怕本周只完成了 SSH 加固、下周开始配置 fail2ban都是在往前走。安全这条路没有终点但每走一步系统都会比昨天更难以攻破。这句话既是说给你听的也是说给所有在持续加固路上坚持的运维人听的。