PhilipL commited on
Commit
2494ef5
·
verified ·
1 Parent(s): 39fc6b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -88
app.py CHANGED
@@ -44,47 +44,70 @@ def check_anomaly(ip, action, log_time, overall_w, time_w, ip_w, dev_w):
44
  if action in ["login_attempt", "logout"]: return "success"
45
 
46
  try:
47
- clean_ip = ip.split(" ")[0]
48
- ip_code = le_ip.transform([clean_ip])[0]
49
- action_code = le_action.transform([action])[0]
 
50
 
51
- current_time = pd.to_datetime(log_time)
52
- current_month = current_time.month
53
- current_day = current_time.day
54
- current_hour = current_time.hour
55
 
56
- action_scale = (dev_w / 100.0) * 100.0
 
 
 
 
 
 
57
 
58
  scaled_baseline = baseline_X.copy().astype(float)
59
- scaled_baseline[:, 0] *= (time_w / 100.0) * 10.0
60
- scaled_baseline[:, 1] *= (time_w / 100.0) * 0.5
61
- scaled_baseline[:, 2] *= (time_w / 100.0) * 2.0
62
- scaled_baseline[:, 3] *= (ip_w / 100.0) * 10.0
63
  scaled_baseline[:, 4] *= action_scale
64
 
65
- new_data_point = np.array([[
66
- current_month * (time_w / 100.0) * 10.0,
67
- current_day * (time_w / 100.0) * 0.5,
68
- current_hour * (time_w / 100.0) * 2.0,
69
- ip_code * (ip_w / 100.0) * 10.0,
70
- action_code * action_scale
71
- ]])
72
 
73
  combined_X = np.vstack((scaled_baseline, new_data_point))
74
- strictness = max(2, int(2 + (overall_w / 100.0) * 4))
75
 
76
- model = HDBSCAN(min_cluster_size=strictness, min_samples=2)
 
 
 
77
  clusters = model.fit_predict(combined_X)
78
 
79
- if clusters[-1] == -1: return "⚠️異常_作息或行為不符"
80
- else: return "success"
81
- except ValueError:
82
- return "⚠️異常_未知特徵"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  def record_log(ip, cookie, account, role, action, status, time_mode, custom_time, ow, tw, iw, dw):
85
  global baseline_X
86
- if time_mode == "自訂時間 (模擬過去/未來)" and custom_time.strip() != "":
87
- log_time = custom_time
88
  else:
89
  tw_tz = datetime.timezone(datetime.timedelta(hours=8))
90
  log_time = datetime.datetime.now(tw_tz).strftime("%Y-%m-%d %H:%M:%S")
@@ -103,18 +126,18 @@ def record_log(ip, cookie, account, role, action, status, time_mode, custom_time
103
  try:
104
  pd.DataFrame([new_log]).to_csv('baseline_logs.csv', mode='a', header=False, index=False, encoding='utf-8-sig')
105
 
106
- current_time = pd.to_datetime(log_time)
107
- clean_ip = ip.split(" ")[0]
108
  new_row = np.array([[
109
- current_time.month,
110
- current_time.day,
111
- current_time.hour,
112
- le_ip.transform([clean_ip])[0],
113
- le_action.transform([action])[0]
114
- ]])
115
  baseline_X = np.vstack((baseline_X, new_row))
116
  except Exception as e:
117
- print(f"寫入 baseline 發生錯誤: {e}")
118
 
119
  return pd.DataFrame(log_history)
120
 
@@ -158,10 +181,8 @@ def simulate_click(ip, cookie, account, button_name, time_mode, custom_time, ow,
158
  role = USER_DB.get(account, ["", "Unknown"])[1]
159
  return record_log(ip, cookie, account, role, button_name, "success", time_mode, custom_time, ow, tw, iw, dw)
160
 
161
- # 🌟 新增:管理員專用的快速測試函式 (強制寫入指定的時間)
162
  def test_anomaly(ip, cookie, account, action_name, test_time_str, ow, tw, iw, dw):
163
  role = USER_DB.get(account, ["", "Unknown"])[1]
164
- # 強制將 time_mode 設為自訂,並傳入測試的具體時間
165
  return record_log(ip, cookie, account, role, action_name, "success", "自訂時間 (模擬過去/未來)", test_time_str, ow, tw, iw, dw)
166
 
167
  def logout(ip, cookie, account, time_mode, custom_time, ow, tw, iw, dw):
@@ -240,50 +261,50 @@ with gr.Blocks(title="模擬校園入口與資安防護系統", css=custom_css)
240
  ip_weight = gr.Number(label="IP 聲譽權重 (%)", value=65, minimum=0, maximum=100)
241
  device_weight = gr.Number(label="裝置指紋/行為權重 (%)", value=45, minimum=0, maximum=100)
242
 
243
- # 🌟 新增:HDBSCAN 自動化測試面板
244
  with gr.Accordion("▼ HDBSCAN 異常辨識自動化測試區", open=True, elem_classes="weight-card"):
245
  gr.Markdown("<span style='color:gray; font-size:0.9em;'>點擊按鈕將直接以指定時間點執行該系統的操作,結果將顯示於左側 Log 區。</span>")
246
 
 
247
  gr.Markdown("#### 1. 選課相關系統 (具備強烈季節性)")
248
  with gr.Row():
249
- t_pre_sel_norm = gr.Button("✅ 正常: 期末網路預選系統 (06-10 22:00)", size="sm")
250
- t_pre_sel_anom = gr.Button("⚠️ 異常: 期末網路預選系統 (10-15 14:00)", size="sm")
251
  with gr.Row():
252
- t_course_norm = gr.Button("✅ 正常: 課程系統 (02-15 16:00)", size="sm")
253
- t_course_anom = gr.Button("⚠️ 異常: 課程系統 (05-20 09:00)", size="sm")
254
  with gr.Row():
255
- t_add_drop_norm = gr.Button("✅ 正常: 開學後加退選系統 (09-15 08:00)", size="sm")
256
- t_add_drop_anom = gr.Button("⚠️ 異常: 開學後加退選系統 (04-10 21:00)", size="sm")
257
 
258
  gr.Markdown("#### 2. 期末與成績相關 (具備週期性)")
259
  with gr.Row():
260
- t_eval_norm = gr.Button("✅ 正常: 期末網路教學評量 (12-20 23:00)", size="sm")
261
- t_eval_anom = gr.Button("⚠️ 異常: 期末網路教學評量 (03-05 11:00)", size="sm")
262
  with gr.Row():
263
- t_score_norm = gr.Button("✅ 正常: 學業成績查詢系統 (04-20 11:00)", size="sm")
264
- t_score_anom = gr.Button("⚠️ 異常: 學業成績查詢系統 (08-15 10:00)", size="sm")
265
 
266
  gr.Markdown("#### 3. 校務與行政服務 (生活與常規)")
267
  with gr.Row():
268
- t_dorm_norm = gr.Button("✅ 正常: 學生宿舍登錄(抽籤)系統 (07-25 16:00)", size="sm")
269
- t_dorm_anom = gr.Button("⚠️ 異常: 學生宿舍登錄(抽籤)系統 (11-15 14:00)", size="sm")
270
  with gr.Row():
271
- t_schol_norm = gr.Button("✅ 正常: 獎助學金申請系統 (03-15 12:00)", size="sm")
272
- t_schol_anom = gr.Button("⚠️ 異常: 獎助學金申請系統 (08-10 05:00)", size="sm")
273
  with gr.Row():
274
- t_card_norm = gr.Button("✅ 正常: 學生證掛失 (任何月份 16:00)", size="sm")
275
- t_card_anom = gr.Button("⚠️ 異常: 學生證掛失 (任何月份 04:00)", size="sm")
276
 
277
  gr.Markdown("#### 4. 學習與日常輔助系統 (具備作息規律)")
278
  with gr.Row():
279
- t_istudy_norm = gr.Button("✅ 正常: 北科i學園PLUS (03-20 13:00)", size="sm")
280
- t_istudy_anom = gr.Button("⚠️ 異常: 北科i學園PLUS (06-29 03:00)", size="sm")
281
  with gr.Row():
282
- t_leave_norm = gr.Button("✅ 正常: 學生請假系統 (10-05 08:00)", size="sm")
283
- t_leave_anom = gr.Button("⚠️ 異常: 學生請假系統 (週日 02:00)", size="sm")
284
  with gr.Row():
285
- t_vdesk_norm = gr.Button("✅ 正常: 軟體雲/WebMail (11-10 10:00)", size="sm")
286
- t_vdesk_anom = gr.Button("⚠️ 異常: 軟體雲/WebMail (深夜 04:00)", size="sm")
287
 
288
  # --- 綁定事件 ---
289
  time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
@@ -326,37 +347,33 @@ with gr.Blocks(title="模擬校園入口與資安防護系統", css=custom_css)
326
  outputs=[log_display]
327
  )
328
 
329
- # 🌟 綁定自動化測試按鈕 (帶入固定時間字串)
330
  test_mapping = [
331
- # 1. 選課相關
332
- (t_pre_sel_norm, "click_pre_select_system", "2026-06-10 22:00:00"),
333
- (t_pre_sel_anom, "click_pre_select_system", "2026-10-15 14:00:00"),
334
- (t_course_norm, "click_course_system", "2026-02-15 16:00:00"),
335
- (t_course_anom, "click_course_system", "2026-05-20 09:00:00"),
336
- (t_add_drop_norm, "click_add_drop_system", "2026-09-15 08:00:00"),
337
- (t_add_drop_anom, "click_add_drop_system", "2026-04-10 21:00:00"),
338
 
339
- # 2. 期末與成績
340
- (t_eval_norm, "click_eval_system", "2026-12-20 23:00:00"),
341
- (t_eval_anom, "click_eval_system", "2026-03-05 11:00:00"),
342
- (t_score_norm, "click_score_query", "2026-04-20 11:00:00"),
343
- (t_score_anom, "click_score_query", "2026-08-15 10:00:00"),
344
 
345
- # 3. 校務與行政
346
- (t_dorm_norm, "click_dorm_system", "2026-07-25 16:00:00"),
347
- (t_dorm_anom, "click_dorm_system", "2026-11-15 14:00:00"),
348
- (t_schol_norm, "click_scholarship", "2026-03-15 12:00:00"),
349
- (t_schol_anom, "click_scholarship", "2026-08-10 05:00:00"),
350
- (t_card_norm, "click_card_loss", "2026-10-01 16:00:00"), # 任何月份,取 10 月代表
351
- (t_card_anom, "click_card_loss", "2026-10-01 04:00:00"),
352
 
353
- # 4. 學習與日常
354
- (t_istudy_norm, "click_istudy", "2026-03-20 13:00:00"),
355
- (t_istudy_anom, "click_istudy", "2026-06-29 03:00:00"),
356
- (t_leave_norm, "click_leave_system", "2026-10-05 08:00:00"),
357
- (t_leave_anom, "click_leave_system", "2026-10-11 02:00:00"), # 10/11 是週日
358
- (t_vdesk_norm, "click_vdesk", "2026-11-10 10:00:00"),
359
- (t_vdesk_anom, "click_vdesk", "2026-11-10 04:00:00")
360
  ]
361
 
362
  for btn, action_name, test_time_str in test_mapping:
 
44
  if action in ["login_attempt", "logout"]: return "success"
45
 
46
  try:
47
+ ow = float(overall_w)
48
+ tw = float(time_w)
49
+ iw = float(ip_w)
50
+ dw = float(dev_w)
51
 
52
+ clean_ip = str(ip).split(" ")[0]
53
+ ip_code = float(le_ip.transform([clean_ip])[0])
54
+ action_code = float(le_action.transform([action])[0])
 
55
 
56
+ current_time = pd.to_datetime(str(log_time))
57
+ current_month = float(current_time.month)
58
+ current_day = float(current_time.day)
59
+ current_hour = float(current_time.hour)
60
+
61
+ time_multiplier = tw / 100.0
62
+ action_scale = (dw / 100.0) * 100.0
63
 
64
  scaled_baseline = baseline_X.copy().astype(float)
65
+ scaled_baseline[:, 0] *= time_multiplier * 10.0
66
+ scaled_baseline[:, 1] *= time_multiplier * 0.5
67
+ scaled_baseline[:, 2] *= time_multiplier * 2.0
68
+ scaled_baseline[:, 3] *= (iw / 100.0) * 10.0
69
  scaled_baseline[:, 4] *= action_scale
70
 
71
+ v_month = current_month * time_multiplier * 10.0
72
+ v_day = current_day * time_multiplier * 0.5
73
+ v_hour = current_hour * time_multiplier * 2.0
74
+ v_ip = ip_code * (iw / 100.0) * 10.0
75
+ v_action = action_code * action_scale
76
+
77
+ new_data_point = np.array([[v_month, v_day, v_hour, v_ip, v_action]], dtype=float)
78
 
79
  combined_X = np.vstack((scaled_baseline, new_data_point))
80
+ strictness = max(2, int(2 + (ow / 100.0) * 4))
81
 
82
+ model = HDBSCAN(
83
+ min_cluster_size=strictness,
84
+ min_samples=2
85
+ )
86
  clusters = model.fit_predict(combined_X)
87
 
88
+ if clusters[-1] == -1:
89
+ return "⚠️異常_作息或行為不符"
90
+
91
+ same_action_mask = (baseline_X[:, 4] == action_code)
92
+
93
+ if np.any(same_action_mask):
94
+ history_points = scaled_baseline[same_action_mask]
95
+ distances = np.linalg.norm(history_points - new_data_point[0], axis=1)
96
+ min_distance = np.min(distances)
97
+
98
+ max_tolerance_distance = time_multiplier * 15.0 + 1.0
99
+
100
+ if min_distance > max_tolerance_distance:
101
+ return "⚠️異常_作息或行為不符"
102
+
103
+ return "success"
104
+ except Exception as e:
105
+ return f"⚠️系統錯誤: {str(e)}"
106
 
107
  def record_log(ip, cookie, account, role, action, status, time_mode, custom_time, ow, tw, iw, dw):
108
  global baseline_X
109
+ if time_mode == "自訂時間 (模擬過去/未來)" and custom_time and str(custom_time).strip() != "":
110
+ log_time = str(custom_time)
111
  else:
112
  tw_tz = datetime.timezone(datetime.timedelta(hours=8))
113
  log_time = datetime.datetime.now(tw_tz).strftime("%Y-%m-%d %H:%M:%S")
 
126
  try:
127
  pd.DataFrame([new_log]).to_csv('baseline_logs.csv', mode='a', header=False, index=False, encoding='utf-8-sig')
128
 
129
+ current_time = pd.to_datetime(str(log_time))
130
+ clean_ip = str(ip).split(" ")[0]
131
  new_row = np.array([[
132
+ float(current_time.month),
133
+ float(current_time.day),
134
+ float(current_time.hour),
135
+ float(le_ip.transform([clean_ip])[0]),
136
+ float(le_action.transform([action])[0])
137
+ ]], dtype=float)
138
  baseline_X = np.vstack((baseline_X, new_row))
139
  except Exception as e:
140
+ pass
141
 
142
  return pd.DataFrame(log_history)
143
 
 
181
  role = USER_DB.get(account, ["", "Unknown"])[1]
182
  return record_log(ip, cookie, account, role, button_name, "success", time_mode, custom_time, ow, tw, iw, dw)
183
 
 
184
  def test_anomaly(ip, cookie, account, action_name, test_time_str, ow, tw, iw, dw):
185
  role = USER_DB.get(account, ["", "Unknown"])[1]
 
186
  return record_log(ip, cookie, account, role, action_name, "success", "自訂時間 (模擬過去/未來)", test_time_str, ow, tw, iw, dw)
187
 
188
  def logout(ip, cookie, account, time_mode, custom_time, ow, tw, iw, dw):
 
261
  ip_weight = gr.Number(label="IP 聲譽權重 (%)", value=65, minimum=0, maximum=100)
262
  device_weight = gr.Number(label="裝置指紋/行為權重 (%)", value=45, minimum=0, maximum=100)
263
 
 
264
  with gr.Accordion("▼ HDBSCAN 異常辨識自動化測試區", open=True, elem_classes="weight-card"):
265
  gr.Markdown("<span style='color:gray; font-size:0.9em;'>點擊按鈕將直接以指定時間點執行該系統的操作,結果將顯示於左側 Log 區。</span>")
266
 
267
+ # 🌟 按鈕文字已更新為最新測試時間 🌟
268
  gr.Markdown("#### 1. 選課相關系統 (具備強烈季節性)")
269
  with gr.Row():
270
+ t_pre_sel_norm = gr.Button("✅ 正常: 初選系統 (06-13 11:00)", size="sm")
271
+ t_pre_sel_anom = gr.Button("⚠️ 異常: 初選系統 (10-15 13:00)", size="sm")
272
  with gr.Row():
273
+ t_course_norm = gr.Button("✅ 正常: 選課系統 (02-25 07:50)", size="sm")
274
+ t_course_anom = gr.Button("⚠️ 異常: 選課系統 (07-15 05:00)", size="sm")
275
  with gr.Row():
276
+ t_add_drop_norm = gr.Button("✅ 正常: 加退選系統 (02-18 01:00)", size="sm")
277
+ t_add_drop_anom = gr.Button("⚠️ 異常: 加退選系統 (05-15 12:00)", size="sm")
278
 
279
  gr.Markdown("#### 2. 期末與成績相關 (具備週期性)")
280
  with gr.Row():
281
+ t_eval_norm = gr.Button("✅ 正常: 教學評鑑 (12-17 13:20)", size="sm")
282
+ t_eval_anom = gr.Button("⚠️ 異常: 教學評鑑 (03-15 03:00)", size="sm")
283
  with gr.Row():
284
+ t_score_norm = gr.Button("✅ 正常: 成績查詢 (11-17 18:50)", size="sm")
285
+ t_score_anom = gr.Button("⚠️ 異常: 成績查詢 (02-15 03:00)", size="sm")
286
 
287
  gr.Markdown("#### 3. 校務與行政服務 (生活與常規)")
288
  with gr.Row():
289
+ t_dorm_norm = gr.Button("✅ 正常: 宿舍系統 (07-21 23:10)", size="sm")
290
+ t_dorm_anom = gr.Button("⚠️ 異常: 宿舍系統 (11-15 16:00)", size="sm")
291
  with gr.Row():
292
+ t_schol_norm = gr.Button("✅ 正常: 獎學金申請 (03-12 14:00)", size="sm")
293
+ t_schol_anom = gr.Button("⚠️ 異常: 獎學金申請 (08-15 02:00)", size="sm")
294
  with gr.Row():
295
+ t_card_norm = gr.Button("✅ 正常: 學生證掛失 (10-23 13:40)", size="sm")
296
+ t_card_anom = gr.Button("⚠️ 異常: 學生證掛失 (08-10 03:00)", size="sm")
297
 
298
  gr.Markdown("#### 4. 學習與日常輔助系統 (具備作息規律)")
299
  with gr.Row():
300
+ t_istudy_norm = gr.Button("✅ 正常: iStudy 平台 (10-18 16:00)", size="sm")
301
+ t_istudy_anom = gr.Button("⚠️ 異常: iStudy 平台 (08-20 02:00)", size="sm")
302
  with gr.Row():
303
+ t_leave_norm = gr.Button("✅ 正常: 請假系統 (03-29 08:45)", size="sm")
304
+ t_leave_anom = gr.Button("⚠️ 異常: 請假系統 (08-15 13:00)", size="sm")
305
  with gr.Row():
306
+ t_vdesk_norm = gr.Button("✅ 正常: 軟體雲/信箱 (03-22 18:00)", size="sm")
307
+ t_vdesk_anom = gr.Button("⚠️ 異常: 軟體雲/信箱 (08-10 00:00)", size="sm")
308
 
309
  # --- 綁定事件 ---
310
  time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
 
347
  outputs=[log_display]
348
  )
349
 
350
+ # 🌟 內部參數 Mapping 已更新為最新測試時間 🌟
351
  test_mapping = [
352
+ (t_pre_sel_norm, "click_pre_select_system", "2026-06-13 11:00:00"),
353
+ (t_pre_sel_anom, "click_pre_select_system", "2026-10-15 13:00:00"),
354
+ (t_course_norm, "click_course_system", "2026-02-25 07:50:00"),
355
+ (t_course_anom, "click_course_system", "2026-07-15 05:00:00"),
356
+ (t_add_drop_norm, "click_add_drop_system", "2026-02-18 01:00:00"),
357
+ (t_add_drop_anom, "click_add_drop_system", "2026-05-15 12:00:00"),
 
358
 
359
+ (t_eval_norm, "click_eval_system", "2026-12-17 13:20:00"),
360
+ (t_eval_anom, "click_eval_system", "2026-03-15 03:00:00"),
361
+ (t_score_norm, "click_score_query", "2026-11-17 18:50:00"),
362
+ (t_score_anom, "click_score_query", "2026-02-15 03:00:00"),
 
363
 
364
+ (t_dorm_norm, "click_dorm_system", "2026-07-21 23:10:00"),
365
+ (t_dorm_anom, "click_dorm_system", "2026-11-15 16:00:00"),
366
+ (t_schol_norm, "click_scholarship", "2026-03-12 14:00:00"),
367
+ (t_schol_anom, "click_scholarship", "2026-08-15 02:00:00"),
368
+ (t_card_norm, "click_card_loss", "2026-10-23 13:40:00"),
369
+ (t_card_anom, "click_card_loss", "2026-08-10 03:00:00"),
 
370
 
371
+ (t_istudy_norm, "click_istudy", "2026-10-18 16:00:00"),
372
+ (t_istudy_anom, "click_istudy", "2026-08-20 02:00:00"),
373
+ (t_leave_norm, "click_leave_system", "2026-03-29 08:45:00"),
374
+ (t_leave_anom, "click_leave_system", "2026-08-15 13:00:00"),
375
+ (t_vdesk_norm, "click_vdesk", "2026-03-22 18:00:00"),
376
+ (t_vdesk_anom, "click_vdesk", "2026-08-10 00:00:00")
 
377
  ]
378
 
379
  for btn, action_name, test_time_str in test_mapping: