@zhin.js/agent 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -12
- package/lib/agent-prompt/resolver.d.ts +2 -1
- package/lib/agent-prompt/resolver.d.ts.map +1 -1
- package/lib/agent-prompt/resolver.js +8 -3
- package/lib/agent-prompt/resolver.js.map +1 -1
- package/lib/assistant/home-mcp-bridge.d.ts +1 -1
- package/lib/assistant/home-mcp-bridge.d.ts.map +1 -1
- package/lib/assistant/home-policy.js +20 -21
- package/lib/assistant/home-policy.js.map +1 -1
- package/lib/assistant/home-tools.d.ts.map +1 -1
- package/lib/assistant/home-tools.js +5 -2
- package/lib/assistant/home-tools.js.map +1 -1
- package/lib/bootstrap.d.ts +12 -0
- package/lib/bootstrap.d.ts.map +1 -1
- package/lib/bootstrap.js +14 -0
- package/lib/bootstrap.js.map +1 -1
- package/lib/builtin/analyze-media-tool.d.ts.map +1 -1
- package/lib/builtin/analyze-media-tool.js +11 -5
- package/lib/builtin/analyze-media-tool.js.map +1 -1
- package/lib/builtin/bash-tool.d.ts +4 -2
- package/lib/builtin/bash-tool.d.ts.map +1 -1
- package/lib/builtin/bash-tool.js +17 -14
- package/lib/builtin/bash-tool.js.map +1 -1
- package/lib/builtin/generate-image-tool.d.ts +1 -1
- package/lib/builtin/generate-image-tool.d.ts.map +1 -1
- package/lib/builtin/generate-image-tool.js +3 -3
- package/lib/builtin/generate-image-tool.js.map +1 -1
- package/lib/builtin/grep-tool.d.ts.map +1 -1
- package/lib/builtin/grep-tool.js +4 -1
- package/lib/builtin/grep-tool.js.map +1 -1
- package/lib/builtin/knowledge-search-tool.d.ts +6 -0
- package/lib/builtin/knowledge-search-tool.d.ts.map +1 -0
- package/lib/builtin/knowledge-search-tool.js +184 -0
- package/lib/builtin/knowledge-search-tool.js.map +1 -0
- package/lib/builtin/orchestration-tools.d.ts +2 -1
- package/lib/builtin/orchestration-tools.d.ts.map +1 -1
- package/lib/builtin/orchestration-tools.js.map +1 -1
- package/lib/builtin/read-file-tool.d.ts.map +1 -1
- package/lib/builtin/read-file-tool.js +4 -4
- package/lib/builtin/read-file-tool.js.map +1 -1
- package/lib/builtin/run-spec-dry-run-tool.d.ts +1 -4
- package/lib/builtin/run-spec-dry-run-tool.d.ts.map +1 -1
- package/lib/builtin/run-spec-dry-run-tool.js.map +1 -1
- package/lib/builtin/run-validation-spec-tool.d.ts +1 -4
- package/lib/builtin/run-validation-spec-tool.d.ts.map +1 -1
- package/lib/builtin/run-validation-spec-tool.js.map +1 -1
- package/lib/builtin/spawn-task-tool.d.ts +2 -1
- package/lib/builtin/spawn-task-tool.d.ts.map +1 -1
- package/lib/builtin/spawn-task-tool.js.map +1 -1
- package/lib/builtin/web-fetch-tool.d.ts +2 -0
- package/lib/builtin/web-fetch-tool.d.ts.map +1 -1
- package/lib/builtin/web-fetch-tool.js +38 -16
- package/lib/builtin/web-fetch-tool.js.map +1 -1
- package/lib/builtin-tools.d.ts +2 -0
- package/lib/builtin-tools.d.ts.map +1 -1
- package/lib/builtin-tools.js +5 -1
- package/lib/builtin-tools.js.map +1 -1
- package/lib/config/fix-ai-config.d.ts +1 -1
- package/lib/config/fix-ai-config.d.ts.map +1 -1
- package/lib/config/fix-ai-config.js +1 -1
- package/lib/config/normalize-ai-config.d.ts +5 -2
- package/lib/config/normalize-ai-config.d.ts.map +1 -1
- package/lib/config/normalize-ai-config.js +50 -7
- package/lib/config/normalize-ai-config.js.map +1 -1
- package/lib/config/provider-instance.d.ts +1 -1
- package/lib/config/provider-instance.d.ts.map +1 -1
- package/lib/config/provider-instance.js +2 -51
- package/lib/config/provider-instance.js.map +1 -1
- package/lib/config/types.d.ts +9 -5
- package/lib/config/types.d.ts.map +1 -1
- package/lib/config/types.js.map +1 -1
- package/lib/config/validate-ai-config.d.ts.map +1 -1
- package/lib/config/validate-ai-config.js +12 -2
- package/lib/config/validate-ai-config.js.map +1 -1
- package/lib/create-agent-session.d.ts +1 -1
- package/lib/create-agent-session.d.ts.map +1 -1
- package/lib/deferred-worker-runner.d.ts +1 -1
- package/lib/deferred-worker-runner.d.ts.map +1 -1
- package/lib/deferred-worker-runner.js +39 -12
- package/lib/deferred-worker-runner.js.map +1 -1
- package/lib/index.d.ts +5 -19
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -10
- package/lib/index.js.map +1 -1
- package/lib/init/activate-ai-database-storage.d.ts +1 -1
- package/lib/init/activate-ai-database-storage.d.ts.map +1 -1
- package/lib/init/activate-ai-database-storage.js +12 -8
- package/lib/init/activate-ai-database-storage.js.map +1 -1
- package/lib/init/create-zhin-agent.d.ts.map +1 -1
- package/lib/init/create-zhin-agent.js +18 -6
- package/lib/init/create-zhin-agent.js.map +1 -1
- package/lib/init/introspection-collectors.d.ts +1 -1
- package/lib/init/introspection-collectors.d.ts.map +1 -1
- package/lib/init/introspection-collectors.js.map +1 -1
- package/lib/init/introspection-commands-format.d.ts +1 -1
- package/lib/init/introspection-commands-format.d.ts.map +1 -1
- package/lib/init/introspection-commands-format.js.map +1 -1
- package/lib/init/message-media.d.ts +2 -1
- package/lib/init/message-media.d.ts.map +1 -1
- package/lib/init/message-media.js.map +1 -1
- package/lib/init/register-agent-mesh-mcp.d.ts.map +1 -1
- package/lib/init/register-agent-mesh-mcp.js +18 -2
- package/lib/init/register-agent-mesh-mcp.js.map +1 -1
- package/lib/init/register-ai-service.d.ts.map +1 -1
- package/lib/init/register-ai-service.js +2 -1
- package/lib/init/register-ai-service.js.map +1 -1
- package/lib/init/register-builtin-tools.d.ts.map +1 -1
- package/lib/init/register-builtin-tools.js +12 -7
- package/lib/init/register-builtin-tools.js.map +1 -1
- package/lib/init/register-db-upgrade.js.map +1 -1
- package/lib/init/register-introspection-commands.d.ts.map +1 -1
- package/lib/init/register-introspection-commands.js +8 -9
- package/lib/init/register-introspection-commands.js.map +1 -1
- package/lib/init/register-owner-approve-commands.d.ts.map +1 -1
- package/lib/init/register-owner-approve-commands.js +16 -22
- package/lib/init/register-owner-approve-commands.js.map +1 -1
- package/lib/mcp-client/bridge.d.ts +4 -4
- package/lib/mcp-client/bridge.d.ts.map +1 -1
- package/lib/mcp-client/bridge.js.map +1 -1
- package/lib/mcp-client/connection.d.ts.map +1 -1
- package/lib/mcp-client/connection.js +37 -1
- package/lib/mcp-client/connection.js.map +1 -1
- package/lib/mcp-server/agent-mesh-tools.js +1 -1
- package/lib/mcp-server/agent-mesh-tools.js.map +1 -1
- package/lib/media/media-capabilities.d.ts.map +1 -1
- package/lib/media/media-capabilities.js +5 -7
- package/lib/media/media-capabilities.js.map +1 -1
- package/lib/media/resolve-config.d.ts.map +1 -1
- package/lib/media/resolve-config.js +5 -7
- package/lib/media/resolve-config.js.map +1 -1
- package/lib/memory-layers.d.ts.map +1 -1
- package/lib/memory-layers.js +10 -15
- package/lib/memory-layers.js.map +1 -1
- package/lib/orchestrator/agent-dispatcher.d.ts +1 -1
- package/lib/orchestrator/agent-dispatcher.d.ts.map +1 -1
- package/lib/orchestrator/owner-confirm-orchestration.d.ts +1 -1
- package/lib/orchestrator/owner-confirm-orchestration.d.ts.map +1 -1
- package/lib/orchestrator/owner-confirm-orchestration.js +3 -9
- package/lib/orchestrator/owner-confirm-orchestration.js.map +1 -1
- package/lib/orchestrator/remote-agent-registry.d.ts +1 -1
- package/lib/orchestrator/remote-agent-registry.d.ts.map +1 -1
- package/lib/plugin-ai-hook-bus.d.ts.map +1 -1
- package/lib/plugin-ai-hook-bus.js +2 -7
- package/lib/plugin-ai-hook-bus.js.map +1 -1
- package/lib/routing/runtime-binding.d.ts +1 -1
- package/lib/routing/runtime-binding.d.ts.map +1 -1
- package/lib/security/audit-logger.d.ts +1 -0
- package/lib/security/audit-logger.d.ts.map +1 -1
- package/lib/security/audit-logger.js +17 -7
- package/lib/security/audit-logger.js.map +1 -1
- package/lib/security/dangerous-tool-policy.d.ts +4 -0
- package/lib/security/dangerous-tool-policy.d.ts.map +1 -1
- package/lib/security/dangerous-tool-policy.js +46 -42
- package/lib/security/dangerous-tool-policy.js.map +1 -1
- package/lib/security/exec-policy.d.ts +1 -1
- package/lib/security/exec-policy.d.ts.map +1 -1
- package/lib/security/exec-policy.js +15 -3
- package/lib/security/exec-policy.js.map +1 -1
- package/lib/security/file-policy.d.ts +8 -0
- package/lib/security/file-policy.d.ts.map +1 -1
- package/lib/security/file-policy.js +48 -12
- package/lib/security/file-policy.js.map +1 -1
- package/lib/security/file-role-policy.d.ts +6 -3
- package/lib/security/file-role-policy.d.ts.map +1 -1
- package/lib/security/file-role-policy.js +29 -6
- package/lib/security/file-role-policy.js.map +1 -1
- package/lib/security/index.d.ts +3 -45
- package/lib/security/index.d.ts.map +1 -1
- package/lib/security/index.js +3 -66
- package/lib/security/index.js.map +1 -1
- package/lib/security/network-policy.d.ts +30 -87
- package/lib/security/network-policy.d.ts.map +1 -1
- package/lib/security/network-policy.js +133 -280
- package/lib/security/network-policy.js.map +1 -1
- package/lib/security/owner-approve-always-store.js +0 -1
- package/lib/security/owner-approve-always-store.js.map +1 -1
- package/lib/security/sandbox-docker.d.ts +28 -0
- package/lib/security/sandbox-docker.d.ts.map +1 -0
- package/lib/security/sandbox-docker.js +177 -0
- package/lib/security/sandbox-docker.js.map +1 -0
- package/lib/security/sandbox.d.ts +10 -0
- package/lib/security/sandbox.d.ts.map +1 -1
- package/lib/security/sandbox.js +152 -14
- package/lib/security/sandbox.js.map +1 -1
- package/lib/service.d.ts +4 -5
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +4 -12
- package/lib/service.js.map +1 -1
- package/lib/subagent.d.ts +7 -3
- package/lib/subagent.d.ts.map +1 -1
- package/lib/subagent.js +2 -2
- package/lib/subagent.js.map +1 -1
- package/lib/types/disposable.d.ts +5 -0
- package/lib/types/disposable.d.ts.map +1 -0
- package/lib/types/disposable.js +2 -0
- package/lib/types/disposable.js.map +1 -0
- package/lib/zhin-agent/agent-loop-standalone.d.ts +11 -0
- package/lib/zhin-agent/agent-loop-standalone.d.ts.map +1 -1
- package/lib/zhin-agent/agent-loop-standalone.js +26 -7
- package/lib/zhin-agent/agent-loop-standalone.js.map +1 -1
- package/lib/zhin-agent/agent-loop-turn.d.ts.map +1 -1
- package/lib/zhin-agent/agent-loop-turn.js +76 -9
- package/lib/zhin-agent/agent-loop-turn.js.map +1 -1
- package/lib/zhin-agent/agents-instruction.d.ts +15 -0
- package/lib/zhin-agent/agents-instruction.d.ts.map +1 -0
- package/lib/zhin-agent/agents-instruction.js +98 -0
- package/lib/zhin-agent/agents-instruction.js.map +1 -0
- package/lib/zhin-agent/builtin-tools.d.ts +1 -1
- package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
- package/lib/zhin-agent/compaction-runtime.d.ts.map +1 -1
- package/lib/zhin-agent/compaction-runtime.js +7 -1
- package/lib/zhin-agent/compaction-runtime.js.map +1 -1
- package/lib/zhin-agent/config.d.ts +53 -3
- package/lib/zhin-agent/config.d.ts.map +1 -1
- package/lib/zhin-agent/config.js +53 -2
- package/lib/zhin-agent/config.js.map +1 -1
- package/lib/zhin-agent/index.d.ts +20 -16
- package/lib/zhin-agent/index.d.ts.map +1 -1
- package/lib/zhin-agent/index.js +108 -99
- package/lib/zhin-agent/index.js.map +1 -1
- package/lib/zhin-agent/interfaces.d.ts +63 -0
- package/lib/zhin-agent/interfaces.d.ts.map +1 -0
- package/lib/zhin-agent/interfaces.js +8 -0
- package/lib/zhin-agent/interfaces.js.map +1 -0
- package/lib/zhin-agent/model-harness.js +1 -1
- package/lib/zhin-agent/phase-trace.d.ts +12 -1
- package/lib/zhin-agent/phase-trace.d.ts.map +1 -1
- package/lib/zhin-agent/phase-trace.js +25 -0
- package/lib/zhin-agent/phase-trace.js.map +1 -1
- package/lib/zhin-agent/prompt-assembly.d.ts +13 -4
- package/lib/zhin-agent/prompt-assembly.d.ts.map +1 -1
- package/lib/zhin-agent/prompt-assembly.js +34 -8
- package/lib/zhin-agent/prompt-assembly.js.map +1 -1
- package/lib/zhin-agent/prompt-trace.d.ts +20 -0
- package/lib/zhin-agent/prompt-trace.d.ts.map +1 -0
- package/lib/zhin-agent/prompt-trace.js +72 -0
- package/lib/zhin-agent/prompt-trace.js.map +1 -0
- package/lib/zhin-agent/prompt.d.ts +25 -3
- package/lib/zhin-agent/prompt.d.ts.map +1 -1
- package/lib/zhin-agent/prompt.js +109 -46
- package/lib/zhin-agent/prompt.js.map +1 -1
- package/lib/zhin-agent/session-io.d.ts +2 -2
- package/lib/zhin-agent/session-io.d.ts.map +1 -1
- package/lib/zhin-agent/session-io.js +2 -3
- package/lib/zhin-agent/session-io.js.map +1 -1
- package/lib/zhin-agent/task-continuation.d.ts +4 -4
- package/lib/zhin-agent/task-continuation.d.ts.map +1 -1
- package/lib/zhin-agent/task-continuation.js.map +1 -1
- package/lib/zhin-agent/tool-catalog.d.ts.map +1 -1
- package/lib/zhin-agent/tool-catalog.js +9 -1
- package/lib/zhin-agent/tool-catalog.js.map +1 -1
- package/lib/zhin-agent/turn-pipeline.d.ts.map +1 -1
- package/lib/zhin-agent/turn-pipeline.js +44 -11
- package/lib/zhin-agent/turn-pipeline.js.map +1 -1
- package/lib/zhin-agent/turn-user-message.d.ts +4 -1
- package/lib/zhin-agent/turn-user-message.d.ts.map +1 -1
- package/lib/zhin-agent/turn-user-message.js +39 -0
- package/lib/zhin-agent/turn-user-message.js.map +1 -1
- package/lib/zhin-agent/workspace-prompt.d.ts +10 -0
- package/lib/zhin-agent/workspace-prompt.d.ts.map +1 -0
- package/lib/zhin-agent/workspace-prompt.js +55 -0
- package/lib/zhin-agent/workspace-prompt.js.map +1 -0
- package/lib/zhin-agent/zhin-agent-private.d.ts +2 -0
- package/lib/zhin-agent/zhin-agent-private.d.ts.map +1 -1
- package/lib/zhin-agent/zhin-agent-private.js.map +1 -1
- package/package.json +16 -6
- package/lib/monitoring/index.d.ts +0 -79
- package/lib/monitoring/index.d.ts.map +0 -1
- package/lib/monitoring/index.js +0 -197
- package/lib/monitoring/index.js.map +0 -1
- package/lib/monitoring/metrics.d.ts +0 -260
- package/lib/monitoring/metrics.d.ts.map +0 -1
- package/lib/monitoring/metrics.js +0 -550
- package/lib/monitoring/metrics.js.map +0 -1
- package/lib/security/budget-limiter.d.ts +0 -161
- package/lib/security/budget-limiter.d.ts.map +0 -1
- package/lib/security/budget-limiter.js +0 -392
- package/lib/security/budget-limiter.js.map +0 -1
- package/lib/security/security-config.example.d.ts +0 -33
- package/lib/security/security-config.example.d.ts.map +0 -1
- package/lib/security/security-config.example.js +0 -166
- package/lib/security/security-config.example.js.map +0 -1
package/lib/security/index.js
CHANGED
|
@@ -4,18 +4,16 @@
|
|
|
4
4
|
* 提供多层安全防护:
|
|
5
5
|
* - 执行策略(exec-policy):命令执行安全
|
|
6
6
|
* - 文件策略(file-policy):文件访问安全
|
|
7
|
-
* - 网络策略(network-policy):网络访问安全
|
|
8
|
-
* - 预算限制(budget-limiter):资源使用限制
|
|
9
7
|
* - 审计日志(audit-logger):安全事件追踪
|
|
8
|
+
* - 网络策略(network-policy):SSRF 防护、域名白名单、网络命令检测
|
|
10
9
|
* - 沙箱环境(sandbox):进程隔离和资源限制
|
|
11
|
-
* - 增强沙箱(sandbox-enhanced
|
|
12
|
-
* - 异常检测(anomaly-detection
|
|
10
|
+
* - 增强沙箱(sandbox-enhanced):更细粒度的安全控制(experimental)
|
|
11
|
+
* - 异常检测(anomaly-detection):行为模式分析和异常检测(experimental)
|
|
13
12
|
*/
|
|
14
13
|
// ── 核心安全策略 ──────────────────────────────────────────────────────
|
|
15
14
|
export * from './file-policy.js';
|
|
16
15
|
export * from './exec-policy.js';
|
|
17
16
|
export * from './network-policy.js';
|
|
18
|
-
export * from './budget-limiter.js';
|
|
19
17
|
export * from './audit-logger.js';
|
|
20
18
|
export * from './comm-message-context.js';
|
|
21
19
|
export * from './owner-approve-always-store.js';
|
|
@@ -24,65 +22,4 @@ export * from './sandbox-enhanced.js';
|
|
|
24
22
|
export * from './anomaly-detection.js';
|
|
25
23
|
export * from './file-role-policy.js';
|
|
26
24
|
export * from './dangerous-tool-policy.js';
|
|
27
|
-
import { initAuditLogger, getAuditLogger, closeAuditLogger } from './audit-logger.js';
|
|
28
|
-
import { initNetworkPolicy, getNetworkPolicy, resetNetworkPolicy } from './network-policy.js';
|
|
29
|
-
import { initBudgetLimiter, getBudgetLimiter, resetBudgetLimiter } from './budget-limiter.js';
|
|
30
|
-
/**
|
|
31
|
-
* 初始化所有安全策略
|
|
32
|
-
*/
|
|
33
|
-
export function initSecurityPolicies(config = {}) {
|
|
34
|
-
const auditLogger = initAuditLogger(config.audit || {});
|
|
35
|
-
const networkPolicy = initNetworkPolicy(config.network || {});
|
|
36
|
-
const budgetLimiter = initBudgetLimiter(config.budget || {});
|
|
37
|
-
return { auditLogger, networkPolicy, budgetLimiter };
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* 重置所有安全策略(用于测试隔离)
|
|
41
|
-
*/
|
|
42
|
-
export function resetSecurityPolicies() {
|
|
43
|
-
try {
|
|
44
|
-
closeAuditLogger();
|
|
45
|
-
}
|
|
46
|
-
catch { /* ignore */ }
|
|
47
|
-
try {
|
|
48
|
-
resetNetworkPolicy();
|
|
49
|
-
}
|
|
50
|
-
catch { /* ignore */ }
|
|
51
|
-
try {
|
|
52
|
-
resetBudgetLimiter();
|
|
53
|
-
}
|
|
54
|
-
catch { /* ignore */ }
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* 获取安全策略状态
|
|
58
|
-
*/
|
|
59
|
-
export function getSecurityPolicyStatus() {
|
|
60
|
-
try {
|
|
61
|
-
const audit = getAuditLogger();
|
|
62
|
-
const network = getNetworkPolicy();
|
|
63
|
-
const budget = getBudgetLimiter();
|
|
64
|
-
return {
|
|
65
|
-
audit: {
|
|
66
|
-
enabled: audit.getConfig().enabled,
|
|
67
|
-
eventCount: audit.getStats().totalEvents,
|
|
68
|
-
},
|
|
69
|
-
network: {
|
|
70
|
-
enabled: network.getConfig().enabled,
|
|
71
|
-
rulesCount: (network.getConfig().allowedDomains?.length || 0) +
|
|
72
|
-
(network.getConfig().blockedDomains?.length || 0),
|
|
73
|
-
},
|
|
74
|
-
budget: {
|
|
75
|
-
enabled: budget.getConfig().enabled,
|
|
76
|
-
activeSessions: 0,
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
return {
|
|
82
|
-
audit: { enabled: false, eventCount: 0 },
|
|
83
|
-
network: { enabled: false, rulesCount: 0 },
|
|
84
|
-
budget: { enabled: false, activeSessions: 0 },
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mEAAmE;AAEnE,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
|
|
@@ -1,98 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 控制 AI Agent 的网络请求,防止:
|
|
5
|
-
* - 访问恶意域名
|
|
6
|
-
* - 数据外泄
|
|
7
|
-
* - SSRF 攻击
|
|
8
|
-
* - 资源滥用
|
|
2
|
+
* 统一网络安全策略 — SSRF 防护、域名白名单、网络命令检测
|
|
9
3
|
*
|
|
4
|
+
* 合并了原散落在 web-fetch-tool.ts / sandbox.ts / sandbox-enhanced.ts / exec-policy.ts 中的
|
|
5
|
+
* 网络安全检查逻辑,作为单一事实来源。
|
|
10
6
|
*/
|
|
7
|
+
/** 网络命令模式(当 enableNetwork: false 时阻断) */
|
|
8
|
+
export declare const NETWORK_COMMAND_PATTERNS: ReadonlyArray<RegExp>;
|
|
9
|
+
/** SSRF 防护:检查主机名是否属于内网/私有/危险地址 */
|
|
10
|
+
export declare function isBlockedSsrfHostname(hostname: string): boolean;
|
|
11
|
+
/** 检查主机名是否匹配域名列表(精确匹配或子域名匹配) */
|
|
12
|
+
export declare function hostnameMatchesList(hostname: string, domains: string[]): boolean;
|
|
13
|
+
/** 从命令中提取所有 URL(小写) */
|
|
14
|
+
export declare function extractUrlsFromCommand(command: string): string[];
|
|
15
|
+
/** 从命令中提取第一个 URL(原始大小写) */
|
|
16
|
+
export declare function extractFirstUrlFromCommand(command: string): string | undefined;
|
|
17
|
+
/** 检测 curl 数据外泄模式(curl -d @file) */
|
|
18
|
+
export declare function isDataExfiltrationAttempt(command: string): boolean;
|
|
11
19
|
export interface NetworkPolicyConfig {
|
|
12
|
-
|
|
13
|
-
enabled: boolean;
|
|
14
|
-
/** 域名白名单(允许访问) */
|
|
20
|
+
enableNetwork?: boolean;
|
|
15
21
|
allowedDomains?: string[];
|
|
16
|
-
/** 域名黑名单(禁止访问) */
|
|
17
|
-
blockedDomains?: string[];
|
|
18
|
-
/** IP 黑名单 */
|
|
19
|
-
blockedIPs?: string[];
|
|
20
|
-
/** 禁止私有 IP */
|
|
21
|
-
blockPrivateIPs?: boolean;
|
|
22
|
-
/** 最大请求大小(字节) */
|
|
23
|
-
maxRequestSize?: number;
|
|
24
|
-
/** 最大响应大小(字节) */
|
|
25
|
-
maxResponseSize?: number;
|
|
26
|
-
/** 请求超时(毫秒) */
|
|
27
|
-
requestTimeout?: number;
|
|
28
|
-
/** 每分钟最大请求数 */
|
|
29
|
-
rateLimit?: number;
|
|
30
|
-
/** 禁止的协议 */
|
|
31
|
-
blockedProtocols?: string[];
|
|
32
|
-
/** 禁止的端口 */
|
|
33
|
-
blockedPorts?: number[];
|
|
34
|
-
}
|
|
35
|
-
export interface NetworkPolicyResult {
|
|
36
|
-
allowed: boolean;
|
|
37
|
-
reason?: string;
|
|
38
|
-
/** 脱敏后的 URL */
|
|
39
|
-
sanitizedUrl?: string;
|
|
40
|
-
}
|
|
41
|
-
export declare class NetworkPolicy {
|
|
42
|
-
private config;
|
|
43
|
-
private rateLimiter;
|
|
44
|
-
private cleanupTimer?;
|
|
45
|
-
constructor(config?: Partial<NetworkPolicyConfig>);
|
|
46
|
-
/**
|
|
47
|
-
* 检查 URL 是否允许访问
|
|
48
|
-
*/
|
|
49
|
-
checkUrl(url: string, userId?: string): NetworkPolicyResult;
|
|
50
|
-
/**
|
|
51
|
-
* 检查域名是否在黑名单中
|
|
52
|
-
*/
|
|
53
|
-
private isBlockedDomain;
|
|
54
|
-
/**
|
|
55
|
-
* 检查域名是否在白名单中
|
|
56
|
-
*/
|
|
57
|
-
private isAllowedDomain;
|
|
58
|
-
/**
|
|
59
|
-
* 检查是否为可疑域名
|
|
60
|
-
*/
|
|
61
|
-
private isSuspiciousDomain;
|
|
62
|
-
/**
|
|
63
|
-
* 检查是否为私有 IP
|
|
64
|
-
*/
|
|
65
|
-
private isPrivateIP;
|
|
66
|
-
/**
|
|
67
|
-
* 获取默认端口
|
|
68
|
-
*/
|
|
69
|
-
private getDefaultPort;
|
|
70
|
-
/**
|
|
71
|
-
* 脱敏域名
|
|
72
|
-
*/
|
|
73
|
-
private maskDomain;
|
|
74
|
-
/**
|
|
75
|
-
* 更新配置
|
|
76
|
-
*/
|
|
77
|
-
updateConfig(config: Partial<NetworkPolicyConfig>): void;
|
|
78
|
-
/**
|
|
79
|
-
* 获取配置(脱敏)
|
|
80
|
-
*/
|
|
81
|
-
getConfig(): NetworkPolicyConfig;
|
|
82
|
-
dispose(): void;
|
|
83
22
|
}
|
|
84
23
|
/**
|
|
85
|
-
*
|
|
24
|
+
* 检查网络命令访问权限(sandbox 层)
|
|
25
|
+
* - enableNetwork: false → 阻断所有网络命令
|
|
26
|
+
* - enableNetwork: true + allowedDomains → 仅允许指定域名
|
|
86
27
|
*/
|
|
87
|
-
export declare function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
export declare function initNetworkPolicy(config: Partial<NetworkPolicyConfig>): NetworkPolicy;
|
|
92
|
-
/** 重置全局网络策略(用于测试隔离) */
|
|
93
|
-
export declare function resetNetworkPolicy(): void;
|
|
28
|
+
export declare function checkNetworkCommandAccess(command: string, config: NetworkPolicyConfig): {
|
|
29
|
+
allowed: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
};
|
|
94
32
|
/**
|
|
95
|
-
*
|
|
33
|
+
* 校验 exec-policy 允许的网络命令(curl/wget)的 URL 安全性
|
|
34
|
+
* - 阻断数据外泄模式(curl -d @file)
|
|
35
|
+
* - 阻断 SSRF 目标(内网/元数据端点)
|
|
96
36
|
*/
|
|
97
|
-
export declare function
|
|
37
|
+
export declare function validateNetworkCommandUrl(command: string): {
|
|
38
|
+
safe: boolean;
|
|
39
|
+
reason?: string;
|
|
40
|
+
};
|
|
98
41
|
//# sourceMappingURL=network-policy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-policy.d.ts","sourceRoot":"","sources":["../../src/security/network-policy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"network-policy.d.ts","sourceRoot":"","sources":["../../src/security/network-policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,yCAAyC;AACzC,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC,MAAM,CAa1D,CAAC;AAIF,kCAAkC;AAClC,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAyB/D;AAID,gCAAgC;AAChC,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAMhF;AAMD,uBAAuB;AACvB,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhE;AAED,2BAA2B;AAC3B,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9E;AAID,oCAAoC;AACpC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGlE;AAID,MAAM,WAAW,mBAAmB;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,mBAAmB,GAC1B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA8CvC;AAID;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA0B7F"}
|
|
@@ -1,305 +1,158 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 控制 AI Agent 的网络请求,防止:
|
|
5
|
-
* - 访问恶意域名
|
|
6
|
-
* - 数据外泄
|
|
7
|
-
* - SSRF 攻击
|
|
8
|
-
* - 资源滥用
|
|
2
|
+
* 统一网络安全策略 — SSRF 防护、域名白名单、网络命令检测
|
|
9
3
|
*
|
|
4
|
+
* 合并了原散落在 web-fetch-tool.ts / sandbox.ts / sandbox-enhanced.ts / exec-policy.ts 中的
|
|
5
|
+
* 网络安全检查逻辑,作为单一事实来源。
|
|
10
6
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/^192\.168\./, // 192.168.0.0/16
|
|
27
|
-
/^127\./, // 127.0.0.0/8 (localhost)
|
|
28
|
-
/^0\./, // 0.0.0.0
|
|
29
|
-
/^::1$/, // IPv6 localhost
|
|
30
|
-
/^fc00:/, // IPv6 private
|
|
31
|
-
/^fd[0-9a-f]{2}:/, // IPv6 private
|
|
32
|
-
/^fe80:/, // IPv6 link-local
|
|
7
|
+
// ── 网络命令模式 ──────────────────────────────────────────────────────
|
|
8
|
+
/** 网络命令模式(当 enableNetwork: false 时阻断) */
|
|
9
|
+
export const NETWORK_COMMAND_PATTERNS = [
|
|
10
|
+
/\bcurl\s+/,
|
|
11
|
+
/\bwget\s+/,
|
|
12
|
+
/\bnc\s+/,
|
|
13
|
+
/\bnetcat\s+/,
|
|
14
|
+
/\bssh\s+/,
|
|
15
|
+
/\bscp\s+/,
|
|
16
|
+
/\brsync\s+/,
|
|
17
|
+
/\bping\s+/,
|
|
18
|
+
/\btraceroute\s+/,
|
|
19
|
+
/\bnmap\s+/,
|
|
20
|
+
/\bhttp\s+/,
|
|
21
|
+
/\bhttps\s+/,
|
|
33
22
|
];
|
|
23
|
+
// ── SSRF 防护 ─────────────────────────────────────────────────────────
|
|
24
|
+
/** SSRF 防护:检查主机名是否属于内网/私有/危险地址 */
|
|
25
|
+
export function isBlockedSsrfHostname(hostname) {
|
|
26
|
+
const h = hostname.toLowerCase();
|
|
27
|
+
return (
|
|
28
|
+
// Localhost
|
|
29
|
+
h === 'localhost' ||
|
|
30
|
+
h === '127.0.0.1' ||
|
|
31
|
+
h === '::1' ||
|
|
32
|
+
h === '0.0.0.0' ||
|
|
33
|
+
h.endsWith('.local') ||
|
|
34
|
+
// IPv4 private ranges
|
|
35
|
+
h.startsWith('10.') ||
|
|
36
|
+
h.startsWith('192.168.') ||
|
|
37
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(h) ||
|
|
38
|
+
// Cloud metadata endpoints (AWS/GCP/Azure)
|
|
39
|
+
h === '169.254.169.254' ||
|
|
40
|
+
h === 'metadata.google.internal' ||
|
|
41
|
+
h === 'metadata.google.com' ||
|
|
42
|
+
// IPv6 private/link-local ranges
|
|
43
|
+
/^fd[0-9a-f]{2}:/i.test(h) ||
|
|
44
|
+
/^fe80:/i.test(h) ||
|
|
45
|
+
// System-level domain blocklist
|
|
46
|
+
h.endsWith('.onion') ||
|
|
47
|
+
h.endsWith('.internal') ||
|
|
48
|
+
h.endsWith('.localhost'));
|
|
49
|
+
}
|
|
50
|
+
// ── 域名匹配 ──────────────────────────────────────────────────────────
|
|
51
|
+
/** 检查主机名是否匹配域名列表(精确匹配或子域名匹配) */
|
|
52
|
+
export function hostnameMatchesList(hostname, domains) {
|
|
53
|
+
const h = hostname.toLowerCase();
|
|
54
|
+
return domains.some(domain => {
|
|
55
|
+
const d = domain.toLowerCase().replace(/^\./, '');
|
|
56
|
+
return h === d || h.endsWith('.' + d);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ── URL 提取 ───────────────────────────────────────────────────────────
|
|
60
|
+
const URL_PATTERN = /https?:\/\/[^\s'"`&|;)}\]]+/gi;
|
|
61
|
+
/** 从命令中提取所有 URL(小写) */
|
|
62
|
+
export function extractUrlsFromCommand(command) {
|
|
63
|
+
return (command.match(URL_PATTERN) || []).map(u => u.toLowerCase());
|
|
64
|
+
}
|
|
65
|
+
/** 从命令中提取第一个 URL(原始大小写) */
|
|
66
|
+
export function extractFirstUrlFromCommand(command) {
|
|
67
|
+
const match = command.match(/https?:\/\/[^\s'"`&|;)}\]]+/i);
|
|
68
|
+
return match ? match[0] : undefined;
|
|
69
|
+
}
|
|
70
|
+
// ── 数据外泄检测 ───────────────────────────────────────────────────────
|
|
71
|
+
/** 检测 curl 数据外泄模式(curl -d @file) */
|
|
72
|
+
export function isDataExfiltrationAttempt(command) {
|
|
73
|
+
const lower = command.toLowerCase();
|
|
74
|
+
return /\bcurl\b/.test(lower) && /-d\s+@|--data-binary\s+@/.test(lower);
|
|
75
|
+
}
|
|
34
76
|
/**
|
|
35
|
-
*
|
|
77
|
+
* 检查网络命令访问权限(sandbox 层)
|
|
78
|
+
* - enableNetwork: false → 阻断所有网络命令
|
|
79
|
+
* - enableNetwork: true + allowedDomains → 仅允许指定域名
|
|
36
80
|
*/
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/pastebin\.com/i, // 代码分享,可能含恶意内容
|
|
48
|
-
/hastebin\.com/i,
|
|
49
|
-
/ngrok\.io/i, // 隧道服务
|
|
50
|
-
/serveo\.net/i,
|
|
51
|
-
/localtunnel\.me/i,
|
|
52
|
-
];
|
|
53
|
-
// ── 速率限制器 ────────────────────────────────────────────────────────
|
|
54
|
-
class RateLimiter {
|
|
55
|
-
requests = new Map();
|
|
56
|
-
/**
|
|
57
|
-
* 检查是否超过速率限制
|
|
58
|
-
* @returns true 表示超过限制
|
|
59
|
-
*/
|
|
60
|
-
isLimited(key, limit, windowMs = 60000) {
|
|
61
|
-
const now = Date.now();
|
|
62
|
-
const windowStart = now - windowMs;
|
|
63
|
-
// 获取或初始化请求记录
|
|
64
|
-
let timestamps = this.requests.get(key) || [];
|
|
65
|
-
// 清理过期记录
|
|
66
|
-
timestamps = timestamps.filter(t => t > windowStart);
|
|
67
|
-
// 检查是否超过限制
|
|
68
|
-
if (timestamps.length >= limit) {
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
// 记录本次请求
|
|
72
|
-
timestamps.push(now);
|
|
73
|
-
this.requests.set(key, timestamps);
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* 清理过期记录
|
|
78
|
-
*/
|
|
79
|
-
cleanup() {
|
|
80
|
-
const now = Date.now();
|
|
81
|
-
for (const [key, timestamps] of this.requests.entries()) {
|
|
82
|
-
const valid = timestamps.filter(t => t > now - 120000); // 保留 2 分钟内的记录
|
|
83
|
-
if (valid.length === 0) {
|
|
84
|
-
this.requests.delete(key);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
this.requests.set(key, valid);
|
|
81
|
+
export function checkNetworkCommandAccess(command, config) {
|
|
82
|
+
// 网络未启用时,阻断所有网络命令
|
|
83
|
+
if (!config.enableNetwork) {
|
|
84
|
+
for (const pattern of NETWORK_COMMAND_PATTERNS) {
|
|
85
|
+
if (pattern.test(command)) {
|
|
86
|
+
const cmd = command.match(pattern)?.[0]?.trim() || 'network command';
|
|
87
|
+
return {
|
|
88
|
+
allowed: false,
|
|
89
|
+
reason: `沙箱网络未启用,禁止执行网络命令: ${cmd}(配置 enableNetwork: true 以允许)`,
|
|
90
|
+
};
|
|
88
91
|
}
|
|
89
92
|
}
|
|
93
|
+
return { allowed: true };
|
|
90
94
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
99
|
-
this.rateLimiter = new RateLimiter();
|
|
100
|
-
// 定期清理速率限制器
|
|
101
|
-
this.cleanupTimer = setInterval(() => this.rateLimiter.cleanup(), 60000);
|
|
102
|
-
if (this.cleanupTimer && typeof this.cleanupTimer === 'object' && 'unref' in this.cleanupTimer) {
|
|
103
|
-
this.cleanupTimer.unref();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* 检查 URL 是否允许访问
|
|
108
|
-
*/
|
|
109
|
-
checkUrl(url, userId) {
|
|
110
|
-
if (!this.config.enabled) {
|
|
111
|
-
return { allowed: true };
|
|
112
|
-
}
|
|
113
|
-
let parsed;
|
|
114
|
-
try {
|
|
115
|
-
parsed = new URL(url);
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return { allowed: false, reason: '无效的 URL 格式' };
|
|
119
|
-
}
|
|
120
|
-
// 1. 协议检查
|
|
121
|
-
if (this.config.blockedProtocols?.includes(parsed.protocol.replace(':', ''))) {
|
|
122
|
-
return {
|
|
123
|
-
allowed: false,
|
|
124
|
-
reason: `禁止的协议: ${parsed.protocol}`,
|
|
125
|
-
sanitizedUrl: `${parsed.protocol}//***`,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
// 2. 端口检查
|
|
129
|
-
const port = parsed.port ? parseInt(parsed.port, 10) : this.getDefaultPort(parsed.protocol);
|
|
130
|
-
if (port && this.config.blockedPorts?.includes(port)) {
|
|
131
|
-
return {
|
|
132
|
-
allowed: false,
|
|
133
|
-
reason: `禁止的端口: ${port}`,
|
|
134
|
-
sanitizedUrl: `${parsed.protocol}//${parsed.hostname}:***`,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
// 3. 私有 IP 检查(在白名单检查之前)
|
|
138
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
139
|
-
if (this.config.blockPrivateIPs && this.isPrivateIP(hostname)) {
|
|
140
|
-
return {
|
|
141
|
-
allowed: false,
|
|
142
|
-
reason: '禁止访问私有 IP 地址',
|
|
143
|
-
sanitizedUrl: `${parsed.protocol}//***`,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
// 4. 可疑域名检查(在白名单检查之前)
|
|
147
|
-
if (this.isSuspiciousDomain(hostname)) {
|
|
148
|
-
return {
|
|
149
|
-
allowed: false,
|
|
150
|
-
reason: `可疑域名: ${this.maskDomain(hostname)}`,
|
|
151
|
-
sanitizedUrl: `${parsed.protocol}//${this.maskDomain(hostname)}`,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
// 5. 域名黑名单检查
|
|
155
|
-
if (this.isBlockedDomain(hostname)) {
|
|
156
|
-
return {
|
|
157
|
-
allowed: false,
|
|
158
|
-
reason: `域名在黑名单中: ${this.maskDomain(hostname)}`,
|
|
159
|
-
sanitizedUrl: `${parsed.protocol}//${this.maskDomain(hostname)}`,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
// 6. 域名白名单检查
|
|
163
|
-
if (this.config.allowedDomains && this.config.allowedDomains.length > 0) {
|
|
164
|
-
if (!this.isAllowedDomain(hostname)) {
|
|
95
|
+
// 网络已启用但有域名白名单时,校验 URL
|
|
96
|
+
if (config.allowedDomains && config.allowedDomains.length > 0) {
|
|
97
|
+
const urls = extractUrlsFromCommand(command);
|
|
98
|
+
if (urls.length === 0) {
|
|
99
|
+
// 网络命令必须包含可校验的 URL
|
|
100
|
+
const hasNetworkCommand = NETWORK_COMMAND_PATTERNS.some(pattern => pattern.test(command));
|
|
101
|
+
if (hasNetworkCommand) {
|
|
165
102
|
return {
|
|
166
103
|
allowed: false,
|
|
167
|
-
reason:
|
|
168
|
-
sanitizedUrl: `${parsed.protocol}//${this.maskDomain(hostname)}`,
|
|
104
|
+
reason: `启用 allowedDomains 时,网络命令必须包含可校验的 URL(如 http://example.com)`,
|
|
169
105
|
};
|
|
170
106
|
}
|
|
107
|
+
return { allowed: true };
|
|
171
108
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// 通过所有检查
|
|
182
|
-
return {
|
|
183
|
-
allowed: true,
|
|
184
|
-
sanitizedUrl: `${parsed.protocol}//${this.maskDomain(hostname)}${parsed.pathname}`,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* 检查域名是否在黑名单中
|
|
189
|
-
*/
|
|
190
|
-
isBlockedDomain(domain) {
|
|
191
|
-
if (!this.config.blockedDomains)
|
|
192
|
-
return false;
|
|
193
|
-
return this.config.blockedDomains.some(blocked => {
|
|
194
|
-
// 支持通配符匹配
|
|
195
|
-
if (blocked.startsWith('*.')) {
|
|
196
|
-
const suffix = blocked.slice(1); // *.example.com -> .example.com
|
|
197
|
-
return domain.endsWith(suffix) || domain === suffix.slice(1);
|
|
109
|
+
for (const url of urls) {
|
|
110
|
+
try {
|
|
111
|
+
const hostname = new URL(url).hostname;
|
|
112
|
+
if (!hostnameMatchesList(hostname, config.allowedDomains)) {
|
|
113
|
+
return {
|
|
114
|
+
allowed: false,
|
|
115
|
+
reason: `域名 ${hostname} 不在允许列表中(允许: ${config.allowedDomains.join(', ')})`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
198
118
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* 检查域名是否在白名单中
|
|
204
|
-
*/
|
|
205
|
-
isAllowedDomain(domain) {
|
|
206
|
-
if (!this.config.allowedDomains || this.config.allowedDomains.length === 0) {
|
|
207
|
-
return true; // 没有白名单则允许所有
|
|
208
|
-
}
|
|
209
|
-
return this.config.allowedDomains.some(allowed => {
|
|
210
|
-
if (allowed.startsWith('*.')) {
|
|
211
|
-
const suffix = allowed.slice(1);
|
|
212
|
-
return domain.endsWith(suffix) || domain === suffix.slice(1);
|
|
119
|
+
catch {
|
|
120
|
+
// URL 解析失败,放行(可能是相对路径或其他格式)
|
|
213
121
|
}
|
|
214
|
-
return domain === allowed || domain.endsWith(`.${allowed}`);
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* 检查是否为可疑域名
|
|
219
|
-
*/
|
|
220
|
-
isSuspiciousDomain(domain) {
|
|
221
|
-
return SUSPICIOUS_DOMAIN_PATTERNS.some(pattern => pattern.test(domain));
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* 检查是否为私有 IP
|
|
225
|
-
*/
|
|
226
|
-
isPrivateIP(hostname) {
|
|
227
|
-
// 简单的 IP 格式检查
|
|
228
|
-
const ipPattern = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
229
|
-
if (!ipPattern.test(hostname)) {
|
|
230
|
-
// 可能是域名,需要解析(这里简化处理)
|
|
231
|
-
return false;
|
|
232
122
|
}
|
|
233
|
-
return isPrivateIP(hostname);
|
|
234
123
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
124
|
+
return { allowed: true };
|
|
125
|
+
}
|
|
126
|
+
// ── exec-policy 层网络命令 URL 校验 ────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* 校验 exec-policy 允许的网络命令(curl/wget)的 URL 安全性
|
|
129
|
+
* - 阻断数据外泄模式(curl -d @file)
|
|
130
|
+
* - 阻断 SSRF 目标(内网/元数据端点)
|
|
131
|
+
*/
|
|
132
|
+
export function validateNetworkCommandUrl(command) {
|
|
133
|
+
// 数据外泄检测
|
|
134
|
+
if (isDataExfiltrationAttempt(command)) {
|
|
135
|
+
return {
|
|
136
|
+
safe: false,
|
|
137
|
+
reason: '检测到潜在数据外泄模式(curl -d @file)。如需上传文件,请使用具体的文件路径。',
|
|
244
138
|
};
|
|
245
|
-
return ports[protocol] || null;
|
|
246
139
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
140
|
+
// SSRF 检测
|
|
141
|
+
const url = extractFirstUrlFromCommand(command);
|
|
142
|
+
if (url) {
|
|
143
|
+
try {
|
|
144
|
+
const hostname = new URL(url).hostname;
|
|
145
|
+
if (isBlockedSsrfHostname(hostname)) {
|
|
146
|
+
return {
|
|
147
|
+
safe: false,
|
|
148
|
+
reason: `URL 目标 ${hostname} 属于内网/私有/危险地址,已被 SSRF 防护拦截。`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
254
151
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* 更新配置
|
|
260
|
-
*/
|
|
261
|
-
updateConfig(config) {
|
|
262
|
-
this.config = { ...this.config, ...config };
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* 获取配置(脱敏)
|
|
266
|
-
*/
|
|
267
|
-
getConfig() {
|
|
268
|
-
return { ...this.config };
|
|
269
|
-
}
|
|
270
|
-
dispose() {
|
|
271
|
-
if (this.cleanupTimer) {
|
|
272
|
-
clearInterval(this.cleanupTimer);
|
|
273
|
-
this.cleanupTimer = undefined;
|
|
152
|
+
catch {
|
|
153
|
+
// URL 解析失败,不拦截
|
|
274
154
|
}
|
|
275
155
|
}
|
|
276
|
-
}
|
|
277
|
-
// ── 全局网络策略实例 ──────────────────────────────────────────────────
|
|
278
|
-
let globalNetworkPolicy = null;
|
|
279
|
-
/**
|
|
280
|
-
* 获取全局网络策略实例
|
|
281
|
-
*/
|
|
282
|
-
export function getNetworkPolicy() {
|
|
283
|
-
if (!globalNetworkPolicy) {
|
|
284
|
-
globalNetworkPolicy = new NetworkPolicy();
|
|
285
|
-
}
|
|
286
|
-
return globalNetworkPolicy;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* 初始化网络策略
|
|
290
|
-
*/
|
|
291
|
-
export function initNetworkPolicy(config) {
|
|
292
|
-
globalNetworkPolicy = new NetworkPolicy(config);
|
|
293
|
-
return globalNetworkPolicy;
|
|
294
|
-
}
|
|
295
|
-
/** 重置全局网络策略(用于测试隔离) */
|
|
296
|
-
export function resetNetworkPolicy() {
|
|
297
|
-
globalNetworkPolicy = null;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* 检查 URL 是否允许访问
|
|
301
|
-
*/
|
|
302
|
-
export function checkNetworkAccess(url, userId) {
|
|
303
|
-
return getNetworkPolicy().checkUrl(url, userId);
|
|
156
|
+
return { safe: true };
|
|
304
157
|
}
|
|
305
158
|
//# sourceMappingURL=network-policy.js.map
|