5.1 Linux 服务器安全加固指南

预计阅读时间:16 分钟

📖 目录

学习目标

学完本章后,你将能够:

  • 理解最小权限、纵深防御、默认拒绝三大安全原则
  • 加固 SSH 服务(密钥认证、禁用 root、fail2ban)
  • 配置 UFW/nftables 防火墙的最小开放规则
  • 审计文件权限、SUID/SGID 和内核安全参数
  • 制定并执行自动化安全更新策略

核心知识

  • 最小权限原则(Principle of Least Privilege)——任何用户/进程只拥有完成工作所需的最小权限
  • 纵深防御(Defense in Depth)——多层安全机制叠加,单层失守不会导致全线崩溃
  • 默认拒绝(Default Deny)——白名单模式,未明确允许的一律拒绝
  • SSH 密钥认证——使用公钥/私钥对替代密码登录,杜绝暴力破解
  • fail2ban——通过分析日志自动封禁反复失败的 IP
  • UFW(Uncomplicated Firewall)——iptables 的前端管理工具
  • SUID/SGID 位——允许普通用户以文件属主或属组的权限执行程序的安全特性
  • unattended-upgrades——Debian/Ubuntu 自动安全更新机制
  • sysctl——Linux 内核运行时参数配置接口

知识关联

原理讲解

为什么安全加固要遵循"最小权限、纵深防御、默认拒绝"三大原则

这三个原则并非凭空而来,而是从真实攻击案例中总结出的防御哲学。最小权限原则源于"一旦攻击者突破某一层,其权限应被限制在最小范围内"——例如 Web 应用漏洞导致的提权攻击,如果 Nginx 进程以 nobody 用户运行且无写权限,攻击者即使拿到 shell 也无法写入关键系统文件。纵深防御承认"没有任何单一防线是完美的",因此在认证、网络、文件系统、内核参数等多个层次叠加防御,单层失守不会导致全线崩溃。默认拒绝则是白名单思维——与其列举所有危险然后逐一阻止(黑名单),不如只允许已知安全的行为,其余一律拒绝。这种设计减少了规则遗漏的可能性,但增加了管理成本,需要在安全性和可维护性之间取得平衡。

从实现角度看,Linux 的安全模型是一个分层栈:DAC(自主访问控制)处理用户/组/other 的基本权限 → MAC(SELinux/AppArmor)叠加强制访问控制 → 防火墙(nftables)在网络层过滤 → 内核参数(sysctl)关闭危险功能 → 应用层自身安全(SSH 加固、fail2ban)。每一层独立运作,即使某层配置有误,其他层仍能提供保护。

攻击面与缩减策略

每台 Linux 服务器都有攻击面(Attack Surface)——即潜在的可被利用入口。包括:运行的服务、开放的端口、安装的软件包、存在的用户账户。安全加固的本质就是系统性地缩减攻击面。缩减策略遵循"三不":不需要的服务不运行、不需要的端口不开放、不需要的用户不存在。

SSH 加固的层次

SSH 是最常见的远程管理入口,也是暴力攻击的首要目标。加固分三个层次:第一层是认证方式(禁用密码 → 仅密钥),第二层是暴露面(改端口、限制登录用户),第三层是动态防护(fail2ban 自动封禁)。三层叠加后,SSH 的安全性大幅提升。

CIS 基准与等保合规

CIS(Center for Internet Security)发布了一系列操作系统安全配置基准,涵盖 SSH、内核参数、文件权限、审计日志等数百项检查项。本章的加固措施是 CIS 基准的子集,适用于大多数互联网场景。等保二级/三级要求可在此基础上增加 auditd 审计日志和强制访问控制(SELinux/AppArmor)。

sysctl 安全参数速查表

参数推荐值防护目标
net.ipv4.tcp_syncookies1SYN Flood 泛洪攻击
net.ipv4.conf.all.rp_filter1IP 源地址欺骗(反伪造)
net.ipv4.conf.all.accept_redirects0ICMP 重定向劫持路由
net.ipv4.conf.all.accept_source_route0源路由攻击
net.ipv4.icmp_echo_ignore_broadcasts1Smurf 放大攻击
net.ipv4.icmp_ignore_bogus_error_responses1伪造错误响应干扰
net.ipv4.conf.all.log_martians1记录异常源地址(侦察辅助)
net.ipv6.conf.all.accept_redirects0IPv6 重定向攻击
kernel.randomize_va_space2ASLR 地址空间随机化
kernel.dmesg_restrict1禁止普通用户读取内核日志
kernel.kptr_restrict1隐藏内核指针地址
fs.suid_dumpable0禁止 SUID 程序产生核心转储

注意:net.ipv4.conf.all.*net.ipv4.conf.default.* 需要成对设置——all 控制全局,default 控制新创建接口。修改后务必用 sysctl -a | grep 参数名 验证实际生效值。

示例代码

1. SSH 加固

# /etc/ssh/sshd_config 关键配置
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak  # 先备份

sudo sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config

# 限制允许登录的用户(白名单)
echo "AllowUsers alice bob deploy" | sudo tee -a /etc/ssh/sshd_config

# 应用配置
sudo systemctl reload sshd

# 验证(另开终端确认连接正常再关闭当前会话!)
ssh -v alice@your-server 2>&1 | grep "Authentication"
# 输出: Authenticated with public key "alice@laptop"

2. UFW 防火墙配置

# 查看当前状态
sudo ufw status verbose
# 输出: Status: inactive

# 设置默认策略
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 开放必要端口
sudo ufw allow 22/tcp      # SSH
sudo ufw allow 80/tcp      # HTTP
sudo ufw allow 443/tcp     # HTTPS

# 可选:限制 SSH 频率(30 秒内最多 6 次尝试)
sudo ufw limit 22/tcp

# 启用防火墙
sudo ufw enable

# 验证规则
sudo ufw status numbered
# 输出:
#      To                         Action      From
# --  ------                    ------      ----
# [ 1] 22/tcp                    LIMIT       Anywhere
# [ 2] 80/tcp                    ALLOW       Anywhere
# [ 3] 443/tcp                   ALLOW       Anywhere

3. fail2ban 安装与配置

# 安装
sudo apt install fail2ban -y

# 创建本地覆盖配置(不建议直接改 jail.conf)
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400
EOF

# 启动并启用
sudo systemctl enable --now fail2ban

# 查看 SSH 防护状态
sudo fail2ban-client status sshd
# 输出:
# Status for the jail: sshd
# |- Filter
# |  |- Currently failed: 2
# |  |- Total failed: 47
# |- Actions
#    |- Currently banned: 3
#    |- Total banned: 12

# 手动解封 IP
sudo fail2ban-client set sshd unbanip 192.168.1.100

4. 自动安全更新

# 安装 unattended-upgrades
sudo apt install unattended-upgrades -y

# 配置自动更新
sudo dpkg-reconfigure --priority=low unattended-upgrades
# 交互式确认后,配置文件写入 /etc/apt/apt.conf.d/20auto-upgrades

# 验证配置
cat /etc/apt/apt.conf.d/20auto-upgrades
# 输出:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";

# 触发一次手动检查
sudo unattended-upgrades --dry-run --debug

5. 文件权限审计

# 查找全局可写文件(安全隐患:任何用户可篡改)
sudo find / -type f -perm -o+w ! -path '/proc/*' ! -path '/sys/*' 2>/dev/null

# 查找 SUID/SGID 文件(提权风险)
sudo find / \( -perm -4000 -o -perm -2000 \) -type f ! -path '/proc/*' ! -path '/sys/*' 2>/dev/null

# 移除不必要的 SUID 位
sudo chmod u-s /usr/bin/wall     # 如果不需要广播消息
sudo chmod u-s /usr/bin/chsh     # 如果使用集中用户管理

# 审计 /home 目录权限
sudo find /home -type f -perm /o+w 2>/dev/null

6. 内核安全参数

# 创建内核参数配置文件
sudo tee /etc/sysctl.d/99-security.conf << 'EOF'
# IP 欺骗防护
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# 禁用 ICMP 重定向(防止中间人攻击)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# 启用 SYN Cookie(防 SYN Flood 攻击)
net.ipv4.tcp_syncookies = 1

# 忽略 ICMP 广播请求(防 Smurf 攻击)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# 记录无路由的源地址包
net.ipv4.conf.all.log_martians = 1
EOF

# 立即生效
sudo sysctl -p /etc/sysctl.d/99-security.conf

# 验证单个参数
sysctl net.ipv4.tcp_syncookies
# 输出: net.ipv4.tcp_syncookies = 1

7. 完整性检查(AIDE)

# 安装 AIDE(Advanced Intrusion Detection Environment)
sudo apt install aide -y

# 初始化数据库
sudo aideinit
# 输出: ... aide.db.new generated

# 复制数据库
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# 执行一次完整性检查
sudo aide --check
# 输出: ... 无变化提示或列出被变更的文件列表

# 配合 cron 每日检查
sudo crontab -e
# 添加:
# 0 6 * * * /usr/bin/aide --check | mail -s "AIDE Report" admin@example.com

8. PAM 密码策略:强度与有效期

# PAM(Pluggable Authentication Modules)是统一认证框架,
# 密码强度规则由 pam_pwquality 模块提供

# Ubuntu/Debian: /etc/security/pwquality.conf
sudo tee /etc/security/pwquality.conf << 'EOF'
minlen = 12            # 最小长度
dcredit = -1           # 至少 1 位数字
ucredit = -1           # 至少 1 位大写字母
lcredit = -1           # 至少 1 位小写字母
ocredit = -1           # 至少 1 位特殊字符
maxrepeat = 3          # 同一字符最多连续 3 次
difok = 5              # 新密码与旧密码至少 5 个字符不同
retry = 3              # 输错可重试次数
EOF
# 确保 /etc/pam.d/common-password 中已启用:
# password requisite pam_pwquality.so retry=3

# 密码有效期与过期控制(chage 操作 /etc/shadow 字段)
sudo chage -M 90 -m 7 -W 14 alice
# -M 90: 90 天后必须改密   -m 7: 两次改密至少间隔 7 天
# -W 14: 过期前 14 天提醒
sudo chage -l alice          # 查看账号过期策略
sudo chage -d 0 alice        # 强制下次登录修改密码

# 验证策略生效(弱密码会被拒绝)
sudo passwd alice

9. sudoers 细粒度授权

# 授权模型: 谁 + 在哪台机器 + 以什么身份 + 能执行哪些命令 + 是否要密码

# 安全编辑(visudo 自带语法校验,写错不会锁死 sudo)
sudo visudo -f /etc/sudoers.d/deploy

# 示例: 只允许 deploy 用户执行特定运维命令,不给 root shell
# /etc/sudoers.d/deploy
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, \
                         /usr/bin/systemctl reload nginx, \
                         /usr/bin/journalctl -u nginx, \
                         /usr/bin/docker ps

# Cmnd_Alias 命令别名: 多命令集合复用
# /etc/sudoers.d/ops
Cmnd_Alias OPS_CMD = /usr/bin/systemctl, /usr/bin/iptables, /usr/bin/nft
Cmnd_Alias DEV_CMD = /usr/bin/docker, /usr/bin/git, /usr/bin/make
%ops ALL=(ALL) NOPASSWD: OPS_CMD
%devs ALL=(ALL) NOPASSWD: DEV_CMD

# 密码缓存时长(默认 15 分钟免密,生产建议缩短)
sudo visudo
# 添加: Defaults timestamp_timeout=5

# 审计 sudo 使用(记录命令与参数)
sudo grep "COMMAND" /var/log/auth.log | tail -20
# 输出: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt update

# 验证授权
sudo -l -U deploy                    # 查看 deploy 拥有的 sudo 权限

10. 文件系统挂载安全选项:noexec / nodev / nosuid

# 原理: 即使攻击者拿到写入权限,也无法在加固挂载点上执行程序、
#       创建设备节点、或利用 SUID 提权 —— 纵深防御的关键一环

# 场景一: /tmp 必须加固(攻击者最常利用的写入点)
# /etc/fstab
UUID=xxxx /tmp ext4 defaults,noexec,nosuid,nodev,mode=1777 0 2

# 场景二: 家目录(防放置恶意可执行文件与设备文件)
UUID=yyyy /home ext4 defaults,nodev,nosuid 0 2

# 场景三: 静态业务数据只读挂载(不可变数据)
UUID=zzzz /opt/app/static ext4 defaults,ro,nodev,nosuid 0 2

# 对运行中的系统临时重挂载(无需重启)
sudo mount -o remount,noexec,nosuid,nodev /tmp

# 验证
mount | grep /tmp
# 输出: /dev/sda3 on /tmp type ext4 (rw,noexec,nosuid,nodev,...)
touch /tmp/x.sh && /tmp/x.sh    # 执行会报 Permission denied

# 盘点现有挂载点的加固状态
sudo findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS | grep -E "noexec|nosuid" || echo "存在未加固挂载点"
# 注意: 加固前先确认业务没有依赖 /tmp 执行文件的场景(部分安装脚本会)

11. rkhunter 与 lynis:入侵检测与安全审计

# rkhunter: 检测 rootkit 后门、恶意文件属性、可疑内核模块
sudo apt install rkhunter -y

# 更新特征库并记录文件属性基线
sudo rkhunter --update
sudo rkhunter --propupd

# 全盘扫描
sudo rkhunter --check --sk
# 输出:
# Checking for rootkits...                      [ OK ]
# Checking /dev for suspicious file types...    [ None found ]
# 可疑项标为 [ Warning ],详细见 /var/log/rkhunter.log
sudo rkhunter --report

# 每日定时扫描
sudo tee /etc/cron.daily/rkhunter.sh << 'EOF'
#!/bin/bash
/usr/bin/rkhunter --check --cronjob --report-warnings-only
EOF
sudo chmod +x /etc/cron.daily/rkhunter.sh

# lynis: 系统安全审计(输出 CIS 风格硬化建议与评分)
sudo apt install lynis -y
sudo lynis audit system
# 输出: 逐项审计 [FOUND]/[SUGGESTION],结尾给出 Hardening Index 分数(如 76/100)
sudo lynis report --viewer      # 交互式查看完整建议

# 落地闭环: [!!] 高风险项优先处理 → 修复后重跑对比分数
# 配合 ch28 Ansible 将审计建议固化为 Playbook,批量应用到所有服务器

常见错误

错误表现根因正确做法
SSH 配置重启后自己被踢出,无法再登录未在另一终端验证连接就关闭了当前会话修改 sshd_config 后先 sudo sshd -t 检查语法,再开第二个终端验证登录成功再关闭原会话
ERROR: Couldn't determine iptables version系统使用 nftables,UFW 底层需 iptables 兼容层sudo apt install iptables 或切换到 nft 直接管理
fail2ban 封禁后自己也被封了测试时频繁重试触发了封禁规则jail.local 中将本机 IP 加入 ignoreip 白名单
unattended-upgrades 导致服务在业务高峰期重启自动更新后某些服务被自动重启配置 Unattended-Upgrade::Automatic-Reboot "false",手动安排重启窗口
应用无法写入自己的数据目录权限设置过严,应用用户无写权限区分"可执行"和"可写"目录:/usr/share/app 只读,/var/lib/app 可写
修改 sudoers 后所有 sudo 都报错sudoers 语法错误导致 sudo 拒绝加载配置永远用 sudo visudo 编辑(自带语法检查);已锁死时用 root 或 pkexec visudo 修复
PAM 密码策略配置后用户无法改密pwquality 规则过严且 retry=0,弱密码直接被拒设置 retry = 3;先用 chage -l 了解现有账号,分级制定强度
挂载 noexec 后应用脚本全部 Permission denied业务脚本存放在被加固的挂载点内临时脚本放 /var/tmp 或独立可执行目录;加固前用 findmnt 盘点业务依赖

最佳实践

实践原理示例
SSH 使用非默认端口(可选)减少自动化扫描工具的命中率Port 2222,注意防火墙同步放行
每季度执行一次安全基线审计漂移检测——配置变更难免,定期审计确保合规使用 lynis audit system 或 CIS-CAT 工具
将安全更新与功能更新分离安全更新应该立即应用,功能更新需要测试窗口配置 Unattended-Upgrade::Allowed-Origins 仅包含 ${distro_id}:${distro_codename}-security
日志远程集中存储防止攻击者清理本地日志掩盖痕迹配置 rsyslog 将日志转发到 4.8:集中式日志管理 集中日志服务器
使用 SSH CA 进行主机/用户证书认证无需逐个管理 authorized_keys,吊销权限立即生效配置 TrustedUserCAKeysHostCertificate
密码策略与 sudoers 一起纳入配置管理人工改配置会漂移,用自动化保证每台机器一致4.1:Ansible 自动化 Ansible 管理 pwquality.conf/etc/sudoers.d/sysctl.d 与 fstab
rkhunter/lynis/AIDE 定期执行并留档入侵检测的价值在于"发现得早",需要持续运行而非一次性cron.daily 扫描 + 报告邮件;月度对比 Hardening Index 分数趋势

练习题

  1. (概念)什么是纵深防御?请用你自己的话解释为什么单层安全是不够的。
  2. (概念)SUID 位的作用是什么?列举两个系统中设置了 SUID 的程序,解释为什么它们需要这个权限。
  3. (实操)在一台 Ubuntu 服务器上完成:禁用 SSH 密码登录、配置 UFW 仅开放 22 和 443 端口、安装并配置 fail2ban 保护 SSH。用另一台机器尝试暴力破解验证防护效果。
  4. (实操)执行 find / -perm -4000 2>/dev/null 列出系统上所有 SUID 文件,分析其中至少 3 个文件是否真的需要 SUID 位。如有可移除的,执行 sudo chmod u-s 移除。
  5. (🔍 挑战)搭建一个双机测试环境:主服务器安装 AIDE 并初始化数据库,模拟攻击者在半夜修改了 /bin/ls,然后运行 sudo aide --check 检查更改。配置 cron 每天 6:00 执行检查并将结果通过电子邮件发送到指定邮箱。
点击查看答案
  1. (概念)纵深防御(Defense in Depth)指在系统的不同层次部署多重安全措施,即使某一层被突破,后续层仍能防御。单层安全不够的原因:任何单点都可能失效(如 SSH 密码泄露→如果只靠密码认证则全线沦陷,但加上密钥认证 + fail2ban + UFW 则层层设防)。
  2. (概念)SUID 位(Set User ID)使程序运行时以文件所有者(通常是 root)而非当前用户身份执行。常见 SUID 程序:/usr/bin/passwd(普通用户需要以 root 权限修改 /etc/shadow)、/bin/ping(需要 root 权限创建原始套接字)。过多的 SUID 程序是安全风险——每个都是提权攻击的潜在入口。
  3. (实操)SSH 配置:/etc/ssh/sshd_configPasswordAuthentication nosudo sshd -t && sudo systemctl reload sshd。UFW:sudo ufw default deny incoming; sudo ufw allow 22/tcp; sudo ufw allow 443/tcp; sudo ufw enable。fail2ban:sudo apt install fail2ban; sudo systemctl enable fail2ban --now。验证:另一台机器用 hydra 暴力破解 SSH,观察 sudo fail2ban-client status sshd 显示 IP 被封禁。
  4. (实操)典型 SUID 文件:/usr/bin/su(切换用户必需)、/usr/bin/sudo(授权提权)、/usr/bin/mount(普通用户挂载设备)。分析判断:如 /usr/bin/wall(发送广播消息)可能不需要 SUID——sudo chmod u-s /usr/bin/wall 移除。注意:不要盲目移除系统关键程序的 SUID,否则可能导致功能异常。
  5. (🔍 挑战)AIDE 配置:sudo apt install aide; sudo aideinit 生成初始数据库(/var/lib/aide/aide.db)。攻击模拟:echo '#!/bin/bash' > /bin/ls_hack; sudo mv /bin/ls_hack /bin/lssudo aide --check 会报告 /bin/ls 的哈希值和 mtime 发生变化。cron 配置:0 6 * * * /usr/bin/aide --check | mail -s "AIDE Report" admin@example.com。注意:AIDE 的数据库文件也需要安全存储,否则攻击者可以替换数据库来隐藏痕迹。

学习检查点

学完本章后,请检验自己是否掌握以下内容:

检查项自测问题验证方法
概念理解能用自己的话解释"最小权限、纵深防御、默认拒绝"三大安全原则尝试向他人讲解
命令操作能不查文档完成 SSH 密钥认证加固、UFW 防火墙配置、fail2ban 安装部署在终端实际执行
原理掌握能说出 SSH 加固的三个层次(认证、暴露面、动态防护)画出流程图
故障排查能独立排查 SSH 配置错误导致无法登录的问题模拟故障并修复
最佳实践能说明为什么需要将安全更新与功能更新分离对比不同方案

本章总结

Linux 安全加固是运维人员的基本功,核心原则是"最小权限、纵深防御、默认拒绝"。最有影响力的加固操作依次是:SSH 仅密钥登录 + fail2ban、防火墙默认拒绝 + 仅开放必要端口、自动安全更新、内核安全参数、定期权限审计。安全不是一次性工作——配置会漂移、漏洞会披露、攻击手法会进化,需要建立持续审计和改进的机制。

速查表

命令/操作用途
sudo systemctl reload sshd应用 SSH 配置变更
sudo sshd -t检查 sshd_config 语法
sudo ufw default deny incoming设置入站默认拒绝
sudo ufw allow 80/tcp放行 HTTP 端口
sudo ufw enable启用防火墙
sudo fail2ban-client status sshd查看 SSH 封禁状态
sudo find / -perm -4000查找所有 SUID 文件
sysctl net.ipv4.tcp_syncookies查看 SYN Cookie 状态
sudo aide --check运行完整性检查
sudo unattended-upgrades --dry-run模拟安全更新

学习路径建议

  • 学完本章后建议阅读 5.5:防火墙实战 nftables 防火墙(更强大的防火墙方案)和 5.6:SELinux 与 AppArmor SELinux 与 AppArmor(强制访问控制)
  • Web 应用层防护可看 sec_web01 ModSecurity WAF 配置
  • 进阶可学习 CIS Linux Benchmark 和 OpenSCAP 自动化合规扫描
  • 等保合规场景可学习 5.13:auditd 审计 auditd 审计日志

延伸阅读

常见问题

SSH 配置为仅密钥登录后怎么备份密钥?
将 ~/.ssh/authorized_keys 和 ~/.ssh/id_rsa(私钥)加密备份。私钥丢失且服务器禁用了密码登录,你将失去所有服务器访问权限。建议用 yubikey 或硬件 token 存储私钥,同时保留一个带密码认证的紧急用户(仅绑定 IP 白名单)。
fail2ban 误封正常用户怎么解决?
先用 fail2ban-client status sshd 查看被封 IP 列表。设置白名单:在 jail.local 中 ignoreip = 你的IP。调低封禁阈值:maxretry = 5(默认 3 次误触率高),bantime = 3600(新手打错密码很正常)。也可以启用 recidive 规则防暴力破解(只封反复违规的 IP)。
CIS 基线检查和等保合规有什么关系?
CIS(Center for Internet Security)是国际安全基准,提供具体可操作的配置检查项。等保(中国网络安全等级保护)是法规合规框架,要求"应配置访问控制""应开启审计"。实践中,满足 CIS Level 1(基础安全)的大部分要求就能覆盖等保二级到三级的大部分配置项。CIS 是工具,等保是目标。
↑ 回到顶部