---
title: L1 檢查結果：日誌轉送全鏈（jedi-log）
---

# L1 檢查結果：日誌轉送全鏈（jedi-log）

> 檢查日期 2026-09-15｜耗時 1 小時 29 分｜對應卡片 CM-1811｜檢查範圍 39 個檔案

---

## 🔴 一句話結論

**兩條新問題，都是中風險：一是「日誌送到外部伺服器的路上完全沒有加密」，二是「有心人可以在日誌裡塞偽造的假紀錄」。都不是「誰能改設定」這類權限漏洞，而是「送出去的資料本身」不夠安全。**

---

## 這一棒在檢查什麼

系統可以把自己產生的日誌即時送到外部伺服器（客戶自己的資安監控系統，即 SIEM）。這一棒檢查的就是這條完整路徑的 39 個檔案：從「設定頁的三支 API」一路到「實際送出網路封包的背景程式」，再到「隨套件出貨的兩支資料庫腳本」。

要回答的核心問題是：**誰改得動「日誌要送去哪裡」，以及送出去的東西夠不夠安全。**

---

## 掃到什麼：總覽表

| # | 嚴重度 | 這是什麼問題 | 出事會怎樣 | 要先有什麼才打得到 | 在哪裡 | 狀態 |
|---|---|---|---|---|---|---|
| **F1** | 🟡 中 | **日誌送到外部伺服器的整條路上完全沒有加密選項** | 只要有人能在網路傳輸路徑上偷看封包（例如同一個機房網段、或被入侵的交換器），就能原封不動看到整份轉送出去的日誌內容，包含操作者身分與其他敏感資料 | ① 管理員已把日誌轉送功能設定好、指向真實的伺服器<br>② 攻擊者要能站在「應用程式主機」到「日誌伺服器」這條網路路徑上 | `jedi_api_log/forwarding/common/forwarder.py:181` | 🆕 **新增** |
| **F2** | 🟡 中 | **送出去的日誌內容沒有過濾換行符號，可以被塞入偽造紀錄** | 有心人可以在系統會記錄下來的欄位（例如登入帳號）裡藏換行符號加一段偽造內容，這段偽造內容會被當成獨立一筆「真的」日誌送到客戶的 SIEM，等於能捏造假的稽核紀錄 | ① 日誌轉送功能已啟用（系統預設就是啟用的）且協定選 syslog<br>② 有一個使用者能碰到的欄位，其值會被原封不動寫進日誌 | `jedi_api_log/forwarding/common/forwarder.py:232` | 🆕 **新增** |

**淨結果：工具提報 2 條候選，全數通過驗證，都是新發現，都是中風險。**

---

## 每條發現的詳述

### F1：日誌轉送沒有加密選項

**現況**：已修（M09-3，CM-2056，1.21.0 出貨）

**①這是什麼問題**：日誌轉送功能不管選哪個通訊協定（syslog 或 gelf）、走 UDP 還是 TCP，全部走「不加密」的傳輸方式，套件裡完全沒有任何加密相關的程式碼。

**②出事會怎樣**：轉送出去的內容包含應用程式日誌與稽核事件——操作者身分、事件細節，以及其他業務資料可能夾帶的內容。跨 arc 總表已登記的一項待辦（BE 日誌會原文記下請求內容，包含密碼）意味著這些明文密碼也有機會經由這條沒加密的管道被送出去。任何能在網路傳輸路徑上偷看封包的人，都能原封不動看到這些內容。

**③要先有什麼才打得到**：
- 管理員已經把日誌轉送功能設定好、指向一台真實的伺服器（這是管理員的操作，不是預設狀態）
- 攻擊者要能站在「應用程式主機」到「客戶指定的日誌伺服器」這段網路路徑上（例如同一個機房網段、被入侵的交換器、或攔截 WAN 線路的設備）——這套系統主要是落地部署給客戶，這段路徑很可能跨出單一信任邊界

**④在哪裡**：`jedi_api_log/forwarding/common/forwarder.py:181`（`build_target_handler` 函式，組出 syslog 的 handler），同樣的問題也存在於 `common/gelf_handler.py` 的 gelf 傳輸實作。

**⑤怎麼修**：幫兩種傳輸協定都加上可選的 TLS 傳輸方式（syslog 走 RFC 5425 TLS syslog，或至少用 `ssl.wrap_socket`/`SSLContext` 包一層 TCP+TLS），並且要把這個選項開放在設定 API 的 `transport` 欄位上（目前只能選 `udp`/`tcp`）。

**首腦補充（驗證細節）**：三位檢查員中有一位對「這條打不打得到」持保留意見，理由是「誰改得動轉送目的地」是管理員層級的操作，不是攻擊者能直接觸發的。另外兩位（影響面、有沒有防護）都判定成立。所以最終是 2 票對 1 票通過，可信度標為「中」而非「高」，但這不影響它是真實存在的缺口——**沒有加密選項本身就是問題**，不管是誰設定的目的地。

---

### F2：日誌轉送內容可被塞入偽造紀錄（日誌注入）

**現況**：已修（M09-4，CM-2055，1.21.0 出貨）

**①這是什麼問題**：組出要送出去的 syslog 格式訊息時，程式沒有過濾掉訊息內容裡的換行符號。

**②出事會怎樣**：如果攻擊者能讓某個值（例如登入帳號欄位）被寫進會被轉送的日誌裡，而這個值裡藏了換行符號加一段偽造的內容，這段偽造內容送到客戶的 SIEM 之後，很多解析器會把這個換行符號當成「這是新的一筆紀錄」，於是偽造內容就變成一筆「看起來是真的」的獨立日誌，等於能捏造假的操作紀錄、混淆事後追查。

**③要先有什麼才打得到**：
- 日誌轉送功能要是啟用狀態，而且協定要選 syslog、有設定好的主機與埠號（系統預設就是啟用的，不需要額外開啟）
- 要有一個使用者能碰到的欄位，它的值會被原封不動記進日誌裡（例如登入時輸入的帳號）

**④在哪裡**：`jedi_api_log/forwarding/common/forwarder.py:232`（`_Rfc5424Formatter.format` 函式，組出最終要送出去的那一行文字）

**⑤怎麼修**：在組出 syslog 那一行文字之前，把訊息內容裡的換行符號（`\r`、`\n`）等控制字元過濾或替換掉，做法可以參考同套件裡 gelf 傳輸方式的處理——它已經把不可控的文字限制在第一行。

**首腦補充（驗證細節）**：三位檢查員一致判定成立（3 票全過），其中一位親自用測試用的 Flask 客戶端送出帶編碼換行符號的請求，實際驗證了換行符號能一路傳到轉送格式化那一行——這是本棒唯一一條有實際操作驗證（非僅讀程式碼推論）的發現，可信度標為「高」。

---

## 已知、非本棒新發現（照卡片交代核對）

卡片開卡前已經查證過三件事，這一棒掃到的內容與這三件一致，**不重複計數**：

1. **三支轉送端點在套件裡沒掛任何權限裝飾器**——這是刻意設計（守門由主專案宿主注入），已經追到 `core/plugins/api_log.py:185-186` 確實有掛上「要登入＋要有對應權限」，讀跟寫是兩個不同的權限。這次掃描沒有誤報成「無守門」。
2. **轉送設定表沒有做客戶隔離**——建表腳本檔頭已寫明理由（平台層設定、背景執行緒沒有請求脈絡）。這次掃描沒有把它當成漏洞誤報。
3. **設定表裡沒有帳號密碼欄位**——這次逐欄核對過建表腳本，確認沒有帳密欄位，跨 arc 總表先前那句「轉送設定裡包含帳密」的說法已經是錯的、不需要再更正一次。

---

## 這份結果可信到什麼程度

### 「這兩條是真的嗎」→ ✅ 可信

- 兩條發現都通過三位獨立檢查員投票：F1 是 2 票對 1 票通過，F2 是 3 票全過。
- F2 有一位檢查員實際打過測試請求驗證換行符號真的能傳到底，不是只憑讀程式碼推論。
- F1 的疑慮不是「這條不成立」，而是「誰能觸發它」這件事上有一票保留——已如實反映在信心等級上，不影響發現本身存在。

### 「是不是只有這兩條」→ ❌ 不完全可信，理由如下

**這是最低強度快篩，不是全面檢查。** 用的是 `low` 強度：一位研究員把 39 個檔案讀完就提報候選，不做元件盤點、不做威脅建模、不跑額外的密鑰專項掃描（雖然如此，低強度仍內建一次密鑰檢查，未在本次掃到已知密鑰洩漏）。所有結論都來自「讀程式碼」，唯一的例外是 F2 的那一次實測請求；**其餘沒有實際打過 API、沒有做過完整的攻擊鏈驗證。**

卡片上列了六個重點追查方向（本棒最重要的一條是「客戶層級權限改到全系統共用設定」），本次掃描的兩條發現落在「加密」與「注入」這兩個方向，**卡片重點①（客戶管理員權限改到全域設定）沒有被工具直接提出成候選**——這不代表那個疑點不成立，只代表這次的研究員視角沒有把它獨立寫成一條發現。下一棒接手或後續複核時，這一點仍待另外確認。

---

## 執行概況

| 項目 | 數字 |
|---|---|
| 檢查範圍 | 39 個檔案（與卡片逐檔對上） |
| 檢查強度 | 最低（`low`），未設定 focus（範圍已經夠小，全讀） |
| 派出／回報的 agent | 7 / 7（1 位研究員＋6 個投票 agent） |
| 候選問題 → 去除重複 | 2 → 2 |
| 投票數 | **6**（2 條發現 × 3 位檢查員） |
| F1 投票結果 | 2 票通過 / 1 票不同意（REACHABILITY 持保留） |
| F2 投票結果 | 3 票全過 |
| 沒投到票的 / 投票中斷的 / 被降低嚴重度的 | 0 / 0 / 0 |
| 驗證章狀態 | `verified`（無拒收理由） |
| 掃描當下的程式碼版本 | commit `9b35885b2723`，branch `main`，工作區乾淨 |
| 耗時 | 1 小時 29 分（5372 秒） |
| 花費 token（子 agent 累計） | 約 113 萬 |

---

> 📄 本報告由 runner（本棒 session）依工具原始產物撰寫，非首腦補寫。
