mdbq 4.2.23__py3-none-any.whl → 4.2.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mdbq might be problematic. Click here for more details.
- mdbq/__version__.py +1 -1
- mdbq/route/monitor.py +178 -5
- {mdbq-4.2.23.dist-info → mdbq-4.2.24.dist-info}/METADATA +1 -1
- {mdbq-4.2.23.dist-info → mdbq-4.2.24.dist-info}/RECORD +6 -6
- {mdbq-4.2.23.dist-info → mdbq-4.2.24.dist-info}/WHEEL +0 -0
- {mdbq-4.2.23.dist-info → mdbq-4.2.24.dist-info}/top_level.txt +0 -0
mdbq/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '4.2.
|
|
1
|
+
VERSION = '4.2.24'
|
mdbq/route/monitor.py
CHANGED
|
@@ -21,7 +21,7 @@ import functools
|
|
|
21
21
|
import hashlib
|
|
22
22
|
import socket
|
|
23
23
|
from datetime import datetime, timedelta
|
|
24
|
-
from typing import Dict, Any, Optional
|
|
24
|
+
from typing import Dict, Any, Optional, List
|
|
25
25
|
from dbutils.pooled_db import PooledDB # type: ignore
|
|
26
26
|
from flask import request, g
|
|
27
27
|
|
|
@@ -437,6 +437,138 @@ class RouteMonitor:
|
|
|
437
437
|
except Exception:
|
|
438
438
|
return None
|
|
439
439
|
|
|
440
|
+
def calculate_risk_score(self, client_ip: str, date: datetime.date) -> int:
|
|
441
|
+
"""
|
|
442
|
+
计算 IP 风险评分(0-100)
|
|
443
|
+
|
|
444
|
+
风险评分基于以下维度:
|
|
445
|
+
1. 请求频率异常(30分):单日请求数超过阈值
|
|
446
|
+
2. 失败率异常(25分):失败请求比例过高
|
|
447
|
+
3. 访问模式异常(20分):短时间访问大量不同接口
|
|
448
|
+
4. 时间分布异常(15分):非正常时间段高频访问
|
|
449
|
+
5. 响应时间异常(10分):平均响应时间过长(可能是攻击)
|
|
450
|
+
|
|
451
|
+
Args:
|
|
452
|
+
client_ip: 客户端 IP 地址
|
|
453
|
+
date: 统计日期
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
int: 风险评分(0-100),分数越高风险越大
|
|
457
|
+
"""
|
|
458
|
+
risk_score = 0
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
connection = self.pool.connection()
|
|
462
|
+
try:
|
|
463
|
+
with connection.cursor() as cursor:
|
|
464
|
+
self.ensure_database_context(cursor)
|
|
465
|
+
|
|
466
|
+
# 获取该 IP 当日的统计数据
|
|
467
|
+
cursor.execute("""
|
|
468
|
+
SELECT
|
|
469
|
+
`请求总数`, `成功次数`, `失败次数`,
|
|
470
|
+
`平均耗时`, `首次访问`, `最后访问`, `访问接口数`
|
|
471
|
+
FROM `api_ip记录`
|
|
472
|
+
WHERE `客户端ip` = %s AND `统计日期` = %s
|
|
473
|
+
""", (client_ip, date))
|
|
474
|
+
|
|
475
|
+
ip_stats = cursor.fetchone()
|
|
476
|
+
if not ip_stats:
|
|
477
|
+
return 0 # 无数据,无风险
|
|
478
|
+
|
|
479
|
+
total_requests = ip_stats['请求总数']
|
|
480
|
+
success_count = ip_stats['成功次数']
|
|
481
|
+
failure_count = ip_stats['失败次数']
|
|
482
|
+
avg_time = float(ip_stats['平均耗时']) if ip_stats['平均耗时'] else 0
|
|
483
|
+
first_access = ip_stats['首次访问']
|
|
484
|
+
last_access = ip_stats['最后访问']
|
|
485
|
+
endpoint_count = ip_stats['访问接口数'] or 0
|
|
486
|
+
|
|
487
|
+
# 1. 请求频率异常检测(30分)
|
|
488
|
+
# 阈值:正常用户单日请求 < 1000,可疑 1000-5000,高风险 > 5000
|
|
489
|
+
if total_requests > 10000:
|
|
490
|
+
risk_score += 30 # 极高频率
|
|
491
|
+
elif total_requests > 5000:
|
|
492
|
+
risk_score += 25 # 高频率
|
|
493
|
+
elif total_requests > 2000:
|
|
494
|
+
risk_score += 18 # 中等频率
|
|
495
|
+
elif total_requests > 1000:
|
|
496
|
+
risk_score += 10 # 略高
|
|
497
|
+
|
|
498
|
+
# 2. 失败率异常检测(25分)
|
|
499
|
+
# 高失败率可能是暴力破解、SQL注入等攻击
|
|
500
|
+
if total_requests > 0:
|
|
501
|
+
failure_rate = failure_count / total_requests
|
|
502
|
+
if failure_rate > 0.8:
|
|
503
|
+
risk_score += 25 # 80%以上失败
|
|
504
|
+
elif failure_rate > 0.5:
|
|
505
|
+
risk_score += 20 # 50%-80%失败
|
|
506
|
+
elif failure_rate > 0.3:
|
|
507
|
+
risk_score += 12 # 30%-50%失败
|
|
508
|
+
elif failure_rate > 0.15:
|
|
509
|
+
risk_score += 5 # 15%-30%失败
|
|
510
|
+
|
|
511
|
+
# 3. 访问模式异常检测(20分)
|
|
512
|
+
# 短时间访问大量不同接口可能是扫描行为
|
|
513
|
+
if endpoint_count > 0:
|
|
514
|
+
# 计算平均每个接口的访问次数
|
|
515
|
+
avg_per_endpoint = total_requests / endpoint_count
|
|
516
|
+
|
|
517
|
+
if endpoint_count > 50 and avg_per_endpoint < 5:
|
|
518
|
+
risk_score += 20 # 访问50+接口,每个接口少于5次(扫描特征)
|
|
519
|
+
elif endpoint_count > 30 and avg_per_endpoint < 10:
|
|
520
|
+
risk_score += 15 # 访问30+接口
|
|
521
|
+
elif endpoint_count > 20 and avg_per_endpoint < 15:
|
|
522
|
+
risk_score += 10 # 访问20+接口
|
|
523
|
+
elif endpoint_count > 10 and avg_per_endpoint < 20:
|
|
524
|
+
risk_score += 5 # 访问10+接口
|
|
525
|
+
|
|
526
|
+
# 4. 时间分布异常检测(15分)
|
|
527
|
+
# 查询该 IP 的小时分布,检测是否有非正常时间段高频访问
|
|
528
|
+
cursor.execute("""
|
|
529
|
+
SELECT
|
|
530
|
+
HOUR(`请求时间`) as hour,
|
|
531
|
+
COUNT(*) as count
|
|
532
|
+
FROM `api_访问日志`
|
|
533
|
+
WHERE `客户端ip` = %s
|
|
534
|
+
AND DATE(`请求时间`) = %s
|
|
535
|
+
GROUP BY HOUR(`请求时间`)
|
|
536
|
+
HAVING count > 100
|
|
537
|
+
ORDER BY count DESC
|
|
538
|
+
""", (client_ip, date))
|
|
539
|
+
|
|
540
|
+
hourly_distribution = cursor.fetchall()
|
|
541
|
+
|
|
542
|
+
# 检测是否有凌晨时段(0-5点)的异常高频访问
|
|
543
|
+
night_requests = sum(h['count'] for h in hourly_distribution if 0 <= h['hour'] <= 5)
|
|
544
|
+
if night_requests > 500:
|
|
545
|
+
risk_score += 15 # 凌晨大量请求(可能是爬虫/攻击)
|
|
546
|
+
elif night_requests > 200:
|
|
547
|
+
risk_score += 10
|
|
548
|
+
elif night_requests > 100:
|
|
549
|
+
risk_score += 5
|
|
550
|
+
|
|
551
|
+
# 5. 响应时间异常检测(10分)
|
|
552
|
+
# 过长的响应时间可能是 DDoS 攻击或资源耗尽攻击
|
|
553
|
+
if avg_time > 5000: # > 5秒
|
|
554
|
+
risk_score += 10
|
|
555
|
+
elif avg_time > 3000: # > 3秒
|
|
556
|
+
risk_score += 7
|
|
557
|
+
elif avg_time > 2000: # > 2秒
|
|
558
|
+
risk_score += 4
|
|
559
|
+
|
|
560
|
+
# 限制评分范围在 0-100
|
|
561
|
+
risk_score = min(100, max(0, risk_score))
|
|
562
|
+
|
|
563
|
+
finally:
|
|
564
|
+
connection.close()
|
|
565
|
+
|
|
566
|
+
except Exception as e:
|
|
567
|
+
# 计算失败时返回 0(保守策略)
|
|
568
|
+
return 0
|
|
569
|
+
|
|
570
|
+
return risk_score
|
|
571
|
+
|
|
440
572
|
# ==================== 核心数据收集 ====================
|
|
441
573
|
|
|
442
574
|
def collect_request_data(self, request) -> Dict[str, Any]:
|
|
@@ -685,6 +817,9 @@ class RouteMonitor:
|
|
|
685
817
|
))
|
|
686
818
|
|
|
687
819
|
# 2. 更新 IP 统计表
|
|
820
|
+
client_ip = request_data.get('客户端ip', '')
|
|
821
|
+
|
|
822
|
+
# 首先更新基础统计
|
|
688
823
|
cursor.execute("""
|
|
689
824
|
INSERT INTO `api_ip记录` (
|
|
690
825
|
`统计日期`, `客户端ip`, `请求总数`, `成功次数`, `失败次数`,
|
|
@@ -695,13 +830,13 @@ class RouteMonitor:
|
|
|
695
830
|
`请求总数` = `请求总数` + 1,
|
|
696
831
|
`成功次数` = `成功次数` + %s,
|
|
697
832
|
`失败次数` = `失败次数` + %s,
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
833
|
+
`平均耗时` = (
|
|
834
|
+
(`平均耗时` * `请求总数` + %s) / (`请求总数` + 1)
|
|
835
|
+
),
|
|
701
836
|
`最后访问` = %s
|
|
702
837
|
""", (
|
|
703
838
|
date,
|
|
704
|
-
|
|
839
|
+
client_ip,
|
|
705
840
|
is_success, is_error,
|
|
706
841
|
response_time, now, now,
|
|
707
842
|
is_success, is_error,
|
|
@@ -709,8 +844,46 @@ class RouteMonitor:
|
|
|
709
844
|
now
|
|
710
845
|
))
|
|
711
846
|
|
|
847
|
+
# 计算该 IP 访问的不同接口数量
|
|
848
|
+
cursor.execute("""
|
|
849
|
+
SELECT COUNT(DISTINCT `路由地址`) as endpoint_count
|
|
850
|
+
FROM `api_访问日志`
|
|
851
|
+
WHERE `客户端ip` = %s AND DATE(`请求时间`) = %s
|
|
852
|
+
""", (client_ip, date))
|
|
853
|
+
|
|
854
|
+
endpoint_result = cursor.fetchone()
|
|
855
|
+
endpoint_count = endpoint_result['endpoint_count'] if endpoint_result else 0
|
|
856
|
+
|
|
857
|
+
# 更新访问接口数
|
|
858
|
+
cursor.execute("""
|
|
859
|
+
UPDATE `api_ip记录`
|
|
860
|
+
SET `访问接口数` = %s
|
|
861
|
+
WHERE `客户端ip` = %s AND `统计日期` = %s
|
|
862
|
+
""", (endpoint_count, client_ip, date))
|
|
863
|
+
|
|
712
864
|
connection.commit()
|
|
713
865
|
|
|
866
|
+
# 3. 计算并更新风险评分(在事务外执行,避免影响主流程性能)
|
|
867
|
+
try:
|
|
868
|
+
risk_score = self.calculate_risk_score(client_ip, date)
|
|
869
|
+
if risk_score > 0:
|
|
870
|
+
# 重新获取连接更新风险评分
|
|
871
|
+
connection2 = self.pool.connection()
|
|
872
|
+
try:
|
|
873
|
+
with connection2.cursor() as cursor2:
|
|
874
|
+
self.ensure_database_context(cursor2)
|
|
875
|
+
cursor2.execute("""
|
|
876
|
+
UPDATE `api_ip记录`
|
|
877
|
+
SET `风险评分` = %s
|
|
878
|
+
WHERE `客户端ip` = %s AND `统计日期` = %s
|
|
879
|
+
""", (risk_score, client_ip, date))
|
|
880
|
+
connection2.commit()
|
|
881
|
+
finally:
|
|
882
|
+
connection2.close()
|
|
883
|
+
except Exception:
|
|
884
|
+
# 风险评分计算失败不影响主流程
|
|
885
|
+
pass
|
|
886
|
+
|
|
714
887
|
finally:
|
|
715
888
|
connection.close()
|
|
716
889
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
mdbq/__init__.py,sha256=Il5Q9ATdX8yXqVxtP_nYqUhExzxPC_qk_WXQ_4h0exg,16
|
|
2
|
-
mdbq/__version__.py,sha256=
|
|
2
|
+
mdbq/__version__.py,sha256=xonW2LDdCLkjtJG5r4FfnQFuBEEqoKgnJ3iX1b03GR8,18
|
|
3
3
|
mdbq/auth/__init__.py,sha256=pnPMAt63sh1B6kEvmutUuro46zVf2v2YDAG7q-jV_To,24
|
|
4
4
|
mdbq/auth/auth_backend.py,sha256=xXVvgKAI1sOGMx_vIAHW0SCSEaIG6h90kXYQwy5P0vI,116902
|
|
5
5
|
mdbq/auth/crypto.py,sha256=M0i4dRljJuE30WH_13ythA2QGKPXZm6TgpnYp6aHOzw,17431
|
|
@@ -30,12 +30,12 @@ mdbq/redis/getredis.py,sha256=vdg7YQEjhoMp5QzxygNGx5DQKRnePrcwPYgUrDypA6g,23672
|
|
|
30
30
|
mdbq/redis/redis_cache.py,sha256=NFETT4tUf6xvE2xHtS828fx2tDBBTigd6S2RaHBj6P8,46392
|
|
31
31
|
mdbq/route/__init__.py,sha256=BT_dAY7V-U2o72bevq1B9Mq9QA7GodwtkxyLNdGaoE8,22
|
|
32
32
|
mdbq/route/analytics.py,sha256=dngj5hVwKddEUy59nSYbOoJ9C7OVrtCmCkvW6Uj9RYM,28097
|
|
33
|
-
mdbq/route/monitor.py,sha256=
|
|
33
|
+
mdbq/route/monitor.py,sha256=QlMaGNiQuhO662NJo7uAzPxnLGKPbYH5WNUVV96FSVE,53266
|
|
34
34
|
mdbq/route/routes.py,sha256=QVGfTvDgu0CpcKCvk1ra74H8uojgqTLUav1fnVAqLEA,29433
|
|
35
35
|
mdbq/selenium/__init__.py,sha256=AKzeEceqZyvqn2dEDoJSzDQnbuENkJSHAlbHAD0u0ZI,10
|
|
36
36
|
mdbq/selenium/get_driver.py,sha256=1NTlVUE6QsyjTrVVVqTO2LOnYf578ccFWlWnvIXGtic,20903
|
|
37
37
|
mdbq/spider/__init__.py,sha256=RBMFXGy_jd1HXZhngB2T2XTvJqki8P_Fr-pBcwijnew,18
|
|
38
|
-
mdbq-4.2.
|
|
39
|
-
mdbq-4.2.
|
|
40
|
-
mdbq-4.2.
|
|
41
|
-
mdbq-4.2.
|
|
38
|
+
mdbq-4.2.24.dist-info/METADATA,sha256=k5gMn-IvExYIXs7VbJyPNw2N2GRSc4Zhy8RpVfAInGE,364
|
|
39
|
+
mdbq-4.2.24.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
40
|
+
mdbq-4.2.24.dist-info/top_level.txt,sha256=2FQ-uLnCSB-OwFiWntzmwosW3X2Xqsg0ewh1axsaylA,5
|
|
41
|
+
mdbq-4.2.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|