dsh-netguard:出網護欄(SSRF 防護)

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

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜