iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
AI Security

《30 天從零打造資安語言模型:從微調到 Agent 落地》系列 第 16 篇

Day 16|任務一:Incident Data Pack — 別把原始 JSON 丟給模型

  • 分享至 

  • xImage
  •  

本文所有資料皆為合成資料。主機名、IP、公司名、時間、事件經過全部虛構;CVE 編號使用真實公開漏洞,但受影響資產為虛構。

問題:原始 case 長什麼樣

XDR / SIEM 平台匯出的一筆 case,實際上可能有上百個欄位、多層巢狀、還帶著平台自己的內部識別碼。長這樣(大幅簡化過的合成範例):

{
  "case_id": "CASE-2026-0731-0042",
  "tenant_id": "t_9f3a2b",
  "created_ts": 1785312840,
  "updated_ts": 1785316200,
  "severity_raw": 4,
  "status": "open",
  "assignee": null,
  "alerts": [
    {
      "alert_id": "ALT-88213",
      "rule_id": "R-1042",
      "rule_name": "Suspicious PowerShell Encoded Command",
      "ts": 1785312840,
      "endpoint": {"hostname": "TW-FIN-WS-014", "ip": "10.42.7.51", "os": "Windows 11 23H2"},
      "process": {"name": "powershell.exe", "cmdline": "powershell -enc SQBFAFgA...", "parent": "outlook.exe"},
      "mitre": ["T1059.001", "T1566.001"]
    },
    {
      "alert_id": "ALT-88219",
      "rule_id": "R-2210",
      "rule_name": "Outbound Connection to Low-Reputation Host",
      "ts": 1785313920,
      "endpoint": {"hostname": "TW-FIN-WS-014", "ip": "10.42.7.51"},
      "network": {"dst_ip": "203.0.113.77", "dst_port": 443, "bytes_out": 184320},
      "mitre": ["T1071.001"]
    }
  ],
  "raw_telemetry_ref": "s3://...",
  "_internal_score": 0.83,
  "_model_version": "det-4.2.1"
}

如果你把這整包丟給模型說「寫一份報告」,會發生四件事:

  1. 它可能把 _internal_score: 0.83 寫進報告,說「本事件風險評分 0.83」——那是平台內部的偵測信心分數,不是風險評分,客戶會誤解
  2. 它會把 severity_raw: 4 直接翻成「嚴重性 4」,但你們對客戶用的是「高/中/低」三級
  3. 它不知道 T1059.001 是什麼,會亂猜或省略
  4. 兩個告警的時間關聯(相隔 18 分鐘)它可能算錯,或根本不算

解法:Incident Data Pack

在原始資料與模型之間插一層確定性的組裝程序,產出一個乾淨、完整、語意明確的資料包。模型只看資料包。

Data Pack 的結構(合成範例):

{
  "pack_version": "1.0",
  "incident": {
    "ref": "IR-2026-0731-014",
    "client_display_name": "【客戶名稱】",
    "detected_at_local": "2026-07-31 14:14 (UTC+8)",
    "duration_minutes": 56,
    "severity": "高",
    "severity_basis": "涉及使用者端點的可疑執行行為,並觀察到後續對外連線"
  },
  "affected_assets": [
    {
      "hostname": "TW-FIN-WS-014",
      "asset_class": "使用者工作站",
      "business_owner_dept": "財務部",
      "criticality": "中",
      "os": "Windows 11 23H2"
    }
  ],
  "timeline": [
    {
      "seq": 1,
      "time_local": "14:14",
      "event": "偵測到經過編碼的 PowerShell 指令執行",
      "parent_process": "outlook.exe",
      "technique": {"id": "T1059.001", "name": "命令與指令碼直譯器:PowerShell"},
      "source_rule": "Suspicious PowerShell Encoded Command"
    },
    {
      "seq": 2,
      "time_local": "14:32",
      "event": "同一端點對低信譽外部主機建立連線",
      "destination": "203.0.113.77:443",
      "bytes_out": 184320,
      "technique": {"id": "T1071.001", "name": "應用層協定:Web 協定"},
      "source_rule": "Outbound Connection to Low-Reputation Host"
    }
  ],
  "technique_summary": [
    {"id": "T1566.001", "name": "網路釣魚:附件", "tactic": "初始存取", "confidence": "推測"},
    {"id": "T1059.001", "name": "PowerShell", "tactic": "執行", "confidence": "已觀察"},
    {"id": "T1071.001", "name": "Web 協定", "tactic": "命令與控制", "confidence": "已觀察"}
  ],
  "related_cves": [],
  "ioc": [
    {"type": "ip", "value": "203.0.113.77", "reputation": "低信譽", "source": "威脅情報比對"}
  ],
  "client_preferences": {
    "severity_scale": "三級(高/中/低)",
    "avoid_abbreviations": true,
    "recommendation_split": ["立即", "中長期"]
  },
  "provenance": {
    "source_case_id": "CASE-2026-0731-0042",
    "assembled_at": "2026-07-31 15:10",
    "assembled_by": "datapack-builder v1.0"
  }
}

Data Pack 的六個設計原則

一、語意明確,沒有任何需要猜的欄位。 severity_raw: 4 變成 severity: "高",而且附上 severity_basis 說明依據。模型不需要知道映射規則,它只需要照著寫。

二、時間全部本地化並排序。 Unix timestamp 換成本地時間,事件按 seq 排好。時間差(duration_minutes)由程式算,不讓模型算。

三、技術編號一律附上名稱與戰術階段。 T1059.001 對模型是一串沒意義的字元。展開成名稱、戰術階段、以及信心程度(已觀察 vs 推測)。最後那項很重要——它讓模型知道哪些可以斷言、哪些要用推測語氣。

四、資產帶上業務脈絡。 asset_class、business_owner_dept、criticality 這些欄位不在原始 case 裡,是從資產清單(CMDB)查來的。這是報告能不能寫出「業務影響」的關鍵。 沒有它,模型只能寫「某台主機」;有了它,才能寫「財務部使用的工作站」。

五、客戶偏好內嵌。 Day 15 提過的客戶怪癖,直接放在 Data Pack 裡。模型每次都看得到。

六、Provenance 必填。 來源 case id、組裝時間、組裝程式版本。這是 Day 25「事實必回溯」與 Day 24 稽核軌跡的基礎。任何一份報告都要能回推到它是從哪一筆原始資料、用哪一版程式產生的。

空欄位的處理

注意 related_cves 是空陣列。這個案例沒有關聯到已知漏洞。

空欄位絕對不能省略。 如果你的組裝程式在沒有資料時直接不輸出那個欄位,模型會不知道是「沒有」還是「沒查」。明確地給一個空陣列,並且在 prompt 裡規定「空陣列代表已查詢但無結果」。

我踩過這個坑:某次報告漏了漏洞關聯段落,追查半天才發現是欄位沒輸出,模型以為那個主題不存在。

Data Pack 帶來的額外好處

當初做這層是為了報告品質,但它後來帶來三個沒預期的好處:

一、可測試。 Data Pack 是純函式的輸出——同樣的 case 進去,同樣的 pack 出來。可以寫單元測試,可以回歸驗證。而模型的輸出沒辦法這樣測。

二、可換模型。 換掉底層模型時,Data Pack 完全不用動。這是 Day 29 那句「模型可換」的具體實現。

三、可審計。 審核者如果覺得報告哪裡怪,可以直接看 Data Pack——是資料錯了還是模型寫錯了,一眼就分得出來。

明天用這個 Data Pack 實際產一份報告。


🛡️ Instagram: @aid3fend — AI 資安實戰紀錄,歡迎追蹤交流。



上一篇
Day 15|從模型到產品:Agent 架構總覽與那條共同語法
下一篇
Day 17|任務一實作:從 Data Pack 到報告初稿
系列文
《30 天從零打造資安語言模型:從微調到 Agent 落地》 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言