Shell实战:生产可用Web恶意IP自动检测脚本

📌 前言

💡 运维痛点:网站突然卡顿、CPU 100%,多半是 CC/DOS 恶意IP高频访问。人工手动翻日志统计IP效率极低,攻击爆发后几小时才能发现,极易造成网站宕机。

本文提供一套直接上线生产、零第三方依赖的Shell巡检脚本,融合:文本三剑客awk/sort/uniq、if条件判断、命令替换、日志持久化、邮件告警全套语法。
全程零基础友好,复制粘贴跟着操作即可部署完成。

✅ 脚本完整实现能力

  • 🟢 自动解析 Nginx/Apache 标准 access.log,提取所有客户端访问IP
  • 🟢 自动统计单IP当日访问总量,自动抓取访问频次最高IP
  • 🟢 自定义攻击阈值(默认单IP访问超10000次判定恶意攻击)
  • 🟢 攻击触发双留存:本地永久告警日志 + 自动发送邮件通知管理员
  • 🟢 配合 crontab 定时巡检,实现7×24小时无人值守安全监控
  • 🟢 兼容 CentOS7 / Rocky Linux / RHEL 主流服务器系统

⚠️ 前置环境准备(必看,缺少任意一项脚本无法告警)

  1. 服务器提前部署 mailx + sendmail 邮件服务
  2. 网站存在标准访问日志 access.log(Nginx默认路径 /var/log/nginx/access.log
  3. 服务器外网可正常发送邮件,防火墙放行465 SMTP端口
  4. 基础操作:vim编辑文件、脚本赋权、crontab定时任务基础认知

一、核心前置知识点速学

1.1 日志统计流水线核心命令

执行流程文字图示(纯文本,全平台兼容)

读取access.log日志 → awk提取第一列IP → sort -n IP排序 → uniq -c 统计每个IP访问次数 → sort -rn 按访问次数倒序 → head -1 取出访问最高IP

完整流水线代码:

awk '{print $1}' /var/log/nginx/access.log | sort -n | uniq -c | sort -rn | head -1

逐段功能拆解:

  1. awk '{print $1}' access.log:提取日志第一列客户端IP
  2. sort -n:IP数字排序,重点:uniq统计前必须排序,否则统计失效
  3. uniq -c:统计重复IP访问次数,输出格式:访问次数 IP地址
  4. sort -rn:按访问次数从高到低倒序,攻击IP排在最上方
  5. head -1:仅保留访问量最高一行数据

1.2 命令替换变量语法

核心语法:变量名=$(命令),将命令输出结果存入变量,脚本3个核心变量:

# 获取本机服务器主机名
server_name=$(cat /etc/hostname)
# 抓取最高访问次数(uniq输出第一列$1)
max_conn=$(awk流水线 | awk '{print $1}')
# 抓取攻击IP地址(uniq输出第二列$2)
attack_ip=$(awk流水线 | awk '{print $2}')

1.3 阈值判断规则

使用整数比较参数 -gt(大于),判断逻辑:
if [ 最高访问次数 -gt 阈值 ] → 判定恶意攻击,触发邮件告警

  • 小型站点推荐阈值:5000
  • 中型站点默认阈值:10000
  • 高并发业务阈值:30000

1.4 配套工具功能速查表

命令 作用 脚本用途
date +%y年%m月%d日%H时%M分%S秒 生成中文时间戳 告警日志记录攻击发生时间
>> 追加写入文件 永久保存告警记录,不覆盖历史日志
mail -s "标题" 邮箱 发送系统邮件 攻击时推送告警给管理员

二、完整生产可用脚本 anti_dos_ip.sh

📝 脚本说明:所有可修改配置统一放在顶部,零基础无需改动下方逻辑代码,直接修改顶部变量即可适配自己服务器。

#!/bin/bash
# ==============================================
# 脚本名称:anti_dos_ip.sh
# 功能:自动检测Web访问日志恶意高频IP,超阈值日志记录+邮件告警
# 适用系统:CentOS / Rocky Linux
# 编写时间:2026-07-09
# ==============================================

########################### 【可自定义配置区域】###########################
# 🔹 网站访问日志路径,Nginx/Apache按需修改
LOG_PATH="/var/log/nginx/access.log"
# 🔹 告警日志持久化保存路径
WARN_LOG="/shell/log/anti-dos.log"
# 🔹 攻击访问阈值,超过该数值判定恶意IP
LIMIT_NUM=10000
# 🔹 管理员接收告警邮箱
ADMIN_MAIL="admin@189.cn"
##########################################################################

# 1. 自动创建日志目录,不存在则新建,避免写入报错
mkdir -p /shell/log/

# 2. 捕获基础信息存入变量
now_time=$(date +%y年%m月%d日%H时%M分%S秒)  # 中文时间戳
server_name=$(cat /etc/hostname)             # 服务器主机名

# 3. 日志统计流水线:提取IP、统计次数、取最高访问IP
ip_stat=$(awk '{print $1}' ${LOG_PATH} | sort -n | uniq -c | sort -rn | head -1)

# 拆分访问次数、攻击IP为独立变量
max_conn=$(echo ${ip_stat} | awk '{print $1}')
attack_ip=$(echo ${ip_stat} | awk '{print $2}')

# 4. 阈值条件判断逻辑
if [ ${max_conn} -gt ${LIMIT_NUM} ]; then
    # 组装完整告警文本
    warn_info="【攻击告警】服务器:${server_name} | 时间:${now_time} | 恶意IP:${attack_ip} | 当日访问次数:${max_conn},单IP访问超过阈值${LIMIT_NUM},疑似DOS/CC攻击!"
    
    # 写入本地告警日志
    echo ${warn_info} >> ${WARN_LOG}
    # 终端打印告警,手动执行时直观查看
    echo ${warn_info}
    # 发送告警邮件通知管理员
    echo ${warn_info} | mail -s "【紧急】服务器遭遇高频IP攻击告警" ${ADMIN_MAIL}
else
    # 无攻击时,记录正常巡检日志(不需要可删除本段)
    echo "【正常巡检】${now_time} 服务器${server_name}无异常IP,最高访问IP:${attack_ip},访问次数${max_conn}" >> ${WARN_LOG}
fi

2.1 分模块代码图示讲解(纯文字标注,替代图片图示)

模块① 头部自定义配置区

作用:

  1. #!/bin/bash:指定Bash解释器,脚本运行必备头部标识;
  2. 全部可变参数集中放置,新手只需要修改这一块,不用改动业务逻辑;
    修改示例:Apache日志只需替换 LOG_PATH="/var/log/httpd/access_log"

模块② 自动创建日志目录

mkdir -p /shell/log/

✅ 运行效果:目录不存在自动创建,已存在不会抛出报错,防止日志写入失败。

模块③ 基础信息变量捕获

now_time=$(date +%y年%m月%d日%H时%M分%S秒)
server_name=$(cat /etc/hostname)

输出示例:now_time=26年07月09日16时22分30秒
多服务器集群场景,通过主机名快速区分哪台机器发生攻击。

模块④ 核心IP统计流水线

ip_stat=$(awk '{print $1}' ${LOG_PATH} | sort -n | uniq -c | sort -rn | head -1)
max_conn=$(echo ${ip_stat} | awk '{print $1}')
attack_ip=$(echo ${ip_stat} | awk '{print $2}')

执行前后对比:

  • 执行前:access.log 成千上百行杂乱访问日志
  • 执行后输出示例:12650 110.23.45.67
    拆分结果:max_conn=12650(访问次数),attack_ip=110.23.45.67(攻击IP)

模块⑤ if阈值判断+告警逻辑

if [ ${max_conn} -gt ${LIMIT_NUM} ]; then
    # 告警逻辑
else
    # 正常巡检记录
fi

⚠️ 重点避坑:[ ] 括号左右内侧必须保留空格,少空格直接脚本报错!

  1. >> 追加写入日志:历史告警永久保存,用于事后溯源;
  2. 邮件标题带【紧急】标识,管理员可第一时间识别高危告警。

三、零基础完整部署步骤(分步图标注,新手跟着复制)

步骤1:创建脚本文件 📄

打开服务器终端,执行命令创建脚本

vim anti_dos_ip.sh

粘贴完整脚本代码,按 ESC,输入 :wq 保存退出。

步骤2:赋予脚本执行权限 🔐

Linux新建文本默认无执行权限,直接运行会报 Permission denied

chmod +x anti_dos_ip.sh

步骤3:手动测试脚本,验证功能 🧪

./anti_dos_ip.sh

两种运行结果区分:

  • 🟢 正常无攻击:终端无告警输出,日志文件写入正常巡检记录;
  • 🔴 存在恶意IP:终端打印告警文本,本地日志留存记录,管理员邮箱收到告警邮件。

步骤4:查看历史告警日志 📋

cat /shell/log/anti-dos.log

可查看全部巡检、攻击记录,攻击事件溯源必备。

步骤5:配置定时任务,生产自动巡检 ⏰

手动执行仅用于测试,生产环境配置定时任务,每小时自动巡检一次

  1. 编辑定时任务列表
crontab -e
  1. 写入定时规则(每小时整点执行)
0 * * * * /shell/anti_dos_ip.sh
  1. 查看已配置定时任务
crontab -l

定时格式说明:分 时 日 月 周0 * * * * = 每小时0分自动运行脚本


四、生产环境避坑指南

❌ 高频踩坑点+解决方案

  1. 日志路径错误,无法统计IP
    解决:核对Nginx/Apache真实日志路径,修改脚本顶部LOG_PATH变量

  2. 收不到告警邮件
    解决:提前部署mailx+sendmail,邮箱开启POP3/SMTP并获取授权码,防火墙放行465端口

  3. 脚本执行报括号语法错误
    解决:[ 变量 -gt 数值 ] 括号内侧左右必须留空格,无空格直接崩溃

  4. 定时任务不自动执行
    解决:脚本使用绝对路径,提前执行chmod +x授权,定时任务缺少终端环境变量

  5. 告警日志持续膨胀占满磁盘
    增加日志自动清理代码,放在脚本最底部:

# 自动删除30天前告警日志
find /shell/log -name "anti-dos.log" -mtime +30 -delete

五、脚本生产升级拓展方案 🚀

二次开发扩展功能,按需添加:

  1. 自动防火墙拉黑恶意IP:识别攻击IP后通过firewalld/iptables永久封禁IP,阻断流量;
  2. 多渠道告警:新增钉钉/企业微信机器人推送,不局限邮件通知;
  3. 告警防抖:1小时内同一IP重复攻击仅推送1次邮件,避免消息轰炸;
  4. 日志按日期分割:每日生成独立告警日志,防止单文件过大;
  5. 服务联动监控:搭配netstat检测Nginx服务,服务宕机同步推送故障告警。

六、全文总结

本案例是一套轻量化、零成本、开箱即用的服务器安全自动化脚本,无复杂第三方组件,零基础运维、后端开发、在校学生均可快速部署落地。

脚本整合文本三剑客、变量、条件判断、输出重定向、邮件告警、定时任务全套Shell核心知识点,全部落地真实生产安全场景。学会后可直接复用在服务器巡检工作中,替代人工手动分析日志,提前拦截CC/DOS攻击,大幅降低网站宕机风险。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐