jeecgboot/JeecgBoot · error · JeecgBootBizTipException

原始接口路径仅支持相对路径或 http(s) 完整URL

Error message

原始接口路径仅支持相对路径或 http(s) 完整URL

What it means

Thrown when a non-http relative path contains a scheme separator ('://') or starts with a dangerous scheme (file:, ftp:, gopher:, jar:, netdoc:). This blocks SSRF and local-file-read attempts via the OpenAPI proxy that forwards originUrl to an upstream.

Source

Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java:273

            // 二次解码,防止 %252f 这类双重编码绕过
            decoded = java.net.URLDecoder.decode(decoded, "UTF-8");
        } catch (Exception e) {
            throw new JeecgBootBizTipException("原始接口路径包含非法字符");
        }
        //update-begin---author:scott ---date:20260429  for:【issues/9590】微服务nginx部署openApi接口访问不到-----------
        // 微服务部署时,OpenAPI 配置的接口可能位于其他微服务模块(如 erp 7003),允许 originUrl 直接配置完整 http(s) URL
        String lower = decoded.toLowerCase();
        boolean isFullHttpUrl = lower.startsWith("http://") || lower.startsWith("https://");
        if (!isFullHttpUrl) {
            if (!decoded.startsWith("/")) {
                throw new JeecgBootBizTipException("原始接口路径必须以 / 开头,或填写完整的 http(s) URL");
            }
            if (decoded.startsWith("//") || decoded.startsWith("/\\")) {
                throw new JeecgBootBizTipException("原始接口路径不能以 // 或 /\\ 开头");
            }
            if (lower.contains("://") || lower.startsWith("file:") || lower.startsWith("ftp:") || lower.startsWith("gopher:")
                    || lower.startsWith("jar:") || lower.startsWith("netdoc:")) {
                throw new JeecgBootBizTipException("原始接口路径仅支持相对路径或 http(s) 完整URL");
            }
        } else {
            // 即便是完整URL,也禁止其它危险协议(防止 http://x@file:/... 之类的绕过场景)
            String afterScheme = lower.substring(lower.indexOf("://") + 3);
            if (afterScheme.contains("file:") || afterScheme.contains("ftp:") || afterScheme.contains("gopher:")
                    || afterScheme.contains("jar:") || afterScheme.contains("netdoc:")) {
                throw new JeecgBootBizTipException("原始接口路径不允许嵌套 file/ftp/gopher/jar/netdoc 等协议");
            }
        }
        if (decoded.contains("..")) {
            throw new JeecgBootBizTipException("原始接口路径不能包含 ..");
        }
        //update-end---author:scott ---date:20260429  for:【issues/9590】微服务nginx部署openApi接口访问不到-----------
    }

    @GetMapping("/json")
    public SwaggerModel swaggerModel() {

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Replace the dangerous scheme with a relative '/path' or a full 'http(s)://host/path' URL.
  2. Search the open_api table for rows whose origin_url matches file:|ftp:|gopher:|jar:|netdoc: and correct them.
  3. Add a client-side regex gate in the admin UI rejecting these schemes before submit.

Example fix

// before: originUrl = "file:///data/config.json"
// after:  originUrl = "/sys/api/config"
Defensive patterns

Strategy: validation

Validate before calling

private static final java.util.regex.Pattern DANGEROUS =
    java.util.regex.Pattern.compile("://|^(file:|ftp:|gopher:|jar:|netdoc:)", java.util.regex.Pattern.CASE_INSENSITIVE);
private static boolean isSafeRelative(String s) {
    return s != null && s.startsWith("/") && !DANGEROUS.matcher(s.toLowerCase()).find();
}

Prevention

When it happens

Trigger: origin_url set to 'file:///etc/passwd', 'ftp://internal/data', 'gopher://...', or a relative path that after double-decode contains '://' (e.g. '%3a%2f%2f').

Common situations: Security testing / penetration attempts; misconfigured import that loaded unsafe URLs; legacy data with absolute non-http URLs.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/fba7ee0b3b8357c0. Report an issue: GitHub.