diff --git a/src/metabase/api/geojson.clj b/src/metabase/api/geojson.clj index 03242b3242c5f1e43c7210c91a45eaaa786cd97e..6b3e2288c49bf0a9c1e10ddd7fe961d8326aeb11 100644 --- a/src/metabase/api/geojson.clj +++ b/src/metabase/api/geojson.clj @@ -8,7 +8,7 @@ [ring.util.codec :as rc] [ring.util.response :as rr] [schema.core :as s]) - (:import java.net.URL + (:import [java.net InetAddress URL] org.apache.commons.io.input.ReaderInputStream)) (def ^:private CustomGeoJSON @@ -36,13 +36,16 @@ (tru "URLs referring to hosts that supply internal hosting metadata are prohibited."))) (def ^:private invalid-hosts - #{"169.254.169.254" ; internal metadata for AWS, OpenStack, and Azure - "metadata.google.internal"}) ; internal metadata for GCP - + #{"metadata.google.internal"}) ; internal metadata for GCP (defn- valid-host? [^URL url] - (not (invalid-hosts (.getHost url)))) + (let [host (.getHost url) + host->url (fn [host] (URL. (str "http://" host))) + base-url (host->url (.getHost url))] + (and (not-any? (fn [invalid-url] (.equals ^URL base-url invalid-url)) + (map host->url invalid-hosts)) + (not (.isLinkLocalAddress (InetAddress/getByName host)))))) (defn- valid-protocol? [^URL url] @@ -52,8 +55,8 @@ [url-string] (try (let [url (URL. url-string)] - (and (valid-host? url) - (valid-protocol? url))) + (and (valid-protocol? url) + (valid-host? url))) (catch Throwable e (throw (ex-info (invalid-location-msg) {:status-code 400, :url url-string} e))))) diff --git a/test/metabase/api/geojson_test.clj b/test/metabase/api/geojson_test.clj index 60012dfbd9cabbd233a2be9714b4a3a72d8192bd..dd06356457db363afee6b19b86b2d3c01082bcb4 100644 --- a/test/metabase/api/geojson_test.clj +++ b/test/metabase/api/geojson_test.clj @@ -35,19 +35,35 @@ (deftest validate-geojson-test (testing "It validates URLs and files appropriately" - (let [examples {;; Prohibited hosts (see explanation in source file) + (let [examples {;; Internal metadata for GCP "metadata.google.internal" false "https://metadata.google.internal" false "//metadata.google.internal" false + ;; Link-local addresses (internal metadata for AWS, OpenStack, and Azure) + "http://169.254.0.0" false + "http://fe80::" false "169.254.169.254" false "http://169.254.169.254/secret-stuff.json" false + ;; alternate IPv4 encodings (hex, octal, integer) + "http://0xa9fea9fe" false + "https://0xa9fea9fe" false + "http://0xA9FEA9FE" false + "http://0xa9.0xfe.0xa9.0xfe" false + "http://0XA9.0XFE.0xA9.0XFE" false + "http://0xa9fea9fe/secret-stuff.json" false + "http://025177524776" false + "http://0251.0376.0251.0376" false + "http://2852039166" false ;; Prohibited protocols "ftp://example.com/rivendell.json" false "example.com/rivendell.json" false + "jar:file:test.jar!/test.json" false ;; Acceptable URLs "http://example.com/" true "https://example.com/" true "http://example.com/rivendell.json" true + "http://192.0.2.0" true + "http://0xc0000200" true ;; Resources (files on classpath) are valid "c3p0.properties" true ;; Other files are not