PhilipL commited on
Commit
a4c77d4
·
verified ·
1 Parent(s): fcdc619

update locate weight

Browse files
Files changed (1) hide show
  1. app.py +31 -18
app.py CHANGED
@@ -33,20 +33,17 @@ global_stats = {
33
  "start_time": datetime.datetime.now()
34
  }
35
 
36
- # 系統防護權重全域變數 (預設值)
37
  system_weights = {
38
  "ow": 75.0, "tw": 80.0, "iw": 65.0,
39
  "dw": 45.0, "gw": 50.0, "fw": 60.0
40
  }
41
 
42
- # 專屬更新權重的副程式
43
  def update_system_weights(ow, tw, iw, dw, gw, fw):
44
  system_weights.update({
45
  "ow": float(ow), "tw": float(tw), "iw": float(iw),
46
  "dw": float(dw), "gw": float(gw), "fw": float(fw)
47
  })
48
 
49
- # --- 13 個系統按鈕的對應字典 ---
50
  ACTION_MAP = {
51
  "教務系統: 期末網路教學評量": "click_eval_system",
52
  "教務系統: 期末網路預選系統": "click_pre_select_system",
@@ -66,24 +63,33 @@ ACTION_MAP = {
66
  log_history = []
67
  initial_df_abn = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
68
 
 
69
  def get_ip_category(ip_str):
70
  ip = str(ip_str).split(" ")[0]
71
  if ip.startswith("140.124."): return 0.0
72
  elif ip.startswith("61.228."): return 1.0
73
  elif ip.startswith("210.61."): return 2.0
74
  elif ip.startswith("45.33."): return 3.0
75
- else: return 4.0
 
 
 
 
 
 
 
 
 
 
76
 
77
  # --- 1. 載入模型與歷史資料 ---
78
  try:
79
  le_action = joblib.load('le_action.pkl')
80
 
81
  print("📂 正在讀取本地歷史資料庫...")
82
- # 直接讀取本地的 baseline_logs.csv,不再向雲端同步
83
  if os.path.exists('baseline_logs.csv'):
84
  baseline_df = pd.read_csv('baseline_logs.csv')
85
  else:
86
- # 如果檔案不存在,建立帶有標題的空 DataFrame 並存檔
87
  baseline_df = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
88
  baseline_df.to_csv('baseline_logs.csv', index=False)
89
 
@@ -179,7 +185,6 @@ def get_plot_data(selected_key):
179
 
180
  df_live = pd.DataFrame(log_history)
181
  if not df_live.empty:
182
- # 👉 雙重防護 2:加入 errors='coerce' 容錯機制,剔除壞資料避免圖表破圖
183
  df_live['timestamp'] = pd.to_datetime(df_live['timestamp'], errors='coerce')
184
  df_live = df_live.dropna(subset=['timestamp'])
185
  df_live = df_live[df_live['action'] == action_code].copy()
@@ -264,7 +269,6 @@ def check_anomaly(ip, account, action, log_time):
264
  if action in ["login_attempt", "logout"]: return "success"
265
 
266
  try:
267
- # 直接從全域變數提取當前權重
268
  ow = float(system_weights["ow"])
269
  tw = float(system_weights["tw"])
270
  iw = float(system_weights["iw"])
@@ -272,9 +276,22 @@ def check_anomaly(ip, account, action, log_time):
272
  gw = float(system_weights["gw"])
273
  fw = float(system_weights["fw"])
274
 
275
- # --- 第一道防線 (限縮為單一按鈕判斷,並套用精確的閾值) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  current_dt = pd.to_datetime(str(log_time))
277
- cutoff_dt = current_dt - pd.Timedelta(seconds=60) # 往前回溯 60 秒
278
 
279
  recent_clicks = 0
280
  for log in log_history:
@@ -300,7 +317,7 @@ def check_anomaly(ip, account, action, log_time):
300
  if (recent_clicks + 1) > max_allowed_clicks:
301
  return f"⚠️異常_單一操作頻率過高 ({recent_clicks+1}次/分)"
302
 
303
- # --- 第二道防線 (HDBSCAN AI 空間異常判斷) 繼續執行 ---
304
  ip_code = float(get_ip_category(ip))
305
  action_code = float(le_action.transform([action])[0])
306
 
@@ -362,13 +379,11 @@ def check_anomaly(ip, account, action, log_time):
362
  def record_log(ip, cookie, account, role, action, status, time_mode, custom_time):
363
  global baseline_X
364
 
365
- # 👉 雙重防護 1:驗證自訂時間格式
366
  if time_mode == "自訂時間 (模擬過去/未來)" and custom_time and str(custom_time).strip() != "":
367
  try:
368
  valid_time = pd.to_datetime(str(custom_time))
369
  log_time = valid_time.strftime("%Y-%m-%d %H:%M:%S")
370
  except Exception:
371
- # 🚨 解析失敗,退回當前時間並標記狀態
372
  log_time = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S")
373
  status = "⚠️格式錯誤_無效的自訂時間"
374
  else:
@@ -380,7 +395,6 @@ def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
380
 
381
  new_log = {"timestamp": log_time, "ip_address": ip, "cookie_id": cookie, "account": account, "role": role, "action": action, "status": status}
382
 
383
- # 將產生的新 Log 直接 append (附加) 到本地的 baseline_logs.csv 中
384
  new_df = pd.DataFrame([new_log])
385
  new_df.to_csv('baseline_logs.csv', mode='a', header=not os.path.exists('baseline_logs.csv'), index=False)
386
 
@@ -388,7 +402,7 @@ def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
388
  except: pass
389
 
390
  global_stats["total_count"] += 1
391
- if "異常" in str(status) or "錯誤" in str(status): global_stats["abnormal_count"] += 1
392
 
393
  log_history.insert(0, new_log)
394
 
@@ -401,10 +415,10 @@ def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
401
  except: pass
402
 
403
  df_all = pd.DataFrame(log_history)
404
- abnormal_logs = [log for log in log_history if "異常" in str(log.get("status", "")) or "錯誤" in str(log.get("status", ""))]
405
  df_abnormal = pd.DataFrame(abnormal_logs) if abnormal_logs else pd.DataFrame(columns=df_all.columns)
406
 
407
- input_update = gr.update(value=f"時間: {log_time} | IP: {ip} | 帳號: {account} | 動作: {action} | 狀態: {status}") if "異常" in str(status) or "錯誤" in str(status) else gr.update()
408
  return df_all, df_abnormal, input_update
409
 
410
  def fast_login(target_account, ip, cookie, time_mode, custom_time):
@@ -593,7 +607,6 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
593
  time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
594
  btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
595
 
596
- # 綁定權重拉桿與更新函式
597
  weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
598
  for w_input in weight_inputs:
599
  w_input.change(fn=update_system_weights, inputs=weight_inputs, outputs=[])
 
33
  "start_time": datetime.datetime.now()
34
  }
35
 
 
36
  system_weights = {
37
  "ow": 75.0, "tw": 80.0, "iw": 65.0,
38
  "dw": 45.0, "gw": 50.0, "fw": 60.0
39
  }
40
 
 
41
  def update_system_weights(ow, tw, iw, dw, gw, fw):
42
  system_weights.update({
43
  "ow": float(ow), "tw": float(tw), "iw": float(iw),
44
  "dw": float(dw), "gw": float(gw), "fw": float(fw)
45
  })
46
 
 
47
  ACTION_MAP = {
48
  "教務系統: 期末網路教學評量": "click_eval_system",
49
  "教務系統: 期末網路預選系統": "click_pre_select_system",
 
63
  log_history = []
64
  initial_df_abn = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
65
 
66
+ # HDBSCAN 特徵分群用的 IP 分類
67
  def get_ip_category(ip_str):
68
  ip = str(ip_str).split(" ")[0]
69
  if ip.startswith("140.124."): return 0.0
70
  elif ip.startswith("61.228."): return 1.0
71
  elif ip.startswith("210.61."): return 2.0
72
  elif ip.startswith("45.33."): return 3.0
73
+ else: return 4.0
74
+
75
+ # 👉 新增:專供 Geo-Weight 權重邏輯使用的精細分級
76
+ def get_geo_level(ip_str):
77
+ ip = str(ip_str).split(" ")[0]
78
+ if ip == "140.124.71.55": return 0 # 校內預設
79
+ elif ip == "140.124.18.22": return 1 # 宿舍
80
+ elif ip.startswith("61.228."): return 2 # 家裡
81
+ elif ip.startswith("210.61."): return 3 # 公共場所
82
+ elif ip.startswith("45.33."): return 4 # 國外異常
83
+ else: return 5 # 未知
84
 
85
  # --- 1. 載入模型與歷史資料 ---
86
  try:
87
  le_action = joblib.load('le_action.pkl')
88
 
89
  print("📂 正在讀取本地歷史資料庫...")
 
90
  if os.path.exists('baseline_logs.csv'):
91
  baseline_df = pd.read_csv('baseline_logs.csv')
92
  else:
 
93
  baseline_df = pd.DataFrame(columns=["timestamp", "ip_address", "cookie_id", "account", "role", "action", "status"])
94
  baseline_df.to_csv('baseline_logs.csv', index=False)
95
 
 
185
 
186
  df_live = pd.DataFrame(log_history)
187
  if not df_live.empty:
 
188
  df_live['timestamp'] = pd.to_datetime(df_live['timestamp'], errors='coerce')
189
  df_live = df_live.dropna(subset=['timestamp'])
190
  df_live = df_live[df_live['action'] == action_code].copy()
 
269
  if action in ["login_attempt", "logout"]: return "success"
270
 
271
  try:
 
272
  ow = float(system_weights["ow"])
273
  tw = float(system_weights["tw"])
274
  iw = float(system_weights["iw"])
 
276
  gw = float(system_weights["gw"])
277
  fw = float(system_weights["fw"])
278
 
279
+ # 👉 第一道防線:地理圍籬 (Geo-Fencing) 攔截
280
+ geo_level = get_geo_level(ip)
281
+
282
+ if gw == 100 and geo_level > 0:
283
+ return "⚠️異常_地理位置受限 (100%絕對鎖定: 僅限校內專網存取)"
284
+ elif gw >= 90 and geo_level > 1:
285
+ return "⚠️異常_地理位置受限 (高敏感防護: 僅限校園網路與宿舍)"
286
+ elif gw >= 70 and geo_level > 2:
287
+ return "⚠️異常_地理位置受限 (進階防護: 禁止公共場所與海外連線)"
288
+ elif gw >= 50 and geo_level > 3:
289
+ return "⚠️異常_地理位置受限 (預設防護: 禁止海外異常 IP)"
290
+ # 若 gw < 50,則放行所有位置,交由後續 AI 處理
291
+
292
+ # --- 第二道防線:頻率攔截 ---
293
  current_dt = pd.to_datetime(str(log_time))
294
+ cutoff_dt = current_dt - pd.Timedelta(seconds=60)
295
 
296
  recent_clicks = 0
297
  for log in log_history:
 
317
  if (recent_clicks + 1) > max_allowed_clicks:
318
  return f"⚠️異常_單一操作頻率過高 ({recent_clicks+1}次/分)"
319
 
320
+ # --- 第三道防線:HDBSCAN AI 空間異常判斷 ---
321
  ip_code = float(get_ip_category(ip))
322
  action_code = float(le_action.transform([action])[0])
323
 
 
379
  def record_log(ip, cookie, account, role, action, status, time_mode, custom_time):
380
  global baseline_X
381
 
 
382
  if time_mode == "自訂時間 (模擬過去/未來)" and custom_time and str(custom_time).strip() != "":
383
  try:
384
  valid_time = pd.to_datetime(str(custom_time))
385
  log_time = valid_time.strftime("%Y-%m-%d %H:%M:%S")
386
  except Exception:
 
387
  log_time = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).strftime("%Y-%m-%d %H:%M:%S")
388
  status = "⚠️格式錯誤_無效的自訂時間"
389
  else:
 
395
 
396
  new_log = {"timestamp": log_time, "ip_address": ip, "cookie_id": cookie, "account": account, "role": role, "action": action, "status": status}
397
 
 
398
  new_df = pd.DataFrame([new_log])
399
  new_df.to_csv('baseline_logs.csv', mode='a', header=not os.path.exists('baseline_logs.csv'), index=False)
400
 
 
402
  except: pass
403
 
404
  global_stats["total_count"] += 1
405
+ if "異常" in str(status) or "錯誤" in str(status) or "受限" in str(status): global_stats["abnormal_count"] += 1
406
 
407
  log_history.insert(0, new_log)
408
 
 
415
  except: pass
416
 
417
  df_all = pd.DataFrame(log_history)
418
+ abnormal_logs = [log for log in log_history if "異常" in str(log.get("status", "")) or "錯誤" in str(log.get("status", "")) or "受限" in str(log.get("status", ""))]
419
  df_abnormal = pd.DataFrame(abnormal_logs) if abnormal_logs else pd.DataFrame(columns=df_all.columns)
420
 
421
+ input_update = gr.update(value=f"時間: {log_time} | IP: {ip} | 帳號: {account} | 動作: {action} | 狀態: {status}") if "異常" in str(status) or "錯誤" in str(status) or "受限" in str(status) else gr.update()
422
  return df_all, df_abnormal, input_update
423
 
424
  def fast_login(target_account, ip, cookie, time_mode, custom_time):
 
607
  time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
608
  btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
609
 
 
610
  weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
611
  for w_input in weight_inputs:
612
  w_input.change(fn=update_system_weights, inputs=weight_inputs, outputs=[])