前言¶
智能體開發裏有一個反覆出現的場景:把帶密鑰的配置文件、.env、連接串丟進對話,或者讓工具執行後把輸出送回上下文。憑證一旦進入上下文,模型可能把它原樣寫進日誌、代碼和回覆裏。靠提示詞提醒「不要泄露密鑰」並不可靠,因爲模型拿到文本時已經看到了明文。
dsh-sensitive-guard 就是爲這件事做的插件:不是提醒,而是在用戶輸入和工具結果進入上下文之前就把憑證替換成 <SG_xxxxxxxxxxxx> 佔位符,明文加密留在本機保管庫,需要用的時候再點開或導出。
下面介紹這個插件:它安裝在哪、攔截哪些入口、認得出什麼、配置怎麼改,以及哪些邊界要提前知道。
定位¶
插件名稱 dsh-sensitive-guard,維護者 wangxy496,分類 admin-security,許可證 MIT,當前版本 0.5.0(以 npm 包爲準)。目標只做一件事:密鑰、令牌、密碼在進入模型上下文前被換成 <SG_ 前綴的代號,明文以 AES-256-GCM 加密保存在本地保管庫。模型拿到的是代號,用戶點一下鎖能看到真值。
代號裏 12 位十六進制是 HMAC-SHA256(vault.key, 明文) 的前綴。密鑰只在本機,所以拿到代號的人沒法靠窮舉短密碼反推;同一個密鑰每次得到同一個代號。0.3.4 及更早版本用的是 sha256(明文) 前綴,短密碼可以離線猜出來,升級後舊代號仍保留可解鎖,新捕獲一律換成新算法。
核心功能¶
插件分 host 端和客戶端兩半:host 端抓數據、管保管庫、開接口;客戶端加設置頁和對話裏的鎖形膠囊。
| 註冊點 | 端 | 作用 |
|---|---|---|
agent/pre-step |
host 鉤子 | 用戶輸入進上下文前脫敏 |
tools/post-execute |
host 鉤子 | 工具結果進上下文前脫敏 |
llm/stream |
host 鉤子 | 出網的流式文本兜底清洗 |
sensitive_guard_status、sensitive_guard_export |
host 工具 | 查狀態;把明文導出成 0600 臨時文件 |
/guard/* |
HTTP 路由 | 設置頁取數、揭示明文、暫停/關閉保護、規則清單與開關、手動錄入 |
settings.section |
客戶端 slot | 設置頁裏的「敏感保護」 |
conversation.user.text.node |
客戶端 slot | 對話裏的鎖形膠囊 |
前提只要 tools 一個。webServer 不存在時脫敏照常工作,只是設置頁和揭示用不了。
攔截點有兩層:用戶輸入走 agent/pre-step,工具結果走 tools/post-execute;llm/stream 再洗一遍出網的流式文本做兜底,只處理 text-delta 和 reasoning-delta,tool-call-delta 直接放過,否則工具參數會被替換成佔位符。
安裝¶
要求 dsh 0.2.0 以上、Node 18 以上。Windows 11 和 Ubuntu 22.04 均實測,macOS 未測。資料裏給了三種裝法,這裏列前兩種。
第一種直接編輯 ~/.dsh/profiles/<profile>/package.json:
{
"dependencies": {
"dsh-sensitive-guard": "0.5.0"
},
"dsh": {
"profile": {
"bundles": ["dsh-sensitive-guard"]
}
}
}
bundles 裏保留原有條目,只追加這一行。然後在同目錄跑 pnpm install,重啓 dsh。
第二種讓 dsh 自己裝,在會話裏說「安裝這個目錄下的插件:/絕對/路徑」,它會走 install_bundle。
裝完後可以驗證。發一句:
我的 api key 是 sk-proj-abcdefghijklmnopqrstuvwx
應該顯示成 我的 api key 是 sk- 加一個鎖形膠囊。點開能看到明文,20 秒後自動遮回。再打開「設置 → 敏感保護」,最下面一行 inline reveal: 顯示 ok 即正常。
日常使用¶
用戶消息裏的佔位符會渲染成可點的膠囊,顏色按類型分:密碼紅、token 紫、key 綠、其它藍,點開後統一變橙。點擊走本機接口,明文不經過模型。
注意:只有用戶消息的膠囊能點。AI 回覆和工具結果走另一套節點渲染,宿主沒有留「包一層」的口子,強行做就得整體替換助手消息渲染,宿主升級會白屏,所以作者沒做。這兩類位置的明文要去設置頁看。
設置頁分兩個標籤。「敏感數據管理」是保管庫,列表保留名稱/值、分類、規則三列,頂部「添加敏感數據」是彈窗,填名稱、明文、類型(可以自定義分類);明文直接加密進保管庫,不寫 rules.json,之後這段值出現就自動遮。小鎖臨時查看明文,旁邊的「複製明文」按鈕走本機接口取完整明文寫到剪貼板,明文不進模型上下文。
「自動檢測規則」列出 242 條規則(221 條上游 + 21 條內置),可按名稱/關鍵詞搜索、按全部/已開/已關篩選、每頁 20 條翻頁,逐條開關。默認「已開啓優先」排序,14 條默認關閉的規則集中在最後兩頁。
模型拿不到明文。要連庫或調接口時讓它先導出:
sensitive_guard_export(<SG_xxx>) 明文寫到 0600 文件,返回路徑
命令裏用 $(cat /那個/路徑) 明文不進上下文
工具只有兩個:sensitive_guard_status 看狀態和條目元數據,不含明文,連前 8 位預覽都不返回;sensitive_guard_export 負責導出,文件 15 分鐘後過期。
一個常被當成 bug 的點:模型讀 application.yml 時看到的是佔位符,拿它去連庫必然失敗。要麼先導出,要麼臨時點一次暫停。
認得出什麼¶
系統規則庫內置 221 條來自 gitleaks 的廠商規則(1Password、Adobe、Adafruit、Age、AWS、GCP、Azure、Stripe、Slack 等,MIT 許可,見 NOTICE)。每條帶關鍵詞預篩、正則和可選熵值閾值,命中後才跑正則,不會 221 條全量掃一遍。默認開 207 條高置信規則;10 條「近似轉換」和 4 條寬鬆規則默認關,在規則標籤裏自己開。上游還有一條 pkcs12-file 按文件名 .p12/.pfx 判定,文本脫敏用不上,規則頁標爲「不適用」。規則數據由 scripts/build-gitleaks.mjs 從上游 TOML 轉換生成,升級時重跑即可。
覆蓋的廠商前綴:sk-、sk_、ghp_、glpat-、npm_、hf_、AKIA、ASIA、xox*-、AIza、whsec_、SG.,以及 PEM 私鑰塊、JWT、Bearer 令牌。
賦值和環境變量也認:password=、secret:、api_key:、SECRET_KEY=、DB_PASSWORD=。
JSON 和結構化數據一塊處理。工具讀 .env、cat config.json 返回的常是一整段 JSON,{"password": "Abc!23456"} 這種值沒有廠商前綴,只看值形狀認不出來。現在只要字段名是 password、passwd、pwd、token、credential、api_key、db_pass、dsn、connection_string 這類(含下劃線、連字符、駝峯變體),值一律換代號,鍵名、層級和別的值都不動;已經解析成對象的工具結果同樣處理。
示例和佔位不遮:your_password_here、${DB_PASS}、<your-token>、changeme,以及 password_policy、token_count 這種只是描述字段的名字。
中文說法也能識別:數據庫密碼是…、我的 token 是…。中文語境的密碼從 6 位起就攔(我的密碼是 123456);英文和 key=value 形式從 8 位起,否則 the secret is hidden 裏的 hidden 會被當成密碼。句尾語氣詞和標點留在佔位符外面。
連接串和命令行也覆蓋:mysql://user:pass@host、postgresql://…、JDBC 參數裏的 password=、X-Api-Key:,以及 mysql -uroot -pabc12345、redis-cli -a xxx;只認這幾個客戶端,docker run -p 8080:80 不會被誤傷。
被換行打斷的 key 也認:sk-proj-… 粘貼時常被插入 \r、\n 或 \r\n,這類按跨行匹配把兩段拼回完整值再入庫,佔位符與不換行時完全相同。
熵值檢測默認關閉,rules.json 里加 "entropy": true 纔開。它抓沒有前綴的隨機串,但只對 base64 或混合字符集有用;純 hex 串上限是 4.0 bits/char,永遠夠不到 4.5 的默認閾值,8f3a9b2c… 這種開了也抓不到;閾值降到 3.9 又會誤傷英文長句。
配置¶
配置文件是 <數據目錄>/rules.json,存盤後兩秒內生效,不用重啓。Windows 下是 %USERPROFILE%\.dsh\sensitive-guard\,Linux 下是 ~/.dsh/sensitive-guard/。
{
"extraRules": [
{ "id": "my-internal", "pattern": "X-WX-Token:\\s*([A-Za-z0-9]{20,})", "flags": "i", "group": 1 }
],
"disabled": ["jwt"],
"enabledRules": [],
"outboundScrub": true,
"entropy": false,
"entropyThreshold": 4.5,
"allowCidrs": ["192.168.0.0/16"]
}
group 要遮擋的捕獲組序號,0 表示整個匹配。自定義正則的性能需要自己負責,別寫 (a+)+、(.*)* 這類結構——它跑在同步鉤子裏,回溯爆炸會卡住宿主。
disabled 寫規則 id 關掉單條默認開的規則,enabledRules 寫 id 打開一條默認關的規則;設置頁開關就是維護這兩個列表。outboundScrub: false 會關掉出網補洗。allowCidrs 默認空數組,意思是隻認本機。
網絡訪問¶
五個 HTTP 接口默認只接受本機迴環:桌面版的瀏覽器和 dsh 在同一臺機器,天然滿足。只有 dsh 以 --host 0.0.0.0 啓動、又從另一臺機器的瀏覽器打開時會拒。兩個辦法:一是在服務所在機器的瀏覽器裏打開 127.0.0.1:3080,不用改配置;二是在 rules.json 里加 "allowCidrs": ["192.168.0.0/16"],存盤兩秒生效,設置頁頂欄會出橙色提示。
沒配的時候頁面不會白屏,會降級成只讀:能看到有哪些條目、什麼類型、什麼時候入庫、命中幾次,看不到值和 8 位預覽。放行之後除了網段匹配還有三道檢查,都不用配:Host 頭必須是 IP 字面量(防 DNS rebinding);POST 必須是 application/json(跨站 text/plain 表單發不進來);Origin 必須和 Host 同源。
要清楚代價:開放網段意味着該網段裏任何設備都能讀到完整明文,不只是預覽。只在可信內網開,用完把這一行刪掉。沒做登錄是因爲加一套認證會讓點小鎖多兩步,不如把網段收窄。
已知限制¶
- 對話裏的膠囊只覆蓋用戶消息,原因見「日常使用」。
- 不做出口改寫。平臺的
tools/pre-execute只有 allow、deny、cancel、ask 四個動作,沒有改參數的掛點,所以用憑據只能走導出文件。 - 保管庫防的是誤讀和落盤明文,不防已經拿到你賬戶權限的人。加密是 AES-256-GCM,Windows 上密鑰文件用
icacls收緊到當前賬戶。 - 歷史會話不受保護。
pre-step在宿主把用戶原文寫進日誌之後才執行,session/event又只是觀察者,插件沒有機會在落盤前改。舊會話裏的明文還在磁盤上,那批密鑰該輪換。 exports/下是唯一落盤的明文,15 分鐘後在下次導出時清理。- 保管庫最多留 500 條,超出按最後命中時間淘汰。
- 保管庫壞掉時會放行,保證對話不中斷,但會計數,可在
sensitive_guard_status裏看到。
小結¶
dsh-sensitive-guard 適合需要在對話裏貼憑證、又不想讓明文進模型上下文或日誌的場景:它把攔截點放在進上下文之前,用本機加密保管庫存真值,並提供點開、複製和導出三種取值方式。安裝前建議通讀源碼和 LICENSE/NOTICE,確認它註冊的鉤子和 HTTP 路由符合你的環境。插件以當前 dsh 進程權限運行,能讀會話內文本,也能在放行網段下把明文暴露給該網段。
目錄頁:https://www.skillhub.cn/plugins/wangxy496/dsh-sensitive-guard
GitHub:https://github.com/wangxy496/dsh-sensitive-guard