All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.rest.api.service.sanitizer.UrlSanitizerUtils Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.rest.api.service.sanitizer;

import io.gravitee.rest.api.service.exceptions.InvalidDataException;
import io.gravitee.rest.api.service.exceptions.UrlForbiddenException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
 * @author GraviteeSource Team
 */
public class UrlSanitizerUtils {

    public static void checkAllowed(String url, List whitelist, boolean allowPrivate) {
        if (whitelist != null && !whitelist.isEmpty()) {
            if (
                whitelist
                    .stream()
                    .noneMatch(
                        whitelistUrl ->
                            whitelistUrl.endsWith("/")
                                ? url.startsWith(whitelistUrl)
                                : (url.equals(whitelistUrl) || url.startsWith(whitelistUrl + '/'))
                    )
            ) {
                throw new UrlForbiddenException();
            }
        } else if (!allowPrivate && UrlSanitizerUtils.isPrivate(url)) {
            throw new UrlForbiddenException();
        }
    }

    public static boolean isPrivate(String url) {
        try {
            InetAddress inetAddress = Inet6Address.getByName(new URL(url).getHost());

            return (
                inetAddress.isSiteLocalAddress() ||
                inetAddress.isAnyLocalAddress() ||
                inetAddress.isLoopbackAddress() ||
                inetAddress.isLinkLocalAddress() ||
                inetAddress.isMulticastAddress() ||
                isPrivateOwasp(inetAddress.getHostAddress())
            );
        } catch (Exception e) {
            throw new InvalidDataException("Url [" + url + "] is invalid");
        }
    }

    /**
     * Check ip address is private using owasp algorithm.
     */
    private static boolean isPrivateOwasp(String ipAddress) {
        List ipPrefixes = new ArrayList<>();

        // Add prefix for loopback addresses.
        ipPrefixes.add("127.");
        ipPrefixes.add("0.");

        // Add IP V4 prefix for private addresses.
        // See https://en.wikipedia.org/wiki/Private_network
        ipPrefixes.add("10.");
        ipPrefixes.add("172.16.");
        ipPrefixes.add("172.17.");
        ipPrefixes.add("172.18.");
        ipPrefixes.add("172.19.");
        ipPrefixes.add("172.20.");
        ipPrefixes.add("172.21.");
        ipPrefixes.add("172.22.");
        ipPrefixes.add("172.23.");
        ipPrefixes.add("172.24.");
        ipPrefixes.add("172.25.");
        ipPrefixes.add("172.26.");
        ipPrefixes.add("172.27.");
        ipPrefixes.add("172.28.");
        ipPrefixes.add("172.29.");
        ipPrefixes.add("172.30.");
        ipPrefixes.add("172.31.");
        ipPrefixes.add("192.168.");
        ipPrefixes.add("169.254.");

        // Add IP V6 prefix for private addresses.
        // See https://en.wikipedia.org/wiki/Unique_local_address
        // See https://en.wikipedia.org/wiki/Private_network
        // See https://simpledns.com/private-ipv6
        ipPrefixes.add("fc");
        ipPrefixes.add("fd");
        ipPrefixes.add("fe");
        ipPrefixes.add("ff");
        ipPrefixes.add("::1");
        ipPrefixes.add("0:0:0:0:0:0:0:0");

        // Verify the provided IP address
        // Remove whitespace characters from the beginning/end of the string and convert it to lower case
        // Lower case is for preventing any IPV6 case bypass using mixed case depending on the source used to get the IP address

        String ipToVerify = ipAddress.toLowerCase();
        // Perform the check against the list of prefix

        for (String prefix : ipPrefixes) {
            if (ipToVerify.startsWith(prefix)) {
                return true;
            }
        }

        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy