华为防火墙上传异常流量报警
代码功能概述
该代码主要用于从一个特定的防火墙设备获取网络流量报告,并根据流量数据进行警报通知。它涉及到对设备的两个主要操作:
- 获取流量报告(POST 请求):根据设定的时间范围和应用程序代码,从防火墙设备中请求流量报告。
- 发送警报通知:如果检测到某个用户的总流量超过 5000MB,则通过钉钉 Webhook 发送警报。
个人博客
个人博客直达地址
网站不断完善中里面拥有大量的脚本,并且源码完全开放 欢迎纯白嫖。关注公众私信可免费写脚本。
效果展示
使用方法
-
初始化 Redis 连接:
- 代码使用
redis.Redis
连接到 Redis 数据库,用于缓存处理过的数据。
- 代码使用
-
定义应用程序名称:
app_names
字典定义了一些应用程序代码与其名称的映射关系。
-
获取时间范围:
- 计算当前日期的开始和结束时间戳,以确定数据查询的时间范围。
-
发送 GET 请求获取基础数据:
- 发送 GET 请求到防火墙设备,获取基础的流量数据。
-
循环处理每个应用程序:
- 对每个应用程序代码,发送 POST 请求请求详细的流量数据。
-
处理和检查数据:
- 解析返回的流量数据,检查每个 IP 地址的流量。
- 如果某个 IP 地址的流量超过 5000MB,则通过钉钉 Webhook 发送警报通知。
-
缓存和控制警报发送:
- 使用 Redis 缓存已处理的数据,避免重复警报。
- 通过设置缓存过期时间来控制警报发送的频率。
注意事项
-
安全性:
- 代码中
verify=False
表示忽略 SSL 证书验证,这可能存在安全隐患。应确保使用正确的 SSL 证书或适当处理 SSL 验证。
- 代码中
-
防火墙 IP 地址:
url
和params
中的自己防火墙ip
应替换为实际的防火墙设备 IP 地址。
-
Web 应用服务:
- 确保钉钉 Webhook 的
access_token
是正确的,并且配置了 Webhook 地址。
- 确保钉钉 Webhook 的
-
Redis 配置:
r = redis.Redis(host='10.1.6.175', port=6379, db=0)
中的 Redis 地址和端口应根据实际环境进行配置。
-
错误处理:
- 代码对请求失败做了基本处理,但可能需要根据实际情况添加更多的错误处理和重试机制。
-
性能优化:
- 代码中对每个应用程序循环发送请求,可能会对性能产生影响。考虑优化请求发送和数据处理的逻辑。
-
时间范围设置:
time_range
和time_to
应正确设置,以确保获取的流量数据是准确的。
代码使用示例
- 运行代码:直接运行脚本以获取流量报告并发送警报。
- 配置:根据实际环境配置防火墙 IP 地址、Redis 地址以及钉钉 Webhook 相关参数。
- 监控:检查控制台输出和钉钉消息,确保警报通知的准确性和及时性。
import requests
import json
import time
import html
import warnings
import redis
from urllib3.exceptions import InsecureRequestWarning
from datetime import datetime
# 忽略 urllib3 的 InsecureRequestWarning 警告
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
# 连接 Redis
r = redis.Redis(host='10.1.6.175', port=6379, db=0)
# 定义变量组
app_names = {
"%u5951%u6587%u4EF6%u4E2D%u8F6C%u534F%u8BAE": "QQ文件中转协议",
"%u96C5%u864E%u901A%u6587%u4EF6%u4F20%u8F93": "雅虎通文件传输",
"MSN%u6587%u4EF6%u4F20%u8F93": "MSN文件传输",
"%u98DE%u4FE1%u6587%u4EF6%u4F20%u8F93": "飞信文件传输",
"ICQ%u6587%u4EF6%u4F20%u8F93": "ICQ文件传输",
"QQ%u6587%u4EF6%u4F20%u8F93": "QQ文件传输",
"Instan%5C_T%u6587%u4EF6%u4F20%u8F93": "Instan_T文件传输",
"Rediffbol%u6587%u4EF6%u4F20%u8F93": "Rediffbol文件传输",
"Mail.ru%5C_Agent%u6587%u4EF6%u4F20%u8F93": "Mail.ru_Agent文件传输",
"%u767E%u5EA6Hi%u6587%u4EF6%u4F20%u8F93": "百度Hi文件传输",
"Softros%5C_Messenger%u6587%u4EF6%u4F20%u8F93": "Softros_Messenger文件传输",
"%u98DE%u9E26%u4F20%u4E66%u6587%u4EF6%u4F20%u8F93": "飞鸽传书文件传输",
"Trillian%u6587%u4EF6%u4F20%u8F93": "Trillian文件传输",
"ICUII%u6587%u4EF6%u4F20%u8F93": "ICUII文件传输",
"AIM%5C_Express%u6587%u4EF6%u4F20%u8F93": "AIM_Express文件传输",
"123%5C_Web%5C_Messenger%u6587%u4EF6%u4F20%u8F93": "123_Web_Messenger文件传输",
"EyeballChat%u6587%u4EF6%u4F20%u8F93": "EyeballChat文件传输",
"GeVeZeLAN%u6587%u4EF6%u4F20%u8F93": "GeVeZeLAN文件传输",
"EasyMessenger%u6587%u4EF6%u4F20%u8F93": "EasyMessenger文件传输",
"CoolMessenger%u6587%u4EF6%u4F20%u8F93": "CoolMessenger文件传输",
"Indline%5C_Messenger%u6587%u4EF6%u4F20%u8F93": "Indline_Messenger文件传输",
"Outlook%5C_LAN%u6587%u4EF6%u4F20%u8F93": "Outlook_LAN文件传输",
"LanTalk%5C_Messenger%u6587%u4EF6%u4F20%u8F93": "LanTalk_Messenger文件传输",
"SonorkEIM%u6587%u4EF6%u4F20%u8F93": "SonorkEIM文件传输",
"Transporter%5C_P2P%u6587%u4EF6%u4F20%u8F93": "Transporter_P2P文件传输",
"%u98DE%u79CB%u6587%u4EF6%u4F20%u8F93": "飞秋文件传输",
"%u5FAE%u535A%u684C%u9762%u6587%u4EF6%u4F20%u8F93": "微博桌面文件传输",
"35EQ%u6587%u4EF6%u4F20%u8F93": "35EQ文件传输",
"GooberMessenger%u6587%u4EF6%u4F20%u8F93": "GooberMessenger文件传输",
"Commfort%u6587%u4EF6%u4F20%u8F93": "Commfort文件传输",
"Garena%u6587%u4EF6%u4F20%u8F93": "Garena文件传输",
"AvChat%u6587%u4EF6%u4F20%u8F93": "AvChat文件传输",
"%u6709%u670B%u901A%u8BAF%u6587%u4EF6%u4F20%u8F93": "有朋通讯文件传输",
"%u5E03%u8C37%u9E1F%u6587%u4EF6%u4F20%u8F93": "布谷鸟文件传输",
"VypressChat%u6587%u4EF6%u4F20%u8F93": "VypressChat文件传输",
"%u4F18%u4F60%u5BA2%u6587%u4EF6%u4F20%u8F93": "优你客文件传输",
"UU%u6587%u4EF6%u4F20%u8F93": "UU文件传输",
"UCEIM%u6587%u4EF6%u4F20%u8F93": "UCEIM文件传输",
"Espace%u6587%u4EF6%u4F20%u8F93": "Espace文件传输",
"%u6C47%u8BAF%u6587%u4EF6%u4F20%u8F93": "汇讯文件传输",
"ImOffice%u6587%u4EF6%u4F20%u8F93": "ImOffice文件传输",
"%u5642%u5642%u6587%u4EF6%u4F20%u8F93": "嘟嘟文件传输",
"Qcn%u6587%u4EF6%u4F20%u8F93": "Qcn文件传输",
"%u5FAE%u4FE1%u6587%u4EF6%u4F20%u8F93": "微信文件传输",
"Box%u6587%u4EF6%u4E0A%u4F20": "Box文件上传",
"Box%u6587%u4EF6%u4E0B%u8F7D": "Box文件下载",
"%u9489%u9489%u6587%u4EF6%u4F20%u8F93": "钉钉文件传输",
"Studiopass%u6587%u4EF6%u4E0A%u4F20": "Studiopass文件上传",
"WeTransfer%u6587%u4EF6%u4E0A%u4F20": "WeTransfer文件上传",
"WeTransfer%u6587%u4EF6%u4E0B%u8F7D": "WeTransfer文件下载",
"AdobeCreativeCloud%u6587%u4EF6%u4E0A%u4F20": "AdobeCreativeCloud文件上传",
"Insync%u6587%u4EF6%u4E0B%u8F7D": "Insync文件下载",
"Insync%u6587%u4EF6%u4E0A%u4F20": "Insync文件上传",
"%u4F18%u4E91%u7F51%u76D8%u6587%u4EF6%u4E0B%u8F7D": "优云网盘文件下载",
"%u4F18%u4E91%u7F51%u76D8%u6587%u4EF6%u4E0A%u4F20": "优云网盘文件上传",
"%u4F01%u4E1A%u5FAE%u4FE1%u6587%u4EF6%u4F20%u8F93": "企业微信文件传输",
"WhatsAPP%u6587%u4EF6%u4F20%u8F93": "WhatsAPP文件传输",
"Dropbox%u6587%u4EF6%u4E0B%u8F7D": "Dropbox文件下载",
"Dropbox%u6587%u4EF6%u4E0A%u4F20": "Dropbox文件上传",
"%u5FAE%u4FE1%u53D1%u9001%u6587%u4EF6": "微信发送文件",
"%u5FAE%u4FE1%u63A5%u6536%u6587%u4EF6": "微信接收文件",
"%u7C73%u804A%u6587%u4EF6%u4F20%u8F93": "米聊文件传输",
"%u963F%u91CC%u65FA%u65FA%u6587%u4EF6%u4F20%u8F93": "阿里旺旺文件传输",
"PingChat%u6587%u4EF6%u4F20%u8F93": "PingChat文件传输",
"%u817E%u8BAF%u901A%u6587%u4EF6%u4F20%u8F93": "腾讯通文件传输",
"Worktile%u6587%u4EF6%u4F20%u8F93": "Worktile文件传输",
"QQ%u53D1%u9001%u6587%u4EF6": "QQ发送文件",
"QQ%u63A5%u6536%u6587%u4EF6": "QQ接收文件",
"%u767E%u5EA6%u7F51%u76D8": "百度网盘",
"%u767E%u5EA6%u4E91%u76D8%u4E0A%u4F20": "百度云盘上传",
"%u767E%u5EA6%u4E91%u76D8%u4E0B%u8F7D": "百度云盘下载",
"%u963F%u91CC%u4E91%u76D8": "阿里云盘"
}
# 获取当天的时间戳
current_time = int(time.time())
time_range = current_time - (current_time % 86400) # 昨天的时间戳
time_to = current_time + 86400 # 今天的时间戳
date_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
url = "https://自己防火墙ip:8443/common.html"
payload = {
"getTrafficReportTOPN": {
"language": 1,
"vsys": "public",
"pageIndex": 1,
"pageSize": 100,
"exported": 0,
"reportType": "flowReport",
"funcName": "getTrafficReportTOPN",
"time_range": str(time_range),
"time_to": str(time_to),
"topNType": "app",
"desc": "upflow"
}
}
headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'keep-alive',
'Content-Length': '239',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'SESSIONID=bQEAAApssLsyQHBKbFp1IsmHHFB8+n/3C6O/R5rbx5g=&bQEAADaGLftkNINKVr87HQ==&HUAWEI &langfrombrows=zh-CN,©right=2014-2019',
'Host': '自己防火墙ip:8443',
'Origin': 'https://自己防火墙ip:8443',
'Referer': 'https://自己防火墙ip:8443/default.html',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Token': 'kVlUZjudU5EtircTfNj4enORi9mpsF6E8Tolb8zdn3M=',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
'X-Requested-With': 'XMLHttpRequest'
}
response = requests.request("POST", url, headers=headers, json=payload, verify=False)
shuaxin_decoded_data = html.unescape(response.text)
# print(shuaxin_decoded_data)
# 构建 GET 请求 URL
url = "https://自己防火墙ip:8443/filename/heartbeat/"
params = {
"time_range": str(time_range),
"time_to": str(time_to)
}
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Connection": "keep-alive",
"Cookie": "SESSIONID=bQEAAApssLsyQHBKbFp1IsmHHFB8+n/3C6O/R5rbx5g=&bQEAADaGLftkNINKVr87HQ==&HUAWEI &langfrombrows=zh-CN,©right=2014-2019",
"Host": "自己防火墙ip:8443",
"Referer": "https://自己防火墙ip:8443/default.html",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Token": "kVlUZjudU5EtircTfNj4enORi9mpsF6E8Tolb8zdn3M=",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0",
"X-Requested-With": "XMLHttpRequest"
}
# 发送 GET 请求
response = requests.get(url, params=params, headers=headers, verify=False)
if response.status_code == 200:
# 循环处理每个应用程序
for app_code, app_name in app_names.items():
# 构建 POST 请求参数
post_params = {
"getTrafficReportTOPN": {
"language": 1,
"vsys": "public",
"pageIndex": 1,
"pageSize": 10,
"exported": 0,
"reportType": "flowReport",
"funcName": "getTrafficReportTOPN",
"time_range": str(time_range),
"time_to": str(time_to),
"topNType": "app-srcIp",
"application": app_code,
"singleItem": app_code,
"desc": "flow"
}
}
post_url = "https://自己防火墙ip:8443/common.html"
post_headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "SESSIONID=bQEAAApssLsyQHBKbFp1IsmHHFB8+n/3C6O/R5rbx5g=&bQEAADaGLftkNINKVr87HQ==&HUAWEI &langfrombrows=zh-CN,©right=2014-2019",
"Host": "自己防火墙ip:8443",
"Origin": "https://自己防火墙ip:8443",
"Referer": "https://自己防火墙ip:8443/default.html",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Token": "kVlUZjudU5EtircTfNj4enORi9mpsF6E8Tolb8zdn3M=",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0",
"X-Requested-With": "XMLHttpRequest"
}
# 发送 POST 请求
post_response = requests.post(post_url, json=post_params, headers=post_headers, verify=False)
decoded_data = html.unescape(post_response.text)
if post_response.status_code == 200:
# 解析 JSON 数据
data = json.loads(decoded_data)
traffic_report = data["getTrafficReportTOPN"]
for item in traffic_report["data"]:
upflow_mb = int(item["upflow"]) / (1024 * 1024) # 将上行流量转换为MB
downflow_mb = int(item["downflow"]) / (1024 * 1024) # 将下行流量转换为MB
flow_mb = int(item["flow"]) / (1024 * 1024) # 将总流量转换为MB
total_flow_mb = int(item["totalFlow"]) / (1024 * 1024) # 将总流量转换为MB
total_upflow_mb = int(item["totalUpflow"]) / (1024 * 1024) # 将总上行流量转换为MB
total_downflow_mb = int(item["totalDownflow"]) / (1024 * 1024) # 将总下行流量转换为MB
# 构建缓存键值
cache_key = f"{app_name}:{item['singleItem']}"
# 检查缓存中是否存在该键值
if not r.exists(cache_key):
# 如果该用户总流量大于 5000MB,发送报警 Webhook 并将键值存入缓存,缓存过期时间设置为 1 小时
if flow_mb > 5000:
payload = {
"msgtype": "text",
"text": {
"content": f"TEST网络流量预警当前用户总流量大于5000MB通知\n"
f"应用程序名称: {app_name}\n"
f"IP地址: {item['singleItem']}\n"
f"上传流量: {upflow_mb:.2f} MB\n"
f"下载流量: {downflow_mb:.2f} MB\n"
f"该用户总流量: {flow_mb:.2f} MB\n"
f"该用户会话数: {item['sessionNum']}\n"
f"该应用整体总流量: {total_flow_mb:.2f} MB\n"
f"该应用总上传流量: {total_upflow_mb:.2f} MB\n"
f"该应用总下载流量: {total_downflow_mb:.2f} MB\n"
f"总会话数: {item['totalSessionNum']}\n"
}
}
headers = {
"Content-Type": "application/json"
}
response = requests.post(
"https://oapi.dingtalk.com/robot/send?access_token=3d3c3a0e7f45bd760b6d0dde83fe5b193783a50a9db5a5f92db1b27c54XXXXX",
json=payload,
headers=headers
)
if response.status_code == 200:
print("报警 Webhook 发送成功")
else:
print(f"报警 Webhook 发送失败,状态码: {response.status_code}")
# 将键值存入缓存,过期时间设置为 3 小时
r.set(cache_key, 1, ex=10800)
print({
"应用程序名称": app_name,
"IP地址": item["singleItem"],
"上传流量": f"{upflow_mb:.2f} MB",
"下载流量": f"{downflow_mb:.2f} MB",
"该用户总流量": f"{flow_mb:.2f} MB",
"该用户会话数": item["sessionNum"],
"该应用整体总流量": f"{total_flow_mb:.2f} MB",
"该应用总上传流量": f"{total_upflow_mb:.2f} MB",
"该应用总下载流量": f"{total_downflow_mb:.2f} MB",
"总会话数": item["totalSessionNum"]
})
# 每次循环请求之间延迟 0.3 秒
time.sleep(0.3)
else:
print(f"POST 请求失败,状态码: {post_response.status_code}")
else:
print(f"GET 请求失败,状态码: {response.status_code}")