DeepSeek Harness(DSH)的插件開發中,經常涉及從外部拉取資源(圖片、網頁、音頻等)。如果這些 URL 源於用戶輸入或模型輸出,就構成了 SSRF(服務器端請求僞造)的攻擊面。攻擊者可能利用此漏洞訪問內網服務(如 http://127.0.0.1:5099/api)或雲廠商元數據接口(如 http://169.254.169.254/latest/meta-data/iam/security-credentials/)。
dsh-netguard 是一個 DSH 插件,旨在作爲“出網護欄”。它通過一個 netguard 服務和一個可選的 fetch_url 工具,統一管理所有出網請求的地址合法性、大小與超時,避免因判定邏輯寫錯而導致的內網暴露。
核心功能¶
該插件提供以下能力:
- SSRF 防護:只允許訪問公網地址,攔截私網、內網及特殊用途地址(如
127.0.0.1、169.254.169.254等)。 - DNS 解析檢查:對 DNS 解析出的每一條地址都進行合法性判定,防止域名解析到內網。
- 重定向逐跳複查:對 HTTP 重定向的每一跳地址重新進行體檢,防止通過
302位置頭指向內網。 - 流式大小限制:邊讀邊計數,超過
maxBytes立即斷開連接,防止內存耗盡攻擊。 - 超時控制:整條請求鏈路共用一個超時預算,防止長時間卡頓或跳轉拖慢整體性能。
- 端口黑名單:攔截常見內網服務端口(如 22, 23, 25, 6379, 27017)。
- IPv4/IPv6 地址分類:支持 IPv4 的各種變形寫法(如
0x7f.1),IPv6 僅允許2000::/3。 - 工具支持:提供
fetch_url工具(默認關閉),供模型調用獲取公網內容。
安裝與配置¶
安裝¶
在 DSH 項目目錄下執行:
dsh plugin --profile web add github:JackZo400/dsh-netguard
配置¶
在插件配置文件中添加 netguard 服務實例。以下爲常用參數示例:
- insert:
- id: netguard
name: dsh-netguard
config:
allowedProtocols: ['http:', 'https:'] # 僅允許 HTTP/HTTPS
maxBytes: 8388608 # 一次最多下載 8 MiB
onOverflow: error # 超限報錯;若需截斷請設爲 'truncate'
timeoutMs: 20000 # 整條鏈路共用超時時間
allowRedirects: true # 允許重定向,每跳都會重新體檢
maxRedirects: 3
blockedPorts: [22, 23, 25, 6379, 11211, 27017] # 內網常見端口
allowUrlCredentials: false # 禁止 URL 中帶 user:pass
allowSingleLabel: false # 禁止單段主機名(如 http://intranet)
userAgent: dsh-netguard/0.1.0
enableTool: false # 是否開啓 fetch_url 工具
典型用法¶
給其他插件使用¶
獲取公網字節(適合下載圖片或音頻):
const netguard = ctx.get('netguard')
const bytes = await netguard.fetchPublicBytes(imageUrl, {
maxBytes: 8 * 1024 * 1024,
timeoutMs: 20_000
})
獲取完整響應信息(含狀態碼、最終地址、跳轉次數等):
const r = await netguard.fetchPublic(url, {
maxBytes: 64 * 1024,
onOverflow: 'truncate'
})
// 返回值包含 finalUrl, status, bytes, truncated, redirects 等字段
僅體檢 URL 合法性,不下載:
const u = await netguard.assertPublicUrl(url) // 不安全會拋出 NetguardError
主機名與地址判定(可單獨使用):
// 同步檢查,不查 DNS,只擋明顯寫法
netguard.isPublicHost('127.0.0.1') // false
// 異步檢查,查 DNS
await netguard.checkHost('demo.example.com') // 返回 { ok, addresses, offender? }
// IP 分類
netguard.classifyIp('::ffff:10.0.0.1') // 返回 { isIp:true, public:false, reason:'PRIVATE' }
給模型使用(默認關閉)¶
若需允許模型調用外部接口獲取內容,需在配置中開啓工具:
config:
enableTool: true
開啓後,模型可使用 fetch_url 工具:
抓一下 https://example.com/demo.html 裏寫了什麼
純函數邏輯¶
如果不需要 DSH 環境,可直接引入插件提供的純函數邏輯:
import { isPublicIp, classifyIp } from 'dsh-netguard/src/ip.js'
import { assertPublicUrl } from 'dsh-netguard/src/guard.js'
注意事項¶
插件雖然提供全面的地址檢查,但在以下場景下存在侷限:
- DNS 重綁定(TOCTOU)攻擊:插件在解析階段和連接階段可能使用不同的 DNS 結果(如 TTL=0 的域名),攻擊者可能利用此時間差繞過檢測。
- 代理判定時機:插件的地址判定發生在代理配置之前,無法感知通過代理訪問的實際地址。
- 內容安全:插件只驗證“能否去”和“拿多大”,不驗證返回內容本身的安全性(如 HTML 中的惡意指令)。
- 特殊跳轉:不支持
<meta http-equiv="refresh">或 JavaScript 跳轉,僅處理 HTTP 重定向。 - 協議支持:不支持上傳、POST 請求及流式長連接。
- DNSSEC:不執行 DNSSEC 驗證,依賴系統解析器。
- 公網反代:攻擊者若在公網服務器上搭建反向代理指向內網,地址層面無法檢測。
- 端口黑名單:黑名單爲近似值,非完整列表(如
8081,9090等也可能有內網服務)。 - IPv6 限制:僅允許
2000::/3,極少數合法的特殊 IPv6 寫法可能會被誤攔截。 - 無速率限制:插件不限制請求的頻率或併發數,需在外部自行添加配額控制。
總結¶
dsh-netguard 通過嚴格的地址分類、逐跳重定向檢查和流式限流,爲 DSH 插件提供了一個堅實的出網安全層。它解決了傳統正則匹配無法覆蓋的變形 IP、DNS 解析到內網以及重定向劫持等常見 SSRF 漏洞。開發者應根據實際業務需求調整 maxBytes、timeoutMs 和 blockedPorts 參數。
插件目錄:SkillHub 插件目錄
GitHub 倉庫:JackZo400/dsh-netguard