cn_provider_probe_url.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. package service
  2. // CN 供应商探测端点的出站 URL 安全策略校验(配额/余额探测共用)。
  3. //
  4. // 背景(review B4):这两条探测路径会把账号 API key 发往 base_url 衍生端点,
  5. // 此前完全绕过 security.url_allowlist——在加固部署里构成任意外发与内网探测
  6. // 面(本项目此前发生过账号测试 SSRF 生产事件)。与网关转发
  7. // (validateUpstreamBaseURL)、Grok 探测(grokOperatorPolicyValidator)一致,
  8. // 探测发起前必须过同一套运营者策略。
  9. import (
  10. "errors"
  11. "fmt"
  12. "strings"
  13. "github.com/Wei-Shaw/sub2api/internal/config"
  14. "github.com/Wei-Shaw/sub2api/internal/util/urlvalidator"
  15. )
  16. // cnValidateProbeURL 按全局出站 URL 安全策略校验探测端点,返回规范化 URL。
  17. // 白名单开启时强制 UpstreamHosts(阻断私网与未列名主机);关闭时仅做格式
  18. // 校验(HTTP 允许与否跟随配置);cfg 为 nil 时退化为纯格式校验。
  19. func cnValidateProbeURL(cfg *config.Config, raw string) (string, error) {
  20. trimmed := strings.TrimSpace(raw)
  21. if trimmed == "" {
  22. return "", errors.New("probe url is required")
  23. }
  24. if cfg != nil && cfg.Security.URLAllowlist.Enabled {
  25. normalized, err := urlvalidator.ValidateHTTPSURL(trimmed, urlvalidator.ValidationOptions{
  26. AllowedHosts: cfg.Security.URLAllowlist.UpstreamHosts,
  27. RequireAllowlist: true,
  28. AllowPrivate: cfg.Security.URLAllowlist.AllowPrivateHosts,
  29. })
  30. if err != nil {
  31. return "", fmt.Errorf("probe target rejected by URL security policy: %w", err)
  32. }
  33. return normalized, nil
  34. }
  35. var allowInsecureHTTP bool
  36. if cfg != nil {
  37. allowInsecureHTTP = cfg.Security.URLAllowlist.AllowInsecureHTTP
  38. }
  39. normalized, err := urlvalidator.ValidateURLFormat(trimmed, allowInsecureHTTP)
  40. if err != nil {
  41. return "", fmt.Errorf("probe target rejected by URL security policy: %w", err)
  42. }
  43. return normalized, nil
  44. }