Skip to content

Commit

Permalink
fix ZK-5733: URIBuilder causes warnings for resources from jar with "…
Browse files Browse the repository at this point in the history
…!" in url for f51152c
  • Loading branch information
jumperchen committed Jun 7, 2024
1 parent 1d1ffb9 commit 9b5cf71
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 69 deletions.
66 changes: 66 additions & 0 deletions zcommon/src/main/java/org/zkoss/util/URLs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* URLs.java
Purpose:
Description:
History:
4:11 PM 2024/6/7, Created by jumperchen
Copyright (C) 2024 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.util;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import org.apache.hc.core5.net.URIBuilder;

/**
* Utility class for URL operations.
* @author jumperchen
* @since 10.0.1
*/
public class URLs {

/**
* Sanitizes a URL to prevent MalformedURLException and SSRF warning.
*
* @param url The URL to be sanitized.
* @return The sanitized URL.
* @throws MalformedURLException If the URL is not in the correct format.
* @throws URISyntaxException If the URL is not formatted strictly according to RFC2396 and cannot be converted to a URI.
*/
public static URL sanitizeURL(URL url) throws MalformedURLException, URISyntaxException {
if (url == null) return null;

final String urlString = url.getPath();
// avoid java.net.MalformedURLException: no !/ in spec
if (urlString.contains("!/")) {
String[] parts = urlString.split("!/");
if (parts.length == 2) {
String jarFilePath = parts[0];
String internalPath = parts[1];

// Ensure the jarFilePath is properly formed
URL jarURL = new URL(jarFilePath);
URI jarURI = new URIBuilder().setScheme(jarURL.getProtocol())
.setHost(jarURL.getHost()).setPort(jarURL.getPort())
.setPath(jarURL.getPath()).build();

// Combine the jar URI with the internal path
return new URL("jar:" + jarURI + "!/" + internalPath);
} else {
throw new MalformedURLException("Invalid JAR URL format");
}
} else {
// prevent SSRF warning
return new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath())
.setCustomQuery(url.getQuery()).build().toURL();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
import java.net.URL;
import java.net.URLConnection;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.util.URLs;

/**
* A skeletal implementation that assumes the source is either URL or File.
*
Expand All @@ -42,10 +43,8 @@ public long getLastModified(K src) {
URLConnection conn = null;
try {
URL url = (URL) src;
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
// prevent SSRF attack
url = URLs.sanitizeURL(url);
conn = url.openConnection();
final long v = conn.getLastModified();
return v != -1 ? v : 0; //not to reload if unknown (5.0.6 for better performance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
import java.io.InputStreamReader;
import java.net.URL;

import org.apache.hc.core5.net.URIBuilder;

import org.zkoss.io.Files;
import org.zkoss.util.URLs;

/**
* A {@link Loader} that loads the resource by use URL.getContent()
Expand All @@ -40,10 +39,7 @@ public String load(Object src) throws Exception {
if (src instanceof URL) {
URL url = (URL) src;
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);
is = url.openStream();
} else if (src instanceof File) {
is = new FileInputStream((File) src);
Expand Down
7 changes: 2 additions & 5 deletions zhtml/src/main/java/org/zkoss/zhtml/impl/HtmlTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
import java.util.Scanner;

import org.apache.commons.io.input.ReaderInputStream;
import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.idom.Namespace;
import org.zkoss.idom.ProcessingInstruction;
import org.zkoss.util.Pair;
import org.zkoss.util.URLs;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.metainfo.TreeBuilder;
import org.zkoss.zsoup.Zsoup;
Expand Down Expand Up @@ -297,10 +297,7 @@ public org.zkoss.idom.Document parse(URL url) throws Exception {
if (log.isDebugEnabled())
log.debug("Parsing file: [{}]", url);
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);
try (InputStream inStream = url.openStream()) {
return convertToIDOM(Zsoup.parse(inStream, "UTF-8", url.getFile(),
Parser.xhtmlParser()));
Expand Down
32 changes: 3 additions & 29 deletions zk/src/main/java/org/zkoss/zk/ui/http/AbstractExtendlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

import javax.servlet.ServletContext;
Expand All @@ -29,14 +27,14 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.idom.Element;
import org.zkoss.idom.util.IDOMs;
import org.zkoss.lang.ClassResolver;
import org.zkoss.lang.Classes;
import org.zkoss.util.URLs;
import org.zkoss.util.resource.ResourceCache;
import org.zkoss.web.servlet.Servlets;
import org.zkoss.web.util.resource.Extendlet;
Expand Down Expand Up @@ -177,32 +175,8 @@ private InputStream getResourceAsStream(HttpServletRequest request, String path,
try {
URL url = _webctx.getResource(path);
if (url != null) {
final String urlString = url.getPath();
// avoid java.net.MalformedURLException: no !/ in spec
if (urlString.contains("!/")) {
String[] parts = urlString.split("!/");
if (parts.length == 2) {
String jarFilePath = parts[0];
String internalPath = parts[1];

// Ensure the jarFilePath is properly formed
URL jarURL = new URL(jarFilePath);
URI jarURI = new URIBuilder().setScheme(jarURL.getProtocol())
.setHost(jarURL.getHost()).setPort(jarURL.getPort())
.setPath(jarURL.getPath()).build();

// Combine the jar URI with the internal path
url = new URL("jar:" + jarURI + "!/" + internalPath);
} else {
throw new MalformedURLException("Invalid JAR URL format");
}
} else {
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath())
.setCustomQuery(url.getQuery()).build().toURL();
}
// prevent SSRF attack
url = URLs.sanitizeURL(url);
return url.openStream();
}
} catch (Throwable ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.html.HTMLs;
import org.zkoss.io.Files;
import org.zkoss.lang.Exceptions;
import org.zkoss.util.URLs;
import org.zkoss.util.resource.Locator;
import org.zkoss.web.servlet.Charsets;
import org.zkoss.web.servlet.Servlets;
Expand Down Expand Up @@ -210,10 +210,7 @@ protected Interpretation parse(String path, File file, Object extra) throws Exce

protected Interpretation parse(String path, URL url, Object extra) throws Exception {
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);

InputStream is = url.openStream();
if (is != null)
Expand Down
7 changes: 2 additions & 5 deletions zweb/src/main/java/org/zkoss/web/servlet/Servlets.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -55,6 +54,7 @@
import org.zkoss.util.CacheMap;
import org.zkoss.util.Checksums;
import org.zkoss.util.Locales;
import org.zkoss.util.URLs;
import org.zkoss.util.resource.Locator;
import org.zkoss.util.resource.Locators;
import org.zkoss.web.Attributes;
Expand Down Expand Up @@ -854,10 +854,7 @@ public static final InputStream getResourceAsStream(ServletContext ctx, String u
URL url = toURL(uri);
if (url != null) {
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);
return url.openStream();
}
return new ParsedURI(ctx, uri).getResourceAsStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
import java.net.URL;
import java.net.URLConnection;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.io.Files;
import org.zkoss.lang.Library;
import org.zkoss.util.URLs;
import org.zkoss.util.resource.Loader;

/**
Expand Down Expand Up @@ -82,10 +82,7 @@ public long getLastModified(String src) {
URL url = getExtendletContext().getResource(src);
if (url != null) {
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);
conn = url.openConnection();
final long v = conn.getLastModified();
return v != -1 ? v : 0; //not to reload (5.0.6 for better performance)
Expand Down Expand Up @@ -115,10 +112,7 @@ public V load(String src) throws Exception {
URL real = getExtendletContext().getResource(path);
if (real != null) {
// prevent SSRF warning
real = new URIBuilder().setScheme(real.getProtocol())
.setHost(real.getHost()).setPort(real.getPort())
.setPath(real.getPath()).setCustomQuery(real.getQuery())
.build().toURL();
real = URLs.sanitizeURL(real);
is = real.openStream();
}
} catch (Throwable ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
import java.net.URL;
import java.net.URLConnection;

import org.apache.hc.core5.net.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.zkoss.util.URLs;
import org.zkoss.util.resource.Loader;

/**
Expand Down Expand Up @@ -68,10 +68,7 @@ public long getLastModified(ResourceInfo src) {
try {
URL url = src.url;
// prevent SSRF warning
url = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost()).setPort(url.getPort())
.setPath(url.getPath()).setCustomQuery(url.getQuery())
.build().toURL();
url = URLs.sanitizeURL(url);
conn = url.openConnection();
final long v = conn.getLastModified();
return v != -1 ? v : 0; //not to reload (5.0.6 for better performance)
Expand Down

0 comments on commit 9b5cf71

Please sign in to comment.