1. 先把话说在前面:为什么安全加固比你想的更迫切
做了这么多年服务器运维,我有个特别深的感受:很多人对Linux的印象是“开源、稳定、安全”,觉得病毒少、黑客少,装上就能跑,跑起来就不用管。这个想法在十年前也许还能勉强成立,现在再看,纯属侥幸。
说个我自己的经历。早些年接手某公司的一批业务服务器,接手时第一件事就是登录上去看了一眼现状。那批机器跑的是最普通的发行版,装好系统之后基本没做过任何调整,root密码是弱口令,SSH开着密码登录,防火墙没配规则,一堆用不上的服务启动着,日志也没人看。我看着那批机器心里直发毛。后来果然有一台被爆破进去了,挖矿程序占了CPU,业务直接卡死。那次事故之后我才真正意识到,Linux系统安全加固不是可做可不做的加分项,而是每一台机器上线的必答题。
这篇文章聊的核心就是Linux系统安全加固的五大关键策略:账户与认证、权限体系、网络层防护、日志审计、补丁与基线。你不需要是安全专家,只要按着这个框架把每一条落到实处,就能把绝大多数常见的入侵路径堵死。文章里所有内容都是我在实际运维中验证过的,该给命令给命令,该讲原因讲原因。
我不打算写那种看起来很高大上、实际却落不了地的理论。每个策略背后我会讲清楚“为什么这么做”“怎么做”“踩过哪些坑”,你照着操作,至少能把安全水平从“裸奔”拉到“及格线以上”。
适合谁来参考呢?刚入门的小白也好,管着几台到几百台机器的运维也好,甚至只是自己有一台云服务器、想让它更结实一点的同学,这篇文章都可以直接拿来用。看完之后,你至少能对自己的机器多几分把握,知道哪些是最要紧的、哪些可以往后排。
2. 账户与认证:把好第一道门
很多人做安全加固,第一反应是去搞防火墙、搞入侵检测,这没错,但顺序不对。你要先想想,别人想进你这台机器,最常用的路子是什么?不是绕过防火墙,而是直接用合法的身份登录进来。所以账户和认证,才是第一道、也是最关键的一道门。
2.1 清理账户:先看看你家里有几把钥匙
我接手任何一台新机器,干的第一件事永远是查看系统里有哪些用户。Linux系统本身有一些内置账户,那是系统运行需要的,不能乱动,但问题是很多机器上还残留着一些不该存在的账户。比如某个离职同事的账号没删、某次测试创建的临时用户还留在那儿,甚至有些恶意软件会自己创建一个带sudo权限的后门账户。
查看用户列表最简单的方式就是读/etc/passwd。你要关注的是那些uid在1000以下、带有可登录shell的用户。正常的系统进程账号我们不管,但如果你看到一个莫名其妙、从没创建过的用户带着/bin/bash或/bin/sh,那就得警惕了,这几乎可以断定是有问题的。
清理账户的命令不难:
# 查看所有可以登录的用户 awk -F: '$7 ~ /(bash|sh)$/ {print $1}' /etc/passwd # 锁定不用的账户 usermod -L username # 彻底删除不需要的账户 userdel -r username我不太建议你上来就删,先锁定比较稳妥。万一这个账户还有用,你把它删了,后面业务出了问题排查起来更麻烦。锁定之后观察一段时间,确认没问题,再删也不迟。这是运维里常用的一种稳妥做法,线上操作永远要给自己留回退空间。
另外还有一个细节很多人会忽略:检查一下有没有uid为0的非root账户。uid为0意味着这个账户和root拥有完全相同的权限,哪怕用户名长得再普通,也是超级用户。命令行查一下:
awk -F: '$3 == 0 {print $1}' /etc/passwd正常情况,这条命令只会返回root。如果多出来任何名字,马上处理。
2.2 密码策略:别让弱口令毁掉所有加固
账户清完了,下一步就是密码。我不夸张地讲,这么多年我看过的被入侵案例里,八成以上都是从弱口令被爆破开始的。很多人觉得Linux服务器嘛,谁能猜到密码?真的是太小看自动化攻击了。
网上有现成的密码字典,攻击者用工具挂上字典,SSH端口开着密码登录,几万个密码组合几小时就能跑完。你以为的“复杂密码”,可能在字典里躺了好几年了。
那到底怎么设密码?我的建议是,至少12位以上,包含大小写字母、数字和特殊符号,并且不要用任何有意义的单词、生日、键盘连续键。密码设置可以配合/etc/login.defs和/etc/pam.d/里的策略来强制。我用linux-pam提供的pam_pwquality模块比较多,配置完之后设置密码时就会强制校验复杂度。
举个例子,在/etc/pam.d/system-auth或/etc/pam.d/passwd里加上这行:
password requisite pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1解释一下参数:minlen是密码最小长度12位,dcredit、ucredit、lcredit、ocredit分别是要求至少包含一个数字、大写字母、小写字母、特殊字符,前面带负号表示“至少需要多少个”,不带负号则表示“最多允许缺多少个”,别搞混了。retry=3是允许用户重试三次。
还有密码过期策略。一条命令就能设置:
chage -M 90 username强制用户每90天改一次密码。这里有个提醒:如果机器上跑着脚本或服务,用的是密码认证方式,强制改密可能会导致服务认证失败。所以我一般会建议,给人和给服务分开管理,服务尽量用密钥或专用的认证方式,这个我们后面细说。
2.3 SSH加固:远程管理的护城河
如果说账户和密码是门锁,那SSH就是你房子的大门。Linux服务器绝大多数都是远程管理的,SSH也是最常被攻击的入口。我对SSH加固的优先级排序是这样的:
第一,禁用root直接登录。root是超级管理员,一旦被攻破,整个系统就沦陷了。用普通用户登录,需要提权时再sudo,至少多了一道关卡。在/etc/ssh/sshd_config里设置:
PermitRootLogin no第二,优先使用密钥认证,把密码认证关掉。密钥是一对非对称加密的钥匙,你拿着私钥,公钥放在服务器上,登录时靠签名验证,比密码这种方式安全得多,基本不存在爆破的可能。配置项是:
PasswordAuthentication no PubkeyAuthentication yes但这里我要特别提醒一句:关密码认证之前,一定要先确认你的密钥能正常登录,并且把公钥写到对应用户的~/.ssh/authorized_keys里。这个顺序搞反了,你就把自己锁在门外了。我干过这蠢事,当时冷汗都下来了,最后只能通过云厂商的网页终端进去改回来。这种教训一次就够了。
第三,自定义SSH端口。把默认的22改成别的端口,比如32221。这算不上真正意义上的安全防护,因为扫描器扫的是整个网段的所有端口,你改它照样扫得到,但它能挡掉大量“只扫默认端口”的自动攻击脚本,让日志里的爆破尝试少一大截,对降低噪音是立竿见影的。
第四,启用fail2ban。这个工具会自动监控认证日志,检测到同一个IP反复认证失败,就自动封禁这个IP一段时间。它不复杂,装上之后配置一个过滤规则,指定封禁时间就行。当年那台被挖矿程序搞死的服务器,如果提前上了fail2ban,可能根本走不到那一步。
3. 权限体系:最小化才能最大化安全
门锁好了,接下来要看屋里的人。就算攻击者拿到某个普通账户,他能做什么,取决于权限体系设计得怎么样。Linux权限体系的核心思想就四个字:最小权限。给每个用户、每个进程只开刚好够用的权限,多一分都不给。
3.1 文件和目录权限:先把底层的规矩立好
Linux文件权限最基础的是r、w、x三组权限,分别对应owner、group、others。很多人觉得这个太简单了,不值得做安全加固。我跟你说,恰恰是这种最简单的东西,事故率最高。
举几个我见过的真实场景:网站配置文件的密码明文写在/var/www/html里,目录权限是777,任何用户都能改;备份脚本生成的压缩包权限没做限制,里面是数据库的全部数据,结果被webshell一扫就拖走了。这种问题,根本不需要多高深的技术,全靠权限配置到位就能避免。
我的做法是给线上文件做一次全面体检,目标很简单:所有文件、目录的属主和权限都明确,不该被任何人写的绝不放开写权限。一条常用的命令:
# 查找权限过于宽松的关键文件 find /etc -type f -perm -o+w -exec ls -l {} \;发现可疑的,统一收紧:
chmod 644 /etc/xxx.conf chmod 600 /etc/shadow这里有个知识点要提醒一下:chmod/chown这类操作权限本身就是高危动作。比如不小心把/bin目录递归改成777,系统还活着,但安全防线已经名存实亡了。所以我给自己定的规矩是,涉及系统目录的权限改动,必须一条一条针对性执行,绝对不用通配符大范围递归,除非你对整条命令的后果有百分之百的把握。
3.2 sudo权限:分权但不能失控
sudo是Linux里给普通用户临时提权的标准方案。它很好用,但用不好就是灾难。不少运维图省事,直接把sudoers文件里配成所有用户都能执行所有命令,或者某个用户有了NOPASSWD的ALL权限,这和给那台机器留了一根万能钥匙没有区别。
理解sudo的核心,就是把“谁可以以什么身份、执行哪些命令”搞得清清楚楚。修改/etc/sudoers,正规做法是先用visudo命令去编辑,它会帮你做语法检查,防止你写错导致整个sudo不可用。
配置的粒度你应该控制到命令级别。举个例子,如果开发同事需要重启某个Web服务,那就只给他这个权限:
username ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx而不是给一个ALL。如果只是查看日志,那就用只读的tail或grep,进一步可以把这些命令做成只读脚本再授权,避免命令本身支持提权导致权限扩大。
我特意强调一点:sudo授权时特别要防一个坑,就是那些本身能派生出shell的命令,比如vim、less、more、find、man等。用户拿到这些命令的sudo权限之后,在编辑器里输入:!bash,直接就得到一个root shell,权限瞬间就失控了。所以授权之前,先想想这个命令能不能被用来执行任意程序。不能确保安全的,宁可不给。
3.3 SELinux与AppArmor:给系统再加一道保险
文件权限和sudo解决的是“用户能干什么”,SELinux和AppArmor解决的是“进程能干什么”。这两者是强制访问控制,是比传统权限更高一层的防护机制。
SELinux是红帽系发行版自带的,默认就有,安装系统时就启用了。很多运维嫌它麻烦,因为配置不当会导致服务起不来,直接就把它关了。我完全理解这个痛,早年间我也这么干过,后来被现实教育了。SELinux是在系统被攻破之后,还能帮你拦住进程越界行为的关键防线。比如Web服务拿到了系统shell,想读写/etc/shadow,SELinux策略会直接拒绝。
现在主流发行版上SELinux的使用难度已经低很多了。真遇到服务起不来的情况,先不急着关闭,用audit2why看违反了什么策略,常见问题都是端口上下文、文件标签不对,一条restorecon就能修复。这比关闭整个机制要划算得多。
Debian系是AppArmor,用法类似,配置门槛更低一些。我的建议始终是:宁可花半天时间学会调策略,也别一条setenforce 0了事,你关掉的不是那个“烦人”的机制,而是整台机器最后一道防线。
4. 网络层防护:缩小攻击面
账户和权限管的是“谁能进、能做什么”,网络层管的是“别人是否能碰到你的门”。只要攻击面足够小,攻击者连你的门在哪里都不知道,安全水平自然就上去了。
4.1 最小化已启动的服务:少一个服务,少一条路
一台Linux服务器默认会开启一堆网络服务。问题是,这些服务对你当前的业务来说,可能绝大多数都用不上。任何一个监听在网络端口上的服务,都是一条潜在的入侵路径。
按照最小化原则,我只保留业务必需的服务,其余一律关闭。查看已启动服务的命令:
systemctl list-units --type=service --state=running systemctl list-unit-files --type=service --state=enabled第一行是当前正在运行的服务,第二行是开机自启的服务。对照业务的实际情况,把不需要的停掉,再设置成禁止开机启动:
systemctl stop xxx.service systemctl disable xxx.service这条命令我建议你仔细做,做的时候多留意:如果某个服务名字听起来很陌生,先查清楚它是干什么用的,再决定要不要关。有一回我以为某个服务是系统自带的无关进程,差点关掉,后来发现是数据库高可用的一个依赖。所以动手之前,务必确认,别莽。
4.2 配置防火墙:默认拒绝是基本原则
防火墙的思维和直觉是反着的。大多数人刚开始配防火墙时,下意识是“先放行,再指定禁止”,但安全加固的正确姿势恰恰是“先默认拒绝,再逐个放行”。就像你家里先关好门窗,只给少数亲人留钥匙,而不是把门开着,然后贴个条“坏人禁止入内”。
以Linux标配的firewalld为例。基础思路很简单:
# 默认设置成拒绝入站 firewall-cmd --permanent --set-default-zone=drop # 单独放行必要的端口 firewall-cmd --permanent --add-port=32221/tcp firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=443/tcp # 重载使其生效 firewall-cmd --reload这里有几个陷阱我要重点提醒。第一个是,上面这个配置是给有公网IP的服务器用的,你要是这么设置了之后发现网关连不上了,多半是默认zone设置penalty把本机出方向流量也挡了,需要额外给回环接口和内部管理网段放行。第二个是,有些云厂商在操作系统层之外还有一层安全组,两者之间的关系是“交集”,也就是说,你在系统上的防火墙规则再严格,安全组放行的范围才是最终上限。所以两边都要配,别只改一边。
4.3 端口管理:控制暴露面
端口管理其实是对前面几条的补充。你要做到心里有数:这台机器到底有哪些端口在对外监听?这是攻击者最关心的信息,也是你应该时刻掌握的。
常用命令:
ss -lntup这个命令会列出所有正在监听的TCP/UDP端口和对应的进程。看到监听地址是0.0.0.0或者::的,就意味着对所有网卡开放,包括公网。如果某个服务只需要内网访问,那就绑定到内网IP上,可以通过修改配置里的监听地址来实现。
举个例子,数据库服务默认可能监听在所有地址上,如果你只有应用服务器需要连接它,那就把配置改成只监听应用服务器的网段IP,公网彻底不暴露。这种操作不算复杂,但是能把一大票扫描攻击直接挡在外面,性价比极高。
5. 日志与审计:让每件事都留下痕迹
很多运维小伙伴对日志的态度是:出事了才想起来看。这其实是本末倒置了。日志不只是用来排查故障的,它更是安全分析的核心数据源。没有日志,攻击者来了你都不知道,走后门留下的痕迹你也没法追踪,更别说在攻击未遂时提前发现苗头了。安全加固不是把所有路都堵死就万事大吉,真实世界里总会有漏网之鱼,日志就是捕鱼的那张网。
5.1 开启和配置关键日志
Linux系统日志默认是记的,但默认配置往往不够。比如认证日志、sudo日志、内核日志这些关键内容,默认情况下可能只有本地的文件记录。更关键的是,一些应用日志默认不开,比如Web服务,需要单独打开访问日志和错误日志。
我先给你梳理一下几个核心日志文件,后面排查时会非常有用:
- /var/log/messages:系统整体运行日志,各种服务报错一般都在这里。
- /var/log/secure:认证和授权日志。用户登录、SSH连接、sudo操作,都记录在这里。
- /var/log/cron:计划任务执行日志。
- /var/log/audit/audit.log:系统的审计日志,SELinux的拒绝信息也在这里。
如果你用的系统把这些路径做了调整,可以通过查看/etc/rsyslog.conf或journalctl来找对应信息。现在不少发行版默认用systemd-journald,journalctl -xe这类命令查日志也很方便。
5.2 配置审计规则:记录关键行为
除了常规日志,Linux的auditd服务可以做更细粒度的审计。它可以跟踪指定的系统调用和文件访问,比如谁改了/etc/passwd,谁在执行什么可疑命令,都会记录下来。
安装和启动auditd很简单:
systemctl enable auditd systemctl start auditd然后通过/etc/audit/rules.d/audit.rules添加监控规则。举一个我常用的规则,监控关键文件和目录的写操作:
-w /etc/passwd -p wa -k passwd_changes -w /etc/sudoers -p wa -k sudoers_changes这里的含义是:监控/etc/passwd和/etc/sudoers的写入和属性修改,并给事件打上passwd_changes、sudoers_changes标签。配置之后用auditctl -R /etc/audit/rules.d/audit.rules加载一下,然后通过ausearch -k passwd_changes查询。
审计规则不要贪多,规则太多会产生海量日志,反而淹没了真正重要的信息。我一般只监控那些“不应该变但必须防”的文件和目录,就够了。
5.3 日志集中管理与定期检查
日志配置完了,还有两个问题要解决:一是日志太多,把磁盘挤爆;二是日志只存在本机,攻击者入侵之后先清日志,你什么都没了。
解决日志太多,用logrotate做日志轮转,按天或按大小切割,超过一定份数的旧日志自动清理。系统自带的对系统日志已经有轮转配置,但自定义的应用日志需要你手动添加对应的配置。
解决日志被篡改,更可靠的办法是日志集中存储,通过rsyslog把日志实时转发到专门的日志服务器,或者用一些日志平台做采集和检索。这样一来,本机就算被清了,远程那儿的记录还在。这里要提醒一句:日志集中存储本身要有访问控制,不能是谁都能翻的明账本。
有了日志,你必须定期看,而不是等到出了事再看。我个人的习惯是每天快速扫一眼/var/log/secure里有没有异常的认证失败记录,周末抽空把auditd里标记的关键事件过一遍。看日志看着枯燥,但在攻击刚开始的阶段就可能被你发现,比事后补救要舒服太多了。
6. 补丁与基线:加固是一次没有终点的循环
前面几大策略做下来,静态安全水平已经挺不错了。但安全不是一锤子买卖,漏洞是动态出现的,业务也在不断变化,所以补丁管理和基线检查必须跟上。
6.1 系统更新:把补丁这件事纳入节奏
很多运维怕更新,理由很充分:更新有风险,可能把正在运行的服务搞挂。这个担心我能理解,但完全放弃更新,等于把所有已知漏洞都暴露给攻击者,这个风险更大。
我见过最惨痛的一个案例是,某台跑着老版本Web服务的服务器,内核和依赖库多年没更新过,结果被人利用一个公开了两年的提权漏洞拿到了root权限。这个漏洞的修复补丁一年前就出了,只要打了补丁,后面整条入侵链根本走不通。
更新也有技巧,不是让你上了生产就yum update -y。正确做法是先在测试环境验证,再在维护窗口期操作生产机器,更新前备份好配置,更新失败能快速回滚。内核和关键服务更新完之后,注意重启确认状态。
6.2 建立自己的安全基线
安全基线就是你对一台服务器的最低安全标准。每次装完新机器,照着基线检查一遍,不符合就修,不能每次都靠人脑回忆“上次是怎么配的”。
我给自己定的基线比较简单,你可以直接抄:
- root密码和所有用户密码满足强度要求,且定期修改。
- SSH禁止root登录,禁用密码登录,启用密钥认证。
- 防火墙默认拒绝入站,只放行业务端口。
- 无用服务和端口全部关闭。
- sudo规则最小化,不存在ALL权限的普通用户。
- 日志全部开启,auditd覆盖关键文件,日志集中存储。
- 系统补丁保持最新,超过安全周期的版本考虑升级。
这个基线的检查,可以用脚本辅助。比如写一个脚本,自动检测SSH配置项、防火墙规则、sudoers关键项、日志是否在运行,把不符合项列出来。这样巡检一遍只需要几分钟,省下的时间干点别的不香吗?
6.3 定期做个安全体检
新机器照着基线装好,不代表永远安全。业务在变,使用的人在变,密码可能被新来的同事设成了简单口令,防火墙可能有人为了测试临时放行了端口没撤,这些都是安全基线的“漂移”,如不及时修正,当初的加固努力慢慢就白费了。
我建议每隔一个季度或者半年,对每台机器做一次系统的安全复查。复查不是重新做一遍前面五大策略,而是对照基线,找出漂移项并修正。再把近期日志和审计记录扫一遍,看看有没有可疑的访问痕迹。这种定期体检加上日常监控,才能让安全加固的效果持续存在。
7. 最后分享一点个人体会
我做了这么多年服务器运维,越来越理解一个道理:安全不是一个结果,而是一个过程。你把所有策略都做了,也不能保证百分之百安全,但如果不做,那出事就只是时间问题了。防护手段永远在和攻击者赛跑,我们能做的,是把这条赛道尽量修得长一点、陡一点,让对方跑得慢一些。
写这篇文章不是想让你立刻把每一条都做到满分。事实上,一次性想把所有策略全部完美落地,往往会因为操作失误反倒引入新的问题。我更建议你按照这个顺序来:先把账户和SSH加固做好,把密码策略和基础权限理清,这两条永远是投入产出比最高的。然后再逐步推进防火墙、日志和补丁流程。每一步做完,确认稳定了,再走下一步,稳扎稳打,比一步到位更靠谱。
如果你看完这篇文章,能回去查一查自己的服务器开了哪些端口、允许谁用root登录、日志有没有在看,那这篇文章就没白写。安全这件事,说到底就是靠一个“勤”字:勤检查、勤更新、勤复盘,别偷懒。就聊到这儿吧,我得去看看今天有没有新的认证失败日志了。