系统讲解Linux服务器安全加固清单

描述

惕服务器被攻击!完整安全加固清单汇总

服务器被黑不是小概率事件。只要服务器暴露在公网,每时每刻都在被扫描、被尝试弱口令、被探测漏洞。安全加固不是"用不用心"的问题,而是"有没有做"的问题。这篇文章给出一份完整的 Linux 服务器安全加固清单,涵盖账户安全、SSH 加固、防火墙配置、服务安全、日志审计、入侵检测等核心环节。每个条目都讲解为什么要做、怎么做、不做的风险是什么,让初中级运维工程师能照着操作、落地执行。

1. 什么时候需要做安全加固

安全加固应该在服务器上线前就完成,而不是等到被黑之后。以下几个节点必须做安全加固:

新服务器交付后、上线前:服务器默认配置面向易用性,不面向安全。

系统重装或重大变更后:系统变更可能重置安全配置。

漏洞爆发后:如 OpenSSH RCE(CVE-2024-6387)、Linux 内核提权漏洞等。

通过等保测评前:等级保护要求明确的安全基线。

服务器被黑后复盘时:被黑说明存在安全缺口,需要亡羊补牢。

本文适用于 CentOS/RHEL 7/8/9、Ubuntu 18.04/20.04/22.04、Debian 10/11/12 等主流发行版。

2. 加固前的准备工作

加固是高风险操作,配置错误可能导致服务器无法登录或服务中断。操作前必须完成以下准备:

2.1 备份当前配置

 

# 备份所有即将修改的配置文件
mkdir /opt/security-hardening-backup-$(date +%Y%m%d)
cd /opt/security-hardening-backup-$(date +%Y%m%d)

# 备份系统关键配置
cp /etc/ssh/sshd_config ./sshd_config.bak
cp /etc/pam.d/system-auth ./system-auth.bak
cp /etc/login.defs ./login.defs.bak
cp /etc/fstab ./fstab.bak
cp /etc/sysctl.conf ./sysctl.conf.bak
cp /etc/rsyslog.conf ./rsyslog.conf.bak
cp /etc/hosts.allow ./hosts.allow.bak
cp /etc/hosts.deny ./hosts.deny.bak
cp /etc/passwd ./passwd.bak
cp /etc/shadow ./shadow.bak
cp /etc/group ./group.bak
cp -r /etc/iptables* ./iptables.bak 2>/dev/null || true

# 备份 systemd 服务列表
systemctl list-units --type=service --all > services-backup.txt

# 记录当前运行的进程和网络连接(基线)
ps auxf > processes-backup.txt
netstat -tulnp > listening-ports-backup.txt
ss -tulnp > ss-backup.txt

# 记录当前用户和权限
cat /etc/passwd > users-backup.txt
cat /etc/group > groups-backup.txt
getent shadow > shadow-backup.txt

echo"Backup completed. Files are in /opt/security-hardening-backup-$(date +%Y%m%d)"

 

2.2 创建云服务器快照(强烈建议)

云服务器(阿里云、腾讯云、AWS 等)支持创建快照,这一步不能省:

 

# 阿里云 CLI 创建快照(需要先安装 aliyun CLI 并配置 AK)
aliyun ecs CreateSnapshot --DiskId disk-xxx --Description "pre-security-hardening-$(date +%Y%m%d)"

# 腾讯云 CLI
# qcloudcli cvm CreateSnapshot --instanceId ins-xxx --snapshotName "pre-hardening-$(date +%Y%m%d)"

# AWS CLI
# aws ec2 create-snapshot --description "pre-hardening-$(date +%Y%m%d)" --volume-id vol-xxx

 

快照是服务器磁盘的完整副本,出问题可以回滚,比备份配置文件更保险。

2.3 准备紧急救援方式

确保你还有除了 SSH 以外的登录方式:

云控制台 VNC/远程登录(应急入口)

物理服务器使用 IPMI/iLO/iDRAC

提前准备一个可以通过云控制台执行的脚本

2.4 测试窗口

安全加固最好在维护窗口进行,确保:

业务低峰期,不会影响太多用户

有足够时间排查加固后的异常

有人值守,出问题能及时响应

已经通知相关方(业务方、Leader)

3. 账户与密码安全

3.1 检查是否有弱密码账户

 

# 列出所有系统账户(非登录、非服务账号除外)
awk -F: '{print $1, $3, $7}' /etc/passwd | grep -vE "(nologin|false|sync)" | head -50

# 检查是否有空密码账户
awk -F: '($2=="") {print $1}' /etc/shadow

# 检查密码策略
cat /etc/login.defs | grep -E "(PASS_MIN_LEN|PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_WARN_AGE)"

# 查看当前密码策略(CentOS/RHEL)
authconfig --test | grep password
# 或
pam_cracklib --test

 

3.2 设置密码策略

修改 /etc/login.defs(对新用户生效):

 

# /etc/login.defs
PASS_MAX_DAYS   90        # 密码最长使用 90 天
PASS_MIN_DAYS   7         # 密码最少使用 7 天才能修改
PASS_MIN_LEN    12        # 密码最小长度 12 位(注意:实际由 PAM 模块控制)
PASS_WARN_AGE   14        # 密码到期前 14 天警告

 

修改 PAM 模块密码策略(对现有用户也生效,CentOS/RHEL):

 

# /etc/security/pwquality.conf 或 /etc/pam.d/password-auth
# 找到 password requisite pam_pwquality.so 行,改为:
password requisite pam_pwquality.so try_first_pass local_users_only retry=3 
    minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 
    enforce_for_root

# 含义:
# minlen=12          最小长度 12 位
# dcredit=-1        至少包含 1 个数字(dcredit 负数表示"至少")
# ucredit=-1        至少包含 1 个大写字母
# lcredit=-1        至少包含 1 个小写字母
# ocredit=-1        至少包含 1 个特殊字符
# enforce_for_root  root 用户也强制执行

 

Ubuntu/Debian 中编辑 /etc/security/pwquality.conf 或 /etc/pam.d/common-password:

 

password requisite pam_pwquality.so retry=3 minlen=12 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1

 

3.3 锁定不应登录的系统账户

很多服务会创建系统账户,这些账户不应该用于登录:

 

# 锁定不需要登录的账户
for user in bin daemon news uucp games gnats smmsp nobody nfsnobody; do
    usermod -L $user 2>/dev/null && echo "Locked $user" || echo "$user not found or already locked"
done

# 检查是否还有账户是 /bin/bash 登录
awk -F: '{print $1, $7}' /etc/passwd | grep -E "bash$" | grep -v -E "^(root|admin|deploy|app):"

# 确保 root 账户不能通过 SSH 登录
# 这个在 SSH 加固部分会详细说

 

3.4 限制 su 命令使用

只允许特定用户使用 su 切换到 root:

 

# 在 /etc/pam.d/su 中添加(默认已有注释,取消注释即可)
# auth required pam_wheel.so use_uid

# 将信任的用户加入 wheel 组
usermod -aG wheel admin_user

# 验证 wheel 组配置
grep "^wheel" /etc/group

# 测试:非 wheel 组用户不能 su -
su - admin_user  # 先切换到普通用户
su - root        # 应该报错:Permission denied

 

3.5 踢出已登录的异常用户

 

# 查看当前登录用户
who
w
last

# 踢出异常登录(假设发现 hack user)
pkill -KILL -u hack_user

# 立即禁用该账户
usermod -L hack_user
usermod -s /sbin/nologin hack_user

 

4. SSH 安全加固

SSH 是服务器被入侵的最主要入口。大量攻击者用弱口令字典批量扫 SSH。SSH 加固是安全加固中最重要的一环。

4.1 修改 SSH 默认端口

SSH 默认监听 22 端口,全世界扫描器都在扫 22。改成高位端口能减少 99% 的扫描流量:

 

# 编辑 /etc/ssh/sshd_config
Port 22022  # 不要用 2222,有些扫描器也会扫

# 修改后重启 SSH
systemctl restart sshd

# 注意:修改端口后,后续 SSH 连接需要指定端口
ssh -p 22022 root@server_ip

# 防火墙放行新端口(稍后防火墙部分会讲)

 

风险提醒:

改完端口后确保当前 SSH 会话不断(新端口生效后再退出)。

修改端口后监控工具(如 ansible)需要同步更新。

高位端口(如 22022)可能与企业内网策略冲突,注意评估。

4.2 禁用 root 直接登录

root 是最高权限账户,禁用直接登录,强制使用普通用户 + sudo:

 

# /etc/ssh/sshd_config
PermitRootLogin no

# 确保有可用的 sudo 用户
useradd -m -s /bin/bash admin_user
usermod -aG wheel admin_user
echo "admin_user:Str0ngP@ssw0rd" | chpasswd

# 测试新用户可以 sudo
ssh admin_user@server_ip
sudo -l  # 应该显示 admin_user can run commands

 

4.3 使用密钥登录,禁止密码登录

密钥登录从根本上杜绝了暴力破解。密码登录即使再复杂,也是可被破解的:

 

# 在本地机器(你的笔记本/台式机)生成密钥对
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519_server

# 将公钥上传到服务器
ssh-copy-id -i ~/.ssh/id_ed25519_server.pub -p 22022 admin_user@server_ip

# 或者手动追加
# cat ~/.ssh/id_ed25519_server.pub | ssh -p 22022 admin_user@server_ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

# 修改 SSH 配置
# /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

# 重启 SSH
systemctl restart sshd

 

4.4 限制可登录用户和 IP

 

# /etc/ssh/sshd_config
AllowUsers admin_user deploy_user@10.0.0.0/8 admin_user@192.168.1.0/24

# 只允许特定组
AllowGroups wheel admin

# 限制 sshd 监听地址(只监听内网 IP,不监听公网)
ListenAddress 0.0.0.0  # 默认,建议改为内网地址
# ListenAddress 10.0.0.100

 

4.5 其他 SSH 安全参数

 

# /etc/ssh/sshd_config 添加以下内容
# 禁用空密码
PermitEmptyPasswords no

# 禁用 .rhosts 文件
IgnoreRhosts yes

# 禁用基于主机的认证
HostbasedAuthentication no

# 关闭 X11 转发(除非真的需要)
X11Forwarding no

# 关闭 TCP 转发(防止 SSH 被用作代理)
AllowTcpForwarding no

# 关闭 Agent 转发
AllowAgentForwarding no

# 设置空闲超时(客户端 10 分钟无操作自动断开)
ClientAliveInterval 600
ClientAliveCountMax 2

# 限制最大认证尝试次数
MaxAuthTries 3

# 设置登录成功后的 Banner(可选,起到威慑作用)
PrintMotd yes
PrintLastLog yes

# SSH 协议版本(必须为 2)
Protocol 2

 

4.6 使用 fail2ban 防止暴力破解

即使做了以上加固,攻击者仍可能尝试密钥破解或内部账户弱口令。fail2ban 能自动封禁频繁尝试登录的 IP:

 

# CentOS/RHEL 安装
yum install -y epel-release
yum install -y fail2ban

# Ubuntu/Debian 安装
apt install -y fail2ban

# 配置 fail2ban(不修改 /etc/fail2ban/jail.conf,创建 local 覆盖文件)
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600           # 封禁 1 小时
findtime = 600           # 10 分钟内
maxretry = 3             # 失败 3 次即封禁
ignoreip = 127.0.0.1/8 10.0.0.0/8 192.168.0.0/16  # 不封禁这些 IP

[sshd]
enabled = true
port = 22022
filter = sshd
logpath = /var/log/secure  # CentOS/RHEL
# logpath = /var/log/auth.log  # Ubuntu/Debian
maxretry = 3

[sshd-ddos]
enabled = true
port = 22022
filter = sshd-ddos
logpath = /var/log/secure
maxretry = 10
EOF

# 启动并设置开机自启
systemctl enable fail2ban
systemctl start fail2ban

# 查看被封禁的 IP
fail2ban-client status sshd
fail2ban-client banned sshd

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

 

4.7 验证 SSH 加固效果

 

# 检查当前 SSH 配置是否正确
sshd -t

# 查看 SSH 监听端口
ss -tulnp | grep sshd

# 查看谁曾经登录过(用于审计)
last
lastlog | head -50

# 查看 SSH 失败登录记录
# CentOS/RHEL
cat /var/log/secure | grep -i "failed password" | tail -50
# Ubuntu/Debian
cat /var/log/auth.log | grep -i "failed password" | tail -50

# 查看 fail2ban 日志
tail -100 /var/log/fail2ban.log

 

5. 文件系统权限

5.1 设置 /tmp、/var/tmp 权限

攻击者经常利用 /tmp 和 /var/tmp 写入后门文件。应该将这些目录设置为 noexec、nosuid、nodev:

 

# 查看当前 /tmp 挂载选项
mount | grep /tmp

# 如果 /tmp 是独立分区,添加安全挂载选项
# 编辑 /etc/fstab
UUID=xxxx-xxxx-xxxx /tmp ext4 defaults,noexec,nosuid,nodev 0 0

# 如果 /tmp 不是独立分区(大多数云服务器默认),创建一个独立的 /tmp 分区
# 先创建 2G 大小的镜像文件
dd if=/dev/zero of=/var/tmp.mount bs=1M count=2048
mkfs.ext4 /var/tmp.mount

# 备份原 /tmp 内容
cp -a /tmp /tmp.bak

# 挂载新分区
mount --bind /var/tmp.mount /tmp

# 恢复内容
cp -a /tmp.bak/* /tmp/

# 设置权限
chmod 1777 /tmp

# 添加到 /etc/fstab 确保重启后生效
echo"/var/tmp.mount /tmp ext4 defaults,bind,noexec,nosuid,nodev 0 0" >> /etc/fstab

 

5.2 限制系统内核模块加载

防止攻击者加载恶意内核模块:

 

# 禁用模块加载能力
echo"install usb-storage /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install bluetooth /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install freevxfs /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install jffs2 /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install hfs /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install hfsplus /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install squashfs /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install udf /bin/true" >> /etc/modprobe.d/no-usb.conf
echo"install dccp /bin/true" >> /etc/modprobe.d/no-usb.conf

 

5.3 设置 umask 默认值

收紧用户的默认文件创建权限:

 

# /etc/profile 中设置更严格的 umask
# 找到 umask 那行,改为:
umask 0027  # 默认创建文件 640,目录 750

# /etc/csh.cshrc 中也修改:
set umask 0027

 

5.4 关键文件权限检查

 

# 检查关键文件权限
chmod 644 /etc/passwd
chmod 000 /etc/shadow      # shadow 文件只有 root 可读写
chmod 644 /etc/group
chmod 640 /etc/gshadow
chmod 600 /etc/crontab
chmod 600 /etc/anacrontab
chmod 700 /var/spool/cron
chmod 600 /etc/ssh/sshd_config
chmod 644 /etc/hosts.allow
chmod 644 /etc/hosts.deny
chmod 600 /etc/rsyslog.conf
chmod 700 /etc/cron.d
chmod 700 /etc/cron.daily
chmod 700 /etc/cron.hourly
chmod 700 /etc/cron.monthly
chmod 700 /etc/cron.weekly

 

6. 网络层加固

6.1 防火墙基础配置

使用 iptables 或 firewalld 限制入站流量。原则:默认拒绝所有,只放行必要的端口。

使用 firewalld(CentOS/RHEL 7+):

 

# 查看当前规则
firewall-cmd --list-all
firewall-cmd --list-ports
firewall-cmd --list-services

# 放行必要端口
firewall-cmd --permanent --add-port=22022/tcp    # SSH
firewall-cmd --permanent --add-port=80/tcp        # HTTP
firewall-cmd --permanent --add-port=443/tcp       # HTTPS
firewall-cmd --permanent --add-port=3306/tcp      # MySQL(如果需要从内网直接访问)
firewall-cmd --permanent --add-port=6379/tcp      # Redis(仅内网)

# 放行必要服务
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=ssh

# 禁止 Ping(防扫描)
firewall-cmd --permanent --add-icmp-block=echo-request

# 默认拒绝所有入站
firewall-cmd --set-default-zone=drop

# 只允许特定来源 IP 访问 SSH
firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/8
firewall-cmd --permanent --zone=trusted --add-source=192.168.0.0/16
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="your_office_ip/32" port port="22022" protocol="tcp" accept'

# 重载防火墙
firewall-cmd --reload

# 查看生效规则
firewall-cmd --list-all

 

使用 iptables(Ubuntu/Debian 或 CentOS/RHEL 6):

 

# 保存现有规则
iptables-save > /opt/iptables-backup-$(date +%Y%m%d).rules

# 编写规则脚本
cat > /opt/iptables-rules.sh << 'EOF'
#!/bin/bash
# 清空现有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X

# 默认拒绝所有入站
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 允许已建立连接的包
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许 SSH(改成你的端口)
iptables -A INPUT -p tcp --dport 22022 -j ACCEPT

# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 允许 Ping
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# 允许来自内网的连接
iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT

# 记录被拒绝的包(可选,方便排查)
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables DROP: " --log-level 4

# 保存规则
iptables-save > /etc/iptables/rules.v4
EOF

chmod +x /opt/iptables-rules.sh
/opt/iptables-rules.sh

# 查看规则
iptables -L -n -v

 

6.2 内核网络参数加固

修改 /etc/sysctl.conf,收紧网络层面的安全参数:

 

# /etc/sysctl.conf 添加或修改以下内容

# 关闭 IP 转发(除非服务器做路由器)
net.ipv4.ip_forward = 0

# 关闭数据包转发(防止服务器成为路由跳板)
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.default.forwarding = 0

# 禁用源路由包(防止 IP 伪装攻击)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# 关闭 ICMP 重定向
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# 开启 SYN Flood 防护
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096

# 禁止 ICMP Ping 广播
net.ipv4.icmp_echo_ignore_broadcasts = 1

# 忽略 ICMP Ping(可选,影响监控探活)
net.ipv4.icmp_echo_ignore_all = 0  # 建议保持 0,方便自己监控

# 禁止路由记录( traceroute 使用)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# TIME_WAIT 快速回收
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1

# 最大文件描述符
fs.file-max = 6553600

# 应用配置
sysctl -p

 

6.3 限制核心文件访问

 

# 禁止通过 ICMP 路由追踪(防止攻击者探测网络拓扑)
echo 1 > /proc/sys/net/ipv4/conf/all/accept_source_route
# 上面已经在 sysctl.conf 中设置

# 禁止修改路由表
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 0 > /proc/sys/net/ipv6/conf/all/accept_redirects

 

7. 服务安全

7.1 禁用不必要的服务

服务器上不需要的服务越多,攻击面越大。检查并禁用不需要的服务:

 

# 查看所有开机自启服务
systemctl list-unit-files --type=service --state=enabled

# 查看正在运行的服务
systemctl --type=service --state=running

# 常见需要检查和禁用的服务(按需调整)
# telnet-server:明文传输,应禁用
systemctl disable telnet.socket 2>/dev/null
systemctl stop telnet.socket 2>/dev/null

# vsftpd:如果不用 FTP 就禁用
systemctl disable vsftpd 2>/dev/null

# sendmail:邮件服务,如不需要就禁用
systemctl disable sendmail 2>/dev/null

# postfix:如果不用邮件就禁用
systemctl disable postfix 2>/dev/null

# cups:打印服务,云服务器不需要
systemctl disable cups 2>/dev/null

# dovecot:如果不用 IMAP/POP3 就禁用
systemctl disable dovecot 2>/dev/null

# nfslock/nfs:如果不做 NFS 文件共享就禁用
systemctl disable nfs-lock 2>/dev/null
systemctl disable nfs 2>/dev/null

# rpcbind:NFS 依赖的服务
systemctl disable rpcbind 2>/dev/null

# bluetooth:云服务器不需要蓝牙
systemctl disable bluetooth 2>/dev/null
systemctl stop bluetooth 2>/dev/null

# 确认没有不需要的服务在运行
systemctl --type=service --state=running | grep -v -E "(sshd|cron|rsyslog|systemd|dbus|network|polkit|irqbalance|sssd)"

 

7.2 查看监听端口

确保服务器上只有你知道的端口在监听:

 

# 查看所有监听端口
ss -tulnp
# 或
netstat -tulnp

# 特别关注以下几点:
# 1. 是否有不明服务监听在高危端口(如 4444、5555 是 Metasploit 常用端口)
# 2. 是否有服务监听在 0.0.0.0(应该大部分服务只监听 127.0.0.1 或内网 IP)
# 3. 是否有服务监听在公网 IP 但不应该暴露(如数据库、Redis)

# 示例:检查非预期的监听
ss -tulnp | grep -v -E "(22|80|443|22022)"

 

7.3 隐藏服务版本信息

很多服务会在 banner 中显示版本号,攻击者利用版本信息查找对应漏洞:

 

# Nginx 版本隐藏(在 nginx.conf 中)
server_tokens off;

# MySQL 版本隐藏
# MySQL 5.7+: 在 my.cnf [mysqld] 中
# MySQL 8.0+: 不需要单独配置,默认不显示版本

# SSH 版本(在 /etc/ssh/sshd_config 中)
# SSH 默认 banner 无法完全隐藏,但可以降级攻击者信心
# 编辑 /etc/ssh/sshd_config
# 找到 #Banner none,改为:
# Banner /etc/ssh/banner
# 创建自定义 banner 文件
echo"Welcome to Secure Server" > /etc/ssh/banner

# Redis 默认监听 6379,且无认证
# 如果必须暴露在外网,必须设置密码
# /etc/redis/redis.conf
# requirepass your_strong_password_here
# bind 127.0.0.1
# rename-command FLUSHDB ""   # 禁用 FLUSHDB 命令
# rename-command FLUSHALL ""   # 禁用 FLUSHALL 命令
# rename-command KEYS ""       # 禁止 KEYS 命令(或用 SCAN 替代)

 

8. SELinux/AppArmor 加固

8.1 CentOS/RHEL:启用 SELinux

SELinux 是内核级的访问控制系统,能限制被入侵后的横向移动:

 

# 检查 SELinux 状态
getenforce
sestatus

# 如果是 Permissive,改为 Enforcing
# 编辑 /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted

# 临时生效
setenforce 1

# SELinux 常用管理命令
# 查看文件安全上下文
ls -Z /var/www/html
ps auxZ | grep nginx

# 修改目录安全上下文(Web 目录迁移后常用)
semanage fcontext -a -t httpd_sys_content_t "/var/www(/.*)?"
restorecon -Rv /var/www

# 允许服务使用非标准端口
semanage port -a -t http_port_t -p tcp 8080

 

风险提醒:

开启 SELinux 前要确保熟悉常见应用的配置,否则会导致服务启动失败。

如果业务应用在 Permissive 模式下运行正常再切换到 Enforcing。

遇到权限问题时,优先用 ausearch、sealert 查看 SELinux 拒绝日志,而不是直接降级到 Permissive。

8.2 Ubuntu/Debian:配置 AppArmor

 

# 检查 AppArmor 状态
aa-status

# 查看所有配置文件的加载状态
apparmor_status

# AppArmor 配置文件在 /etc/apparmor.d/
# 禁用不必要配置的激进模式(如果确认某服务不需要网络访问)
# 编辑 /etc/apparmor.d/usr.sbin.httpd 或对应的 Nginx 配置文件
# 限制网络访问:
# network inet tcp,
# deny network inet6 tcp,

 

9. 日志审计

9.1 配置日志集中收集

服务器被黑后,攻击者第一件事往往是清理日志。日志必须集中到远程服务器:

 

# rsyslog 客户端配置,将日志发送到远程日志服务器
# /etc/rsyslog.conf 添加:
*.* @@log-server.example.com:514

# 或使用 UDP(性能好但可能丢包):
*.* @log-server.example.com:514

# CentOS/RHEL 重启 rsyslog
systemctl restart rsyslog

# Ubuntu/Debian
systemctl restart rsyslog

 

9.2 配置审计日志

Linux 审计守护进程(auditd)记录系统调用,是取证的重要依据:

 

# 安装 auditd
yum install -y audit  # CentOS/RHEL
apt install -y auditd  # Ubuntu/Debian

# 启动并设置开机自启
systemctl enable auditd
systemctl start auditd

# 配置审计规则
# /etc/audit/rules.d/audit.rules 或 /etc/audit/audit.rules
# 记录所有修改 /etc/passwd、/etc/shadow、/etc/group 的操作
-w /etc/passwd -p wa -k identity_changes
-w /etc/shadow -p wa -k identity_changes
-w /etc/group -p wa -k identity_changes
-w /etc/gshadow -p wa -k identity_changes

# 记录所有 sudo 命令
-w /usr/bin/sudo -p x -k privileged_commands

# 记录 SSH 登录事件
-w /etc/ssh/sshd_config -p wa -k ssh_config_changes
-a always,exit -F arch=b64 -S sshd -F auid>=1000 -F auid!=4294967295 -k sshd_login

# 记录网络配置变更
-w /etc/sysconfig/network -p wa -k network_changes
-w /etc/sysconfig/network-scripts/ -p wa -k network_changes

# 记录敏感文件的执行
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/wget -k network_download
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/curl -k network_download
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/python* -k interpreter_usage
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/perl -k interpreter_usage

# 使规则生效
augenrules --load

# 查看审计日志
ausearch -k identity_changes | head -20
ausearch -k sshd_login | head -20

# 查看最近的审计事件
aureport --latest-events
aureport --auth | head -30

 

9.3 日志文件完整性校验

攻击者可能修改日志掩盖入侵痕迹。使用 AIDE 或 Tripwire 做文件完整性检查:

 

# 安装 AIDE
yum install -y aide  # CentOS/RHEL
apt install -y aide   # Ubuntu/Debian

# 初始化 AIDE 数据库(第一次运行)
aide --init

# 移动初始数据库
mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# 定期检查(手动)
aide --check

# 更新数据库(在确认系统正常后)
aide --update
mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# 每天自动检查(加入 crontab)
echo"0 3 * * * /usr/sbin/aide --check" >> /etc/crontab

 

10. Rootkit 和后门检测

10.1 使用 rkhunter 检查 Rootkit

 

# 安装 rkhunter
yum install -y rkhunter  # CentOS/RHEL
apt install -y rkhunter  # Ubuntu/Debian

# 更新特征库
rkhunter --update

# 执行检查
rkhunter --check --sk --rwo

# 关键检查项:
# - 检查文件系统中的隐藏文件
# - 检查常见的 Rootkit 特征
# - 检查可疑的 LKM(Loadable Kernel Module)
# - 检查网络连接
# - 检查系统命令是否被替换

 

10.2 使用 chkrootkit 检查

 

# 安装 chkrootkit
yum install -y chkrootkit  # CentOS/RHEL
apt install -y chkrootkit  # Ubuntu/Debian

# 运行检查
chkrootkit | grep -v -E "(Checking|not found|Nothing found|Not tested)"

# 查看网络相关
chkrootkit -r

# 注意:有些安全软件会误报
# 如有误报,查看具体命令是否被替换
which ls
rpm -qf /bin/ls
md5sum /bin/ls

 

10.3 检查异常进程和网络连接

 

# 查看所有进程(包括隐藏进程)
ps auxf
ps -ef

# 查看网络连接和对应进程
ss -tulnp
netstat -antp

# 检查是否有进程监听异常端口
ss -tulnp | grep -v -E "(22|80|443|22022)"

# 检查是否有到外网的异常连接(被控服务器会向外发送数据)
ss -tnp | grep -v -E "(10.|192.168.|172.(1[6-9]|2[0-9]|3[01]).)"

# 检查是否有进程在运行但 ps 看不到(高级 Rootkit 特征)
# 如果 ps 和 /proc 里看到进程但 ss/netstat 看不到监听端口,说明可能是后门
for pid in $(ls /proc | grep '^[0-9]'); do
    if [ -f /proc/$pid/cmdline ]; then
        echo"PID $pid: $(cat /proc/$pid/cmdline | tr '�' ' ')"
    fi
done | head -50

# 检查 crontab 是否有可疑任务
crontab -l
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /var/spool/cron/
cat /etc/cron.d/* 2>/dev/null

 

10.4 检查 SSH authorized_keys 是否被篡改

 

# 查看所有用户的 SSH authorized_keys(可能被添加了攻击者的公钥)
for user in $(cut -d: -f1 /etc/passwd); do
    keyfile="/home/$user/.ssh/authorized_keys"
    if [ -f "$keyfile" ]; then
        echo"=== $user authorized_keys ==="
        cat "$keyfile"
    fi
done

# 检查 root 的 authorized_keys(root 直接登录已被禁用,但 keys 本身也可能被篡改)
if [ -f /root/.ssh/authorized_keys ]; then
    echo"=== root authorized_keys ==="
    cat /root/.ssh/authorized_keys
fi

# 检查 SSH 登录记录(看是否有异常登录时间/IP)
last | head -30
lastlog | grep -v "Never"

 

11. 内核参数加固

11.1 限制进程资源使用

防止单个进程耗尽系统资源导致 DoS:

 

# /etc/security/limits.conf 添加:
# 限制最大进程数
*               soft    nproc           4096
*               hard    nproc           8192

# 限制最大文件描述符
*               soft    nofile          65536
*               hard    nofile          65536

# 限制 core dump 大小(防止泄露敏感内存数据)
*               soft    core            0
*               hard    core            0

# 限制普通用户可以使用的内存
# 这个需要根据实际内存调整
# @student       hard    memlock        2097152

 

11.2 禁止 ICMP 重定向

 

# 在 /etc/sysctl.conf 中已经配置
# 再次确认
grep -E "icmp_(echo_ignore_all|accept_redirects)" /etc/sysctl.conf

# 立即生效
sysctl -p

 

11.3 禁用不必要的文件系统

减少内核支持的攻击面:

 

# /etc/modprobe.d/disable-filesystems.conf
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
install vfat /bin/true

 

12. 软件更新与漏洞管理

12.1 配置自动安全更新

 

# CentOS/RHEL:使用 yum-cron
yum install -y yum-cron

# 编辑 /etc/yum/yum-cron.conf
update_cmd = security
update_messages = yes
download_updates = yes
apply_updates = yes

systemctl enable yum-cron
systemctl start yum-cron

# Ubuntu/Debian:使用 unattended-upgrades
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
# 选择 "Yes" 启用自动安全更新

# 查看自动更新日志
tail -50 /var/log/yum.log  # CentOS
tail -50 /var/log/unattended-upgrades/  # Ubuntu

 

12.2 定期漏洞扫描

 

# 安装 OpenVAS 或使用 yum/cve-check(CentOS)
yum install -y yum-plugin-security
yum updateinfo list security

# Ubuntu
apt install -y unattended-upgrades
/usr/lib/update-notifier/update-notifier.notify-matches-available-security-updates

# 如果有商业漏洞扫描器(Qualys、Rapid7),定期扫描生产服务器
# 扫描前通知相关方,选择维护窗口

 

12.3 内核升级

内核漏洞危害极大,但升级内核有风险(可能影响驱动、业务依赖):

 

# CentOS/RHEL 查看可用内核
grub2-mkconfig -o /boot/grub2/grub.cfg
awk -F' '/menuentry/ {print $2}' /boot/grub2/grub.cfg

# 安装最新版内核
yum update -y kernel

# 重启后选择新内核
reboot

# 确认使用的是新内核
uname -r

# 设置默认启动项(防止误回滚)
grub2-set-default "CentOS Linux (6.14.1-1.el8.x86_64) 8 (Core)"
grub2-mkconfig -o /boot/grub2/grub.cfg

 

风险提醒:

内核升级必须通过测试环境验证。

云服务器升级内核前确保有云控制台救援方式。

升级前记录当前内核版本和启动项,保留回滚能力。

13. 监控与告警

13.1 账户变更监控

 

# 监控 /etc/passwd、/etc/shadow、/etc/group 的变更
# 使用 auditd(前面已配置)记录变更
# 配合以下脚本每日比对

cat > /opt/check-accounts.sh << 'EOF'
#!/bin/bash
# 对比当日和昨日的账户数据

YESTERDAY=$(date -d "yesterday" +%Y%m%d)
TODAY=$(date +%Y%m%d)
BACKUP_DIR="/opt/security-hardening-backup"

if [ ! -f "$BACKUP_DIR/passwd.bak" ]; then
    echo"No baseline found"
    exit 1
fi

echo"=== Checking for new users ==="
diff <(sort /opt/security-hardening-backup/passwd.bak | cut -d: -f1) 
     <(sort /etc/passwd | cut -d: -f1) | grep "^>"

echo"=== Checking for removed users ==="
diff <(sort /opt/security-hardening-backup/passwd.bak | cut -d: -f1) 
     <(sort /etc/passwd | cut -d: -f1) | grep "^<"

echo"=== Checking for users with changed shells ==="
diff <(sort /opt/security-hardening-backup/passwd.bak | awk -F: '{print $1":"$7}') 
     <(sort /etc/passwd | awk -F: '{print $1":"$7}') | grep "^>"

echo"=== Checking for UID 0 users ==="
awk -F: '($3==0) {print $1}' /etc/passwd
EOF

chmod +x /opt/check-accounts.sh

# 加入 crontab 每日检查
echo"0 6 * * * root /opt/check-accounts.sh" >> /etc/crontab

 

13.2 新增网络连接监控

 

# 监控是否有新增监听端口(可能后门监听)
cat > /opt/check-ports.sh << 'EOF'
#!/bin/bash
YESTERDAY_PORTS="/var/tmp/listening-ports-backup.txt"
TODAY_PORTS="/var/tmp/listening-ports-$(date +%Y%m%d).txt"

ss -tulnp > "$TODAY_PORTS"

if [ -f "$YESTERDAY_PORTS" ]; then
    echo"=== NEW listening ports ==="
    diff "$YESTERDAY_PORTS""$TODAY_PORTS" | grep "^>" || echo"None"
    echo"=== REMOVED listening ports ==="
    diff "$YESTERDAY_PORTS""$TODAY_PORTS" | grep "^<" || echo"None"
fi

cp "$TODAY_PORTS""$YESTERDAY_PORTS"
EOF

chmod +x /opt/check-ports.sh

 

13.3 Prometheus + Alertmanager 告警体系

 

# node_exporter 采集系统指标
# 安装 node_exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvf node_exporter-1.7.0.linux-amd64.tar.gz
mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/

# 创建 systemd 服务(启用 textfile collector 用于自定义指标)
cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
ExecStart=/usr/local/bin/node_exporter --collector.textfile.directory=/var/lib/node_exporter/textfile_collector
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable node_exporter
systemctl start node_exporter

# 创建自定义指标采集脚本,统计监听端口数量
# 通过 ss -tuln 输出统计当前监听 TCP/UDP 端口数,用于检测被控后新增监听端口
mkdir -p /var/lib/node_exporter/textfile_collector
cat > /usr/local/bin/node_sock_listen.sh << 'SCRIPT'
#!/bin/bash
OUTFILE="/var/lib/node_exporter/textfile_collector/node_sock_listen.prom"

# 统计当前监听中的 TCP 端口数量(排除回环和监听状态为空的行)
TCP_LISTEN=$(ss -tuln | grep -c "LISTEN" || echo 0)

# 统计当前监听中的 UDP 端口数量
UDP_LISTEN=$(ss -uuln | grep -c "UNCONN" || echo 0)

# 输出 Prometheus textfile 格式
cat > "${OUTFILE}.tmp" << EOF
# HELP node_sock_listen_count Number of listening sockets by protocol
# TYPE node_sock_listen_count gauge
node_sock_listen_count{protocol="tcp"} ${TCP_LISTEN}
node_sock_listen_count{protocol="udp"} ${UDP_LISTEN}
EOF
mv "${OUTFILE}.tmp""${OUTFILE}"
SCRIPT

chmod +x /usr/local/bin/node_sock_listen.sh

# 加入 crontab,每分钟执行一次
echo"* * * * * root /usr/local/bin/node_sock_listen.sh" >> /etc/crontab

# 手动执行一次测试
/usr/local/bin/node_sock_listen.sh
cat /var/lib/node_exporter/textfile_collector/node_sock_listen.prom

# 关键告警规则(Prometheus rule file)
# /etc/prometheus/rules.yml
groups:
- name: security
  rules:
# SSH 登录失败过多(需要部署 prometheus/sshd_exporter 并在 sshd 配置中启用 SyslogFacility AUTHPRIV)
  - alert: SSHBruteForce
    expr: rate(sshd_failed_authentication_total[5m]) > 10
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "SSH brute force detected"
      description: "More than 10 failed SSH auth per 5min from {{ $labels.instance }}"

# 新增监听端口(被控特征)
# 通过 node_exporter 的 textfile collector 暴露 ss -tuln 统计的监听端口数
# 自定义采集脚本(见 13.3 节)生成 node_sock_listen_count 指标
  - alert: NewListeningPort
    expr: count by (instance) (node_sock_listen_count) > on(instance) count by (instance) (node_sock_listen_count offset 1h)
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "New listening port detected on {{ $labels.instance }}"

 

14. 安全加固后的验证

完成加固后,必须进行验证:

14.1 加固验证清单

 

# SSH 配置验证
sshd -t
ssh -p 22022 -o PreferredAuthentications=password -o PubkeyAuthentication=no admin_user@127.0.0.1
# 应该报错:Permission denied (password refused 或直接拒绝连接)

# 密钥登录应该成功
ssh -p 22022 -i ~/.ssh/id_ed25519_server.pub admin_user@127.0.0.1

# root 登录应该失败
ssh -p 22022 root@127.0.0.1
# 应该报错:Permission denied

# 防火墙验证
# 从外部 IP 访问非白名单端口应该被拒绝
# 从白名单 IP 访问应该正常

# 文件权限验证
ls -la /etc/shadow  # 应该显示 ----------

# SELinux 验证(CentOS)
getenforce  # 应该显示 Enforcing

# fail2ban 验证
fail2ban-client status sshd
# 应该显示监狱状态和规则

# 服务禁用验证
systemctl status telnet.socket  # 应该显示 inactive
systemctl status bluetooth  # 应该显示 inactive

 

14.2 记录加固报告

每次加固完成,必须输出加固报告,包含:

加固时间、人员

修改前的配置备份路径

每项加固的具体操作

验证结果

遗留风险和后续计划

 

cat > /opt/security-hardening-report-$(date +%Y%m%d).txt << 'EOF'
安全加固报告
====================
日期: $(date +%Y-%m-%d)
操作人: admin_user
服务器: $(hostname) / $(curl -s ifconfig.me || echo"N/A")

一、加固项目
---------
1. SSH 安全
   - 端口: 22 -> 22022
   - 禁用 root 登录: yes
   - 密钥登录: yes
   - fail2ban: enabled
2. 防火墙
   - firewalld: enabled
   - 默认策略: drop
   - 放行端口: 22022, 80, 443
3. 账户安全
   - 密码策略: minlen=12, dcredit=-1, ...
   - wheel 组限制: enabled
   - 空密码账户: 0
4. SELinux: Enforcing (CentOS)
5. 内核参数: 已加固(sysctl.conf)
6. 日志审计: auditd enabled, rsyslog forwarded

二、验证结果
---------
- [x] SSH 配置语法正确
- [x] root 无法登录
- [x] fail2ban 运行正常
- [x] firewall-cmd 规则生效
- [x] 关键文件权限正确
- [ ] 从外部 IP 实际测试(待执行)

三、遗留风险
---------
- [ ] 云平台控制台登录 MFA 未配置
- [ ] 数据库 Redis 密码需要定期轮换

四、下次加固计划
-------------
- 添加 AIDE 文件完整性检查
- 配置 OSSEC 主机入侵检测
EOF

 

15. 总结

安全加固不是一次性工作,而是持续的过程。核心原则要记住:

最小权限原则: 不需要的端口就不开,不需要的服务就禁用,不需要的功能就关闭。每个开放都应该是明确有理由的。

纵深防御原则: 每一层防线失效后还有下一层。SSH 密钥登录失效还有 fail2ban 封禁,防火墙失效还有 SELinux 限制,后门植入还有 auditd 记录。

可审计原则: 一切操作皆有记录,所有变更可追溯。日志不仅要在,而且不能被篡改。定期检查审计日志比被攻击后才发现要好得多。

加固后要验证: 配置改了不代表生效,要实际测试。每做一项加固,马上验证是否生效、是否影响正常功能。

保持更新: 漏洞每天都在被发现,系统每天都在运行新的攻击。安全加固是持续工作,不是做完一次就能高枕无忧。

最后提醒:加固是为了提高攻击成本,而不是让服务器完全不被攻破。再完善的加固也无法保证 100% 安全,所以日志监控、入侵检测、应急响应能力同样重要。防守是体系,加固只是第一步。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分