Skip to content

Commit

Permalink
18.0.6 release
Browse files Browse the repository at this point in the history
  • Loading branch information
davidjgraph committed May 16, 2022
1 parent cc7e86d commit 7a68ebe
Show file tree
Hide file tree
Showing 14 changed files with 190 additions and 151 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/build-release.yml
Expand Up @@ -2,8 +2,6 @@ name: Build & Release

on:
push:
paths:
- VERSION

jobs:
build:
Expand Down
8 changes: 7 additions & 1 deletion ChangeLog
@@ -1,6 +1,12 @@
16-MAY-2022: 18.0.6

- Moves sanitize URL to Utils, adds extra IPv6 check
- Adds additional checks for hyperlinks

15-MAY-2022: 18.0.5

- Security improvements in Java code
- Adds isLinkLocalAddress() to address checks
- Limits well known servlet to serving single file

14-MAY-2022: 18.0.4

Expand Down
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
18.0.5
18.0.6
2 changes: 1 addition & 1 deletion src/main/java/com/mxgraph/online/EmbedServlet2.java
Expand Up @@ -393,7 +393,7 @@ public String createEmbedJavaScript(HttpServletRequest request)
try
{
// Checks if URL already fetched to avoid duplicates
if (!completed.contains(urls[i]))
if (!completed.contains(urls[i]) && Utils.sanitizeUrl(urls[i]))
{
completed.add(urls[i]);
URL url = new URL(urls[i]);
Expand Down
72 changes: 2 additions & 70 deletions src/main/java/com/mxgraph/online/ProxyServlet.java
Expand Up @@ -11,11 +11,9 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.net.InetAddress;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -68,7 +66,7 @@ protected void doGet(HttpServletRequest request,
{
String urlParam = request.getParameter("url");

if (checkUrlParameter(urlParam))
if (Utils.sanitizeUrl(urlParam))
{
// build the UML source from the compressed request parameter
String ref = request.getHeader("referer");
Expand Down Expand Up @@ -118,7 +116,7 @@ protected void doGet(HttpServletRequest request,
{
String redirectUrl = connection.getHeaderField("Location");

if (!checkUrlParameter(redirectUrl))
if (!Utils.sanitizeUrl(redirectUrl))
{
break;
}
Expand Down Expand Up @@ -235,72 +233,6 @@ protected void copyResponse(InputStream is, OutputStream out, byte[] head,
}
}

/**
* Checks if the URL parameter is legal.
*/
public boolean checkUrlParameter(String url)
{
if (url != null)
{
try
{
URL parsedUrl = new URL(url);
String protocol = parsedUrl.getProtocol();
String host = parsedUrl.getHost();
InetAddress address = InetAddress.getByName(host);
String hostAddress = address.getHostAddress();
host = host.toLowerCase();

return (protocol.equals("http") || protocol.equals("https"))
&& !address.isAnyLocalAddress()
&& !address.isLoopbackAddress()
&& !address.isLinkLocalAddress()
&& !host.endsWith(".internal") // Redundant
&& !host.endsWith(".local") // Redundant
&& !host.contains("localhost") // Redundant
&& !hostAddress.startsWith("0.") // 0.0.0.0/8
&& !hostAddress.startsWith("10.") // 10.0.0.0/8
&& !hostAddress.startsWith("127.") // 127.0.0.0/8
&& !hostAddress.startsWith("169.254.") // 169.254.0.0/16
&& !hostAddress.startsWith("172.16.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.17.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.18.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.19.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.20.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.21.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.22.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.23.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.24.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.25.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.26.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.27.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.28.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.29.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.30.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.31.") // 172.16.0.0/12
&& !hostAddress.startsWith("192.0.0.") // 192.0.0.0/24
&& !hostAddress.startsWith("192.168.") // 192.168.0.0/16
&& !hostAddress.startsWith("198.18.") // 198.18.0.0/15
&& !hostAddress.startsWith("198.19.") // 198.18.0.0/15
&& !hostAddress.startsWith("fc00::") // fc00::/7 https://stackoverflow.com/questions/53764109/is-there-a-java-api-that-will-identify-the-ipv6-address-fd00-as-local-private
&& !hostAddress.startsWith("fd00::") // fd00::/8
&& !host.endsWith(".arpa"); // reverse domain (needed?)
}
catch (MalformedURLException e)
{
return false;
}
catch (UnknownHostException e)
{
return false;
}
}
else
{
return false;
}
}

/**
* Returns true if the content check should be omitted.
*/
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/com/mxgraph/online/Utils.java
Expand Up @@ -12,7 +12,11 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
Expand Down Expand Up @@ -481,4 +485,73 @@ public static boolean isNumeric (String str)
return false;
}
}

/**
* Checks if the URL parameter is legal, i.e. isn't attempting an SSRF
*
* @param url the URL to check
* @return true if the URL is permitted
*/
public static boolean sanitizeUrl(String url)
{
if (url != null)
{
try
{
URL parsedUrl = new URL(url);
String protocol = parsedUrl.getProtocol();
String host = parsedUrl.getHost();
InetAddress address = InetAddress.getByName(host);
String hostAddress = address.getHostAddress();
host = host.toLowerCase();

return (protocol.equals("http") || protocol.equals("https"))
&& !address.isAnyLocalAddress()
&& !address.isLoopbackAddress()
&& !address.isLinkLocalAddress()
&& !host.endsWith(".internal") // Redundant
&& !host.endsWith(".local") // Redundant
&& !host.contains("localhost") // Redundant
&& !hostAddress.startsWith("0.") // 0.0.0.0/8
&& !hostAddress.startsWith("10.") // 10.0.0.0/8
&& !hostAddress.startsWith("127.") // 127.0.0.0/8
&& !hostAddress.startsWith("169.254.") // 169.254.0.0/16
&& !hostAddress.startsWith("172.16.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.17.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.18.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.19.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.20.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.21.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.22.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.23.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.24.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.25.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.26.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.27.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.28.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.29.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.30.") // 172.16.0.0/12
&& !hostAddress.startsWith("172.31.") // 172.16.0.0/12
&& !hostAddress.startsWith("192.0.0.") // 192.0.0.0/24
&& !hostAddress.startsWith("192.168.") // 192.168.0.0/16
&& !hostAddress.startsWith("198.18.") // 198.18.0.0/15
&& !hostAddress.startsWith("198.19.") // 198.18.0.0/15
&& !hostAddress.startsWith("fc00::") // fc00::/7 https://stackoverflow.com/questions/53764109/is-there-a-java-api-that-will-identify-the-ipv6-address-fd00-as-local-private
&& !hostAddress.startsWith("fd00::") // fd00::/8
&& !host.endsWith(".arpa"); // reverse domain (needed?)
}
catch (MalformedURLException e)
{
return false;
}
catch (UnknownHostException e)
{
return false;
}
}
else
{
return false;
}
}
}

0 comments on commit 7a68ebe

Please sign in to comment.