Linux服务器安全加固实战:从权限模型到日志审计
2026/9/15 2:57:56 网站建设 项目流程

我接手过不少被入侵的Linux服务器,事后复盘原因,十有八九不是被什么高深的0day击穿,而是栽在基础安全上——root密码是123456、SSH裸奔在公网、一个Tomcat跑在root权限下、防火墙规则形同虚设。这篇文章我会从权限模型、账户认证、文件系统、网络收敛、日志审计、加固落地六个方向,把Linux系统基础安全这摊事从头到尾捋一遍。适合刚入行的运维、自己折腾云服务器的开发者,也适合公司内部要做安全自查的同行。看完之后,你至少能把一台新装的Linux服务器按标准流程加固到能拿出来见人的程度。

1. 先搞清楚Linux安全到底在防什么

1.1 一切皆文件,权限就是命根子

Linux的设计哲学是"一切皆文件",从普通文本、设备节点到网络套接字,都被抽象成文件,访问控制的统一入口就是文件权限。这意味着只要你理解了文件权限模型,就掌握了Linux安全的一半,这是个被说烂但确实管用的切入点。

一个文件上有三组权限:文件属主(user)、属主所在组(group)、其他人(other),每组分别是读(r=4)、写(w=2)、执行(x=1)。数字表示法里,755代表属主可读可写可执行、组和其他人只能读和执行。这个基础概念很多新手都懂,但在实际分配权限时往往相当随意。

我见过最常见的错误就是图省事给目录授权0777,或者干脆把整个应用目录chmod -R 777。结果任何本地用户都能读取或篡改你的配置文件、日志文件,一旦某个Web应用被上传了webshell,攻击者就能以运行用户的身份横向读取系统里的敏感文件。正确的做法是遵循最小权限原则:每个服务一个独立账户,目录只给该账户所需的读写权限,日志文件只允许写入,配置文件只允许读取。这个原则贯穿整个加固过程,后面每一步都在落实它。

1.2 攻击者视角下的加固思路

要加固系统,先得站在攻击者角度想问题。一次典型的入侵路径通常是这样的:先扫描目标开放的端口,发现SSH、MySQL、Redis之类的外露服务;然后尝试弱口令、未授权访问或已知漏洞;一旦拿到一个低权限shell,就开始查看sudo权限、SUID文件、内核版本,寻找提权路径;最后落地上马,留后门、加计划任务、篡改日志,保证持久化。

对应到防御侧,思路就很清晰了:减小暴露面,把不必要的端口和服务全部关掉;强化认证,弱口令和默认配置全部处理;收紧权限,让普通用户即使进来了也无法横向移动;保留审计,日志和文件完整性检查做到位。四个方向都不需要特别高深的技术,但做好了,能把90%以上的常见攻击挡在外面。这篇文章的骨架就是这四个方向,后面每一章都是在落实其中一个环节。

2. 账户与登录安全,把大门先焊死

2.1 账户清理与密码策略

拿到一台新服务器,第一件事不是装业务,而是把系统里已有的账户理一遍。用下面命令看哪些用户具备root权限:

awk -F: '$3==0{print $1}' /etc/passwd

正常情况下输出应该只有root自己。如果出现别的用户名,就要警惕是不是被创建的后门账户,立即锁定或删除。系统中很多默认账户(如lp、sync、games等)不需要登录能力,可以在确认无依赖后锁定:

usermod -L lp

密码策略是另一个重灾区。默认情况下很多发行版的密码可以设置得很随意,改起来要同时看/etc/login.defs和PAM配置两个地方。前者控制密码有效期:

PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_WARN_AGE 14

这样设置之后,用户密码最多90天必须更换,最短使用7天,到期前14天开始提醒。密码复杂度则由pam_pwquality.so这个模块控制。在/etc/pam.d/system-auth/etc/pam.d/passwd中加入类似配置:

password required pam_pwquality.so retry=3 minlen=12 difok=3 ucredit=-1 lcredit=-1 dcredit=-1

含义是允许重试3次、密码最小长度12位、新旧密码至少3处不同、必须包含大写字母、小写字母和数字。第一次配置时要注意,密码策略太严格会引来业务部门的抱怨,建议先定一个中等强度,比如minlen=10加两个复杂度要求,运行一段时间后再逐步收紧。

2.2 SSH远程登录的加固细节

在所有远程管理方式里,SSH是被攻击最多的入口。默认的22端口、root直接登录、密码认证,这三个配置凑齐了基本就是给扫描器送人头。我的建议是不管服务器在不在公网,都按下面的标准来加固。

先切换到密钥认证,生成密钥对:

ssh-keygen -t ed25519 -C "your_comment"

ed25519比RSA密钥更短且安全性更高,现在主流的OpenSSH版本都支持。然后把公钥追加到服务器的~/.ssh/authorized_keys,接着修改/etc/ssh/sshd_config

PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes Port 2222 AllowUsers ops zhangsan

修改之前先备份,修改之后务必用sshd -t检查语法,然后重启sshd。这里有个新手容易忽略的坑:不要直接关掉当前SSH窗口,先用另一个终端测试新端口和密钥登录是否成功,确认没问题了再断开旧会话。否则配置文件一写错,服务器锁在门外,人就只能跑去机房或通过云厂商的VNC控制台救。

PermitRootLogin no 是把root的直接登录关掉。日常运维用普通用户登录,需要管理员权限时再执行sudo,这样所有提权操作都会被记录到日志里,出了问题知道是谁在什么时间做了什么。

AllowUsers 配合白名单可以限定只有指定用户能通过SSH登录,减少被爆破的账户面。如果公司有固定出口IP,再用防火墙把来源IP白名单限定一下,安全性还能更高。防爆破工具我最常用的是fail2ban,它通过监控认证日志,在短时间内多次登录失败的IP会被临时封禁。安装后默认配置一般够用,改一下jail.local

[sshd] enabled = true maxretry = 3 bantime = 3600 findtime = 300

意思是5分钟内失败3次就封1小时。封禁时间不要设太短,否则攻击者可以等时间过了继续爆,也不要太长,避免你把自家同事误封一整天。

2.3 PAM认证的可插拔防线

PAM(Pluggable Authentication Modules)是Linux的认证框架,它的好处是认证方式可以模块化配置,密码、指纹、LDAP、双因子都能插进去。配置文件在/etc/pam.d/目录下,每个服务一个文件。

对于基础安全来说,我比较关注两个用途:一是控制谁能登录,二是给关键服务加二次认证。前面说的密码复杂度配置其实就是通过PAM模块实现的。如果想限制只有特定用户能登录系统,可以配置/etc/security/access.conf,内容类似:

+ : root : ALL + : ops : 192.168.1.0/24 - : ALL : ALL

然后在/etc/pam.d/login/etc/pam.d/sshd中加入一行:

account required pam_access.so

这样除了root和ops组来自内网的用户,其他所有登录尝试都会被拒绝。PAM配置出错的后果比SSH配置出错更严重,它可能直接导致所有人包括root都无法登录。所以每次改动前务必备份原文件,改完之后新开一个终端测试登录,不要动当前会话。

3. 文件系统与权限控制

3.1 特殊权限位:SUID/SGID/Sticky Bit

文件权限除了基础的rwx,还有三个特殊位:SUID、SGID、Sticky Bit。其中SUID是最需要警惕的。

当一个二进制文件设置了SUID位,普通用户执行它时,会以文件属主的身份运行。系统里有/usr/bin/passwd这类程序必须依赖SUID才能让普通用户修改自己的密码。但攻击者拿到低权限shell后,也会搜索系统里所有SUID文件,如果发现某个有漏洞的SUID程序,就能借它提权到root。

检查系统里有哪些SUID文件,一条命令:

find / -perm -4000 -type f 2>/dev/null

同样的方法还可以查SGID(-perm -2000)和Sticky Bit(-perm -1000)。定期跑一遍,把结果保存下来作为基线,以后比对,多出来的文件就是重大嫌疑。确认无用的SUID权限可以去掉:

chmod u-s /path/to/file chmod g-s /path/to/dir

Sticky Bit主要用于共享目录,最典型的就是/tmp。设置了粘滞位的目录里,任何用户都能创建文件,但只能删除自己创建的文件,防止用户之间互相删文件。如果/tmp没有设置Sticky Bit,任何本地用户都能进这个目录删别人的临时文件,等于给了破坏者武器。

3.2 chattr让关键文件动不了

Linux还有一个容易被忽略的安全属性机制,chattr。给文件加上+i属性后,文件变成不可变,即使是root用户也不能修改、删除、重命名。想改内容,必须先用chattr -i解除。

这个特性对防篡改特别有用。系统里几个核心文件可以加上这个保护:

chattr +i /etc/passwd chattr +i /etc/shadow chattr +i /etc/group chattr +i /etc/gshadow

加上之后,攻击者就算拿到了root权限,想往passwd里加一个后门账户也会失败。不过要注意,这个保护是双向的,日常如果要做用户管理工作,比如useraddpasswd,会报Permission denied,得先解除属性再操作,弄完再加回去。生产环境建议封装成脚本,避免操作混乱。

更高阶的做法是利用系统的扩展属性配合审计。比如对Web目录做防篡改监控,先把文件全部加+i,然后通过eBPF或内核模块对关键路径做读写拦截审计。我看到有些安全产品就是基于file_operations层拦截read/write来实现文件防篡改和操作审计的,这种做法颗粒度很细,但需要较强的内核开发能力,普通运维场景用chattr加AIDE定期比对就足够。

3.3 SELinux与AppArmor要不要开

强制访问控制(MAC)是Linux权限体系里最容易被跳过的部分。很多人装完系统第一件事就是setenforce 0,理由是SELinux总是挡业务、报权限错误,干脆关掉省心。从安全角度讲,我不建议这么做。

SELinux通过安全策略给进程、文件打标签,精确控制"哪个进程能访问哪个文件"。它和传统的DAC(自主访问控制)是叠加关系,即使DAC权限配置没错,SELinux也能挡住越权访问。比如Web服务被攻破后,如果SELinux策略限制Apache只能访问特定的Web目录,攻击者想读取/etc/shadow就会被拒绝。

如果确实需要调整,正确做法是先用ausearchaudit2why查看被拒绝的审计记录,确认是策略问题还是业务真的需要访问,再针对性地生成或调整策略。比如:

grep AVC /var/log/audit/audit.log | audit2allow -M mypol semodule -i mypol.pp

这是在确认安全的前提下放行特定行为,而不是一棍子打死关闭整个机制。Debian/Ubuntu系列通常用AppArmor,核心理念类似,配置方式更简洁,用aa-status查看状态,aa-enforceaa-complain切换模式。建议先把有业务影响的进程放到complain模式跑一轮,确认无异常后再转enforce。

4. 网络层收敛暴露面

4.1 端口与服务排查

网络层的攻击是所有入侵的第一步,你不开端口,攻击者连你的门都摸不到。装完系统后先做一次端口盘点:

ss -tlnp

这条命令列出所有处于监听状态的TCP端口和对应进程。看到0.0.0.0:220.0.0.0:3306这类绑定在所有网卡上的监听,要特别注意。MySQL这类数据库服务如果只给本机程序用,应该只监听127.0.0.1,而不是0.0.0.0,否则等于把数据库暴露在网络上。

排查当前启用了哪些服务:

systemctl list-unit-files --type=service --state=enabled

看到明显多余的服务(比如装了图形环境带来的蓝牙、打印服务,或者实验时装的FTP、Telnet),直接禁用:

systemctl disable --now avahi-daemon systemctl disable --now cups

Telnet、rlogin、rsh这些明文协议服务只要存在就是隐患,账号密码在网络上裸奔,抓到包就等于拿到账户。任何版本的系统都不应该启用它们。除了系统服务,还要检查计划任务里有没有可疑的下载脚本:

crontab -l ls /etc/cron.d/ /etc/cron.daily/

有些挖矿木马就是通过定时任务在系统里反复下载并运行恶意程序的。

4.2 firewalld与iptables的落地配置

CentOS/RHEL系默认用firewalld,底层还是iptables。安全加固时我喜欢把默认区域设为drop,再按需放行:

firewall-cmd --permanent --default-zone=drop firewall-cmd --permanent --add-service=ssh firewall-cmd --permanent --add-service=http firewall-cmd --reload

默认区域设为drop意味着所有进站流量默认丢弃,然后再显式放行SSH、HTTP这些必要服务。注意顺序:先确保SSH放行成功,再切换默认区域,否则当前会话直接断连。如果是Ubuntu/Debian环境,用ufw来操作更简单:

ufw default deny incoming ufw allow ssh ufw allow 80/tcp ufw allow 443/tcp ufw enable

对高级一点的需求,直接写iptables规则。一个典型的入站策略骨架是:

iptables -P INPUT DROP iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -i lo -j ACCEPT

顺序很重要,iptables规则从上到下匹配,匹配后不再继续。所以"允许已建立连接"的规则必须放在"默认丢弃"之前,否则正常访问的返回包都被丢了。我见过不少人写反了顺序,然后来问我为什么SSH能连上但网页打不开,其实就是这个原因。

5. 日志审计与入侵排查

5.1 日志体系中哪些值得盯

很多服务器被入侵后,管理员都拿不出任何线索,原因就是日志没看。Linux的日志体系其实很清晰:

  • /var/log/messages:系统整体运行日志
  • /var/log/secure:认证和安全相关日志,SSH登录、sudo操作都在这里
  • /var/log/wtmp:所有成功登录的记录
  • /var/log/btmp:所有失败的登录尝试
  • /var/log/dmesg:内核日志

其中/var/log/secure是最值得每天扫一眼的。我用过一条命令快速统计最近认证失败的IP:

grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -20

如果看到某个IP尝试了几千次,基本可以判定是在暴力破解,直接加到防火墙黑名单。对于systemd管理的系统,很多服务的日志用journalctl查:

journalctl -u sshd --since "1 hour ago"

日志量大的服务器要配置logrotate做轮转,避免日志文件把磁盘撑爆。默认配置一般能用,但建议把保留周期设为90天,满足一般审计需求的同时不至于占太多空间。

5.2 一条龙排查思路

怀疑系统被入侵时,按下面的顺序排查效率最高。

第一步查登录痕迹:

last -20 lastb -20

last看谁成功登录过,lastb看哪些IP在尝试登录。如果发现不认识的主机名或IP,进一步查/var/log/secure里这个IP的操作记录。

第二步查当前进程:

ps aux --sort=-%cpu | head -20

CPU占用异常高的进程要仔细看启动路径和命令行。很多挖矿程序会伪装成类似[kworker][irqbalance]的进程名,用ps -ef看完整参数,再用ls -l /proc/PID/exe反查实际二进制路径。

第三步查网络连接:

ss -antp

如果服务器上有进程在向外网地址建立大量连接,或者监听了一个不认识的端口,赶紧定位进程并断网隔离。

第四步查持久化:

ls -l /etc/rc.d/rc.local find /etc/systemd/system -type f -name "*.service" -newer /etc/passwd crontab -l ls -la /tmp /dev/shm

攻击者要么把启动脚本塞进systemd服务,要么写进crontab或rc.local,要么利用/tmp/dev/shm这种可写目录藏文件。这几处都看一眼,基本能发现90%的后门痕迹。

第五步验证系统文件完整性。CentOS/RHEL系自带的rpm可以快速校验核心文件有没有被动过:

rpm -Va

输出里的S.5....T等标记分别代表文件大小、MD5校验、修改时间被改动过。重点看/bin/sbin/etc下的改动,如果是自己没做过的操作,基本可以确认被入侵了。

5.3 文件完整性监控

等被入侵了再排查属于事后补救。更主动的做法是提前建立文件完整性基线。最常用的工具是AIDE(Advanced Intrusion Detection Environment)。

先初始化数据库:

aide --init mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

以后定期执行aide --check,它会根据基线数据库比对文件是否被修改、新增、删除。推荐用cron每天跑一次:

0 0 * * * /usr/sbin/aide --check >> /var/log/aide.log 2>&1

AIDE适合监控配置文件、可执行文件这些不应该频繁变动的对象。配合前面的chattr +i,一个负责检测、一个负责防篡改,双管齐下效果更好。对于Web目录这类频繁变动的文件,则更适合用inotify做实时监控,或者接入日志分析平台做关联分析。

6. 加固落地清单与踩坑记录

6.1 基础加固命令速查

把前面几章的内容整理成一份可以直接执行的加固步骤,适合拿到新服务器后按顺序操作。注意先做备份,每执行一步都确认业务没有受影响再继续。

# 1. 账户与密码 awk -F: '$3==0{print $1}' /etc/passwd passwd -l 不需要登录的账户 sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs # 2. SSH加固(先备份) cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak # 修改 PermitRootLogin no、PasswordAuthentication no 等 sshd -t && systemctl reload sshd # 3. 文件权限 find / -perm -4000 -type f 2>/dev/null > /root/suid_baseline.log chown -R 应用用户:应用组 /app/data chmod -R 750 /app/data # 4. 防火墙 firewall-cmd --permanent --default-zone=drop firewall-cmd --permanent --add-service=ssh firewall-cmd --reload # 5. 日志与审计 journalctl --vacuum-time=90d systemctl start rsyslog && systemctl enable rsyslog

这份清单只是一个起点,不用所有项都照搬。公司内部有合规要求(比如等保)的,还要对应到具体的控制项,比如身份鉴别、访问控制、安全审计、入侵防范、恶意代码防范这些大类,逐项形成自查表。基础安全的核心是持续维护,不是加完一次就高枕无忧。

6.2 我踩过的几个坑

坑一:改SSH配置把自己锁在门外。我早期有一台外地机房的服务器,改了sshd_config里的一处参数,顺手reload,然后当前会话断了,新的密码认证又恰好被关掉,最后只能联系IDC重装系统。从那以后我养成了两个习惯:一是所有SSH改动前先cp备份,二是改动后用sshd -t验证,三是测试登录成功前绝不关当前窗口。

坑二:chattr +i之后改密码报错。/etc/passwd/etc/shadow加了不可变属性后,执行useradd提示文件无法修改。当时排查了半天才想起来是自己加的属性。这个教训说明:加固操作一定是业务的一部分,要做成流程,而不是临时起意。

坑三:防火墙默认drop导致服务全断。设置默认区域为drop时,没有先把必要端口放行,结果reload之后远程管理直接失效。正确的顺序永远是"先放行后收口",先把SSH放行了,再考虑把默认策略收紧。

坑四:SELinux和业务互相打架。因为没搞懂SELinux的拒绝逻辑,直接全局关闭。后来业务迁移到新环境,安全审计要求必须开SELinux,结果跑起来各种报错。其实SELinux调试并没有那么恐怖,多看看audit日志,用audit2why分析拒绝原因,大多问题都能解决。

坑五:日志太多不看等于没日志。刚开始我把所有日志都保留,磁盘满了才知道定期轮转,而且当时从没主动看过/var/log/secure。直到有一次被入侵,回溯日志才发现攻击者在爆破了一个月才拿到密码,如果当时每天扫一眼失败登录记录,早就该发现并封掉了。现在我会给关键服务器配置日志集中收集,统一到日志平台做告警,不用再一台台机器翻。

最后说点个人体会。Linux基础安全这件事,贵在坚持和制度化,而不是装个安全软件就完事。我见过太多团队做完一轮加固就抛到脑后,半年后代码上了新服务、防火墙放开了新端口,之前的努力全部归零。我的习惯是把加固项写进服务器上线标准流程,新机器一律先加固再上业务,然后每季度用lynis这类工具做一次安全审计,生成报告对照整改。安全这事没有终点,但只要不断重复基础动作,系统就会比大多数裸奔的服务器结实得多。希望这份从实战中沉淀下来的指南能帮你少走一些弯路,拿到手的每一台Linux都能稳稳当当地跑上几年。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询