首页 / 帮助文档 / ubuntu服务器自动化安全防护脚本搭建

ubuntu服务器自动化安全防护脚本搭建

Ubuntu服务器上线后如果不做主动加固,公网IP在几小时内就会被扫描器标记。与其每次手动敲命令封IP、改端口、查异常进程,不如直接部署一套自动化安全防护脚本,把常见攻击拦截在系统层之外。下面直接讲搭建思路、核心模块和可落地的脚本实现。

先明确脚本要解决哪些问题

自动化安全防护不是装一个杀毒软件就完事,它要覆盖几个高频风险点:SSH暴力破解、异常登录行为、恶意扫描、资源耗尽型攻击、已知漏洞服务暴露。脚本的核心逻辑是“检测—判断—处置—记录”,并且要能开机自启和定时执行,否则人工干预成本还是降不下来。

基础环境检查与依赖安装

Ubuntu服务器通常已经自带bash、iptables、awk、grep等基础工具,但部分模块需要额外安装。建议先执行:

sudo apt update
sudo apt install -y fail2ban ufw unattended-upgrades auditd rsyslog

其中fail2ban负责SSH和Web服务的暴力破解封禁,ufw作为iptables前端简化防火墙规则管理,unattended-upgrades用于自动安装安全更新,auditd记录关键文件变更和系统调用。不要用裸iptables写复杂规则,维护成本太高。

SSH暴力破解自动封禁模块

SSH是公网Ubuntu服务器被攻击的第一入口。fail2ban默认配置只监控/var/log/auth.log中的失败登录,但实际环境中攻击者会换端口、换用户名、用慢速爆破绕过频率限制。建议自定义jail规则:

[sshd]
enabled = true
port = 22,2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 300
bantime = 3600
backend = polling

这里把maxretry降到3次,findtime设为5分钟,意味着5分钟内失败3次就封禁1小时。同时监控多个SSH端口,防止攻击者探测到非标准端口后继续爆破。如果服务器只允许密钥登录,还可以在sshd_config中设置PasswordAuthentication no,从源头减少暴力破解面。

实时异常IP检测与自动封禁脚本

fail2ban依赖日志解析,存在延迟。对于已经建立连接的可疑IP,可以用脚本实时检查当前连接数和来源。下面这个脚本每分钟执行一次,统计单个IP对22端口的连接数,超过阈值直接加入ufw拒绝规则:

#!/bin/bash
THRESHOLD=5
LOGFILE="/var/log/ssh_guard.log"

netstat -tn 2>/dev/null | awk '$4 ~ /:22$/ {print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | while read COUNT IP; do
    if [ "$COUNT" -gt "$THRESHOLD" ] && [ -n "$IP" ]; then
        if ! ufw status | grep -q "$IP"; then
            ufw deny from "$IP" to any
            echo "$(date '+%Y-%m-%d %H:%M:%S') Blocked $IP due to $COUNT connections" >> "$LOGFILE"
        fi
    fi
done

将脚本保存为/usr/local/bin/ssh_guard.sh,赋予执行权限,并加入crontab每分钟运行。这个脚本比fail2ban更直接,适合应对短时间高并发的连接型攻击。

防火墙策略自动化部署

ufw默认规则是拒绝所有入站、允许所有出站,但很多管理员在配置时只开放了22端口,导致后续部署Web服务时忘记放行。建议用脚本统一管理端口开放策略,避免手工操作遗漏:

#!/bin/bash
# 重置防火墙
ufw --force reset

# 默认策略
ufw default deny incoming
ufw default allow outgoing

# 允许必要端口
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 2222/tcp

# 限制SSH连接速率
ufw limit 22/tcp
ufw limit 2222/tcp

# 启用防火墙
ufw --force enable

这个脚本可以放在服务器初始化流程中,每次变更端口策略时修改脚本重新执行,而不是手动敲ufw命令。注意ufw limit会限制连接速率,对SSH端口尤其有用,能显著降低爆破效率。

异常登录行为监控与告警

除了封禁IP,还要监控登录成功后的异常行为。比如一个从未登录过的IP突然在凌晨3点成功登录,或者一个用户从两个地理位置相距很远的IP同时登录。可以用脚本分析/var/log/auth.log中的Accepted记录,结合历史登录IP库进行判断:

#!/bin/bash
ALERT_EMAIL="admin@example.com"
LAST_IP_FILE="/var/log/last_login_ips.txt"

grep "Accepted" /var/log/auth.log | awk '{print $11}' | sort -u > /tmp/current_ips.txt

if [ -f "$LAST_IP_FILE" ]; then
    NEW_IPS=$(comm -13 "$LAST_IP_FILE" /tmp/current_ips.txt)
    if [ -n "$NEW_IPS" ]; then
        echo "New login IPs detected: $NEW_IPS" | mail -s "SSH Login Alert" "$ALERT_EMAIL"
    fi
fi

mv /tmp/current_ips.txt "$LAST_IP_FILE"

这个脚本每次执行时对比当前登录IP和历史IP列表,发现新IP就发送邮件告警。对于没有邮件服务的服务器,可以改用Webhook推送或写入日志文件供集中日志系统采集。

恶意扫描行为自动拦截

公网服务器每天都会收到大量端口扫描和路径探测请求。这些扫描流量虽然不一定直接造成破坏,但会消耗资源并暴露服务信息。可以用脚本分析Web服务器日志,对短时间内请求大量不存在路径的IP进行封禁:

#!/bin/bash
LOG_FILE="/var/log/nginx/access.log"
THRESHOLD=50
BLOCK_LOG="/var/log/scan_block.log"

awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -nr | while read COUNT IP; do
    if [ "$COUNT" -gt "$THRESHOLD" ] && [ -n "$IP" ]; then
        # 检查该IP是否请求了大量404页面
        SCAN_COUNT=$(grep "$IP" "$LOG_FILE" | grep " 404 " | wc -l)
        if [ "$SCAN_COUNT" -gt 20 ]; then
            if ! ufw status | grep -q "$IP"; then
                ufw deny from "$IP" to any
                echo "$(date '+%Y-%m-%d %H:%M:%S') Blocked scanner $IP with $SCAN_COUNT 404 requests" >> "$BLOCK_LOG"
            fi
        fi
    fi
done

这个脚本针对Nginx日志,统计每个IP的404请求数量。正常用户偶尔会访问到不存在的页面,但扫描器会在短时间内大量请求随机路径,404比例极高。将脚本加入crontab每10分钟执行一次即可。

资源耗尽型攻击防护

CC攻击和慢速连接攻击会让服务器CPU、内存或连接数飙升。除了在Web服务器层面配置限流,还可以用脚本监控系统负载,当负载超过阈值时自动触发应急防火墙规则:

#!/bin/bash
LOAD_THRESHOLD=10
MAX_CONN_PER_IP=20

LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
if [ "$(echo "$LOAD > $LOAD_THRESHOLD" | bc)" -eq 1 ]; then
    # 获取连接数最高的前20个IP
    netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -20 | while read COUNT IP; do
        if [ "$COUNT" -gt "$MAX_CONN_PER_IP" ] && [ -n "$IP" ]; then
            ufw deny from "$IP" to any
            echo "$(date '+%Y-%m-%d %H:%M:%S') High load block $IP with $COUNT connections" >> /var/log/load_guard.log
        fi
    done
fi

这个脚本需要安装bc用于浮点数比较。当系统1分钟负载超过10时,自动封禁连接数最多的前20个IP中超过阈值的部分。注意负载阈值要根据服务器实际配置调整,避免误封正常流量。

自动安全更新与漏洞修复

很多Ubuntu服务器被入侵是因为已知漏洞没有及时修补。unattended-upgrades可以自动安装安全更新,但默认配置可能不会自动重启相关服务。建议修改配置文件:

sudo dpkg-reconfigure -plow unattended-upgrades

选择“是”启用自动更新。然后编辑/etc/apt/apt.conf.d/50unattended-upgrades,确保以下选项开启:

Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

自动重启设为false是为了避免业务中断,但内核更新需要重启才能生效。对于非关键业务服务器,可以设置Automatic-Reboot为true并在凌晨自动重启。同时建议定期手动执行apt update && apt upgrade -y检查是否有遗漏的更新。

关键文件完整性监控

攻击者入侵后往往会修改系统文件、添加后门账户或替换关键二进制文件。auditd可以监控这些变更,但配置复杂。更简单的方式是用脚本定期计算关键文件的哈希值并对比:

#!/bin/bash
BASELINE_FILE="/var/log/file_baseline.txt"
CURRENT_FILE="/tmp/current_hashes.txt"
ALERT_LOG="/var/log/file_change_alert.log"

# 监控的关键文件列表
FILES=(
    "/etc/passwd"
    "/etc/shadow"
    "/etc/sudoers"
    "/etc/ssh/sshd_config"
    "/usr/bin/ssh"
    "/usr/sbin/sshd"
    "/etc/crontab"
    "/etc/rc.local"
)

for file in "${FILES[@]}"; do
    if [ -f "$file" ]; then
        sha256sum "$file" >> "$CURRENT_FILE"
    fi
done

if [ ! -f "$BASELINE_FILE" ]; then
    cp "$CURRENT_FILE" "$BASELINE_FILE"
    echo "Baseline created at $(date)" >> "$ALERT_LOG"
else
    DIFF=$(diff "$BASELINE_FILE" "$CURRENT_FILE")
    if [ -n "$DIFF" ]; then
        echo "File change detected at $(date):" >> "$ALERT_LOG"
        echo "$DIFF" >> "$ALERT_LOG"
        # 可选:发送告警邮件或Webhook
    fi
fi

rm -f "$CURRENT_FILE"

首次运行生成基线,后续每次执行对比哈希值。一旦发现关键文件被修改,立即记录并告警。这个脚本可以每天执行一次,也可以更频繁地运行。

整合为统一的安全防护脚本

将上述模块整合到一个主控脚本中,统一调度和管理。主控脚本负责调用各个子模块,并记录执行日志:

#!/bin/bash
# Ubuntu服务器自动化安全防护主控脚本
LOG_DIR="/var/log/security_guard"
mkdir -p "$LOG_DIR"

run_module() {
    local module_name="$1"
    local script_path="$2"
    echo "$(date '+%Y-%m-%d %H:%M:%S') Running $module_name..." >> "$LOG_DIR/main.log"
    if bash "$script_path" >> "$LOG_DIR/$module_name.log" 2>&1; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') $module_name completed successfully" >> "$LOG_DIR/main.log"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') $module_name failed" >> "$LOG_DIR/main.log"
    fi
}

# 执行各安全模块
run_module "ssh_guard" "/usr/local/bin/ssh_guard.sh"
run_module "scan_block" "/usr/local/bin/scan_block.sh"
run_module "load_guard" "/usr/local/bin/load_guard.sh"
run_module "file_monitor" "/usr/local/bin/file_monitor.sh"
run_module "login_alert" "/usr/local/bin/login_alert.sh"

将主控脚本加入crontab,根据各模块的执行频率需求设置不同的调度时间。例如SSH防护每分钟执行,扫描拦截每10分钟执行,文件监控每天执行一次。

日志轮转与存储优化

安全脚本会产生大量日志,如果不做轮转,磁盘很快会被写满。建议配置logrotate:

/var/log/security_guard/*.log {
    weekly
    rotate 4
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
}

将配置保存为/etc/logrotate.d/security_guard,每周轮转一次,保留4周压缩日志。对于高流量服务器,可以改为daily并减少保留份数。

部署后的验证与调优

脚本部署完成后,不要直接认为安全防护已经到位。需要模拟攻击场景验证效果:从另一台机器尝试SSH错误密码登录,观察fail2ban是否触发;用nmap扫描服务器端口,检查防火墙是否正常拦截;手动触发高负载脚本,确认封禁逻辑生效。同时检查/var/log/security_guard/目录下的日志,确保各模块正常运行且没有误报。

这套自动化安全防护脚本的核心价值在于把重复性的安全运维工作固化下来,让服务器在无人值守的情况下也能持续抵御常见攻击。实际部署时可以根据业务特点调整阈值和监控范围,但不要追求大而全,优先覆盖SSH爆破、恶意扫描和异常登录这三个最高频的风险点。