jeecgboot/JeecgBoot · error · JeecgBootException
非法URL:仅允许 http / https 协议
Error message
非法URL:仅允许 http / https 协议
What it means
Thrown by checkSsrfHttpUrl when the URL scheme is not http or https (case-insensitive). This prevents server-side requests via dangerous protocols like file://, gopher://, dict://, ftp://, jar://, netdoc:// that could read local files or perform SSRF-adjacent attacks. The check explicitly blocks any non-HTTP scheme.
Source
Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java:334
* 1. 仅允许 http / https 协议;
* 2. 解析主机IP,拒绝 loopback(127.x / ::1)和 link-local(169.254.x,含云元数据 169.254.169.254 / fe80:);
* 注意:RFC1918 私网段(10/172.16/192.168)允许通过,兼容企业内网 MinIO/OSS/文件服务等合法用途。
*
* @param fileUrl HTTP(S) URL
*/
public static void checkSsrfHttpUrl(String fileUrl) {
if (StringUtils.isBlank(fileUrl)) {
throw new JeecgBootException("非法URL:地址为空");
}
URI uri;
try {
uri = new URI(fileUrl);
} catch (URISyntaxException e) {
throw new JeecgBootException("非法URL:格式错误");
}
String scheme = uri.getScheme();
if (scheme == null || !(scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https"))) {
throw new JeecgBootException("非法URL:仅允许 http / https 协议");
}
String host = uri.getHost();
if (StringUtils.isBlank(host)) {
throw new JeecgBootException("非法URL:主机名为空");
}
// 去掉 IPv6 的中括号
if (host.startsWith("[") && host.endsWith("]")) {
host = host.substring(1, host.length() - 1);
}
try {
for (InetAddress addr : InetAddress.getAllByName(host)) {
if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
throw new JeecgBootException("非法URL:禁止访问本机或链路本地地址 " + addr.getHostAddress());
}
}
} catch (UnknownHostException e) {
throw new JeecgBootException("非法URL:主机名无法解析");
}View on GitHub (pinned to 96fb33f5ec)
Solutions
- Ensure only http:// and https:// URLs are accepted from users — enforce this in front-end validation.
- If the URL lacks a scheme, prepend 'https://' only if the host is trusted.
- Strip any 'file://', 'ftp://', or other non-http schemes at the data-entry boundary.
- Review upstream callers (FileDownloadUtils, AiragChatServiceImpl) to confirm they always pass http(s) URLs.
Example fix
// before
String fileUrl = "file:///etc/passwd";
SsrfFileTypeFilter.checkSsrfHttpUrl(fileUrl); // throws
// after
String fileUrl = userInput;
if (!fileUrl.toLowerCase().startsWith("http://") && !fileUrl.toLowerCase().startsWith("https://")) {
return Result.error("仅支持 http/https 链接");
}
SsrfFileTypeFilter.checkSsrfHttpUrl(fileUrl); Defensive patterns
Strategy: validation
Validate before calling
String lowerUrl = fileUrl.toLowerCase();
if (!lowerUrl.startsWith("http://") && !lowerUrl.startsWith("https://")) {
return Result.error("仅支持 http/https 协议");
} Try / catch
try {
SsrfFileTypeFilter.checkSsrfHttpUrl(fileUrl);
} catch (JeecgBootException e) {
log.warn("Blocked non-HTTP scheme in URL: {}", fileUrl);
return Result.error(e.getMessage());
} Prevention
- Restrict URL input fields to http/https schemes on the front-end.
- Reject file://, ftp://, gopher:// and other schemes at the data entry boundary.
- Never construct server-side download URLs from unvalidated user input.
When it happens
Trigger: Passing a file:// URL (e.g., 'file:///etc/passwd'), a gopher:// URL for protocol smuggling, an ftp:// URL, or a URL missing its scheme entirely (uri.getScheme() returns null for scheme-less URIs).
Common situations: User supplies a local file path with 'file://' prefix expecting local file access; legacy code constructs URLs from user input that may include protocol other than http; front-end allows free-text URL input without scheme restriction.
Related errors
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/3736adf8a921c8bd.
Report an issue: GitHub.