Tomcatは:無効である[ヌル]に正規化されています

環境

  1. Tomcatの8.5

理由

Tomcatコンテナのルートディレクトリを超えた相対パス場合は、コンフィギュレーション・ファイルをロードするように相対パスを使用する場合は、Tomcatは、プロンプトが表示されますxxx has been normalized to [null] which is not valid

分析

のは、Tomcatのソースを分析してみましょう。

検証

次のようにStandardRootでは、validateメソッドがあり、この方法は、注釈されています。

/**
    * Ensures that this object is in a valid state to serve resources, checks
    * that the path is a String that starts with '/' and checks that the path
    * can be normalized without stepping outside of the root.
    *
    * @param path
    * @return  the normalized path
    */

最後に、この方法は、エラーの原因を説明したが、それはコンテナのルートから逸脱することなく可能です。

ノーマライズ

この方法は、ここでは、論理ルートを確認し、それを超えるパスパラメータを、解析することができます。親ディレクトリを解消すると、ルートディレクトリの外にあることが判明した場合、単純にはnullを返します。

while (true) {
    int index = normalized.indexOf("/../");
    if (index < 0) {
        break;
    }
    if (index == 0) {
        return null;  // Trying to go outside our context
    }
    int index2 = normalized.lastIndexOf('/', index - 1);
    normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
}

外部配置

外部設定する前に、相対パス以来、エラーが発生した場合、コンテナのルートを超えて、必要性を変更すると、達成するためのURLを使用することができます。

URL url = Thread.currentThread().getContextClassLoader().getResource("");

try {

    Resource resource = new UrlResource(url).createRelative(EXTERNAL_CONFIG_FILE);

    if (!resource.exists()) {

        logger.info("外部配置不存在。");
        return;
    }

    logger.info("外部配置存在。");
    ResourcePropertySource source = new ResourcePropertySource(new EncodedResource(resource, "UTF-8"));
    // 外部配置的优先级最高
    beanFactory.getBean(StandardEnvironment.class).getPropertySources().addFirst(source);

} catch (IOException e) {

    logger.error("加载外部配置出错。", e);
}

付録

検証方法

/**
 * Ensures that this object is in a valid state to serve resources, checks
 * that the path is a String that starts with '/' and checks that the path
 * can be normalized without stepping outside of the root.
 *
 * @param path
 * @return  the normalized path
 */
private String validate(String path) {
    if (!getState().isAvailable()) {
        throw new IllegalStateException(
                sm.getString("standardRoot.checkStateNotStarted"));
    }

    if (path == null || path.length() == 0 || !path.startsWith("/")) {
        throw new IllegalArgumentException(
                sm.getString("standardRoot.invalidPath", path));
    }

    String result;
    if (File.separatorChar == '\\') {
        // On Windows '\\' is a separator so in case a Windows style
        // separator has managed to make it into the path, replace it.
        result = RequestUtil.normalize(path, true);
    } else {
        // On UNIX and similar systems, '\\' is a valid file name so do not
        // convert it to '/'
        result = RequestUtil.normalize(path, false);
    }

    // 检查到超出根目录,在这里抛出了异常。
    if (result == null || result.length() == 0 || !result.startsWith("/")) {
        throw new IllegalArgumentException(
                sm.getString("standardRoot.invalidPathNormal", path, result));
    }

    return result;
}

normalizeメソッド

/**
 * Normalize a relative URI path that may have relative values ("/./",
 * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
 * useful only for normalizing application-generated paths.  It does not
 * try to perform security checks for malicious input.
 *
 * @param path Relative path to be normalized
 * @param replaceBackSlash Should '\\' be replaced with '/'
 *
 * @return The normalized path or <code>null</code> if the path cannot be
 *         normalized
 */
public static String normalize(String path, boolean replaceBackSlash) {

    if (path == null) {
        return null;
    }

    // Create a place for the normalized path
    String normalized = path;

    if (replaceBackSlash && normalized.indexOf('\\') >= 0)
        normalized = normalized.replace('\\', '/');

    // Add a leading "/" if necessary
    if (!normalized.startsWith("/"))
        normalized = "/" + normalized;

    boolean addedTrailingSlash = false;
    if (normalized.endsWith("/.") || normalized.endsWith("/..")) {
        normalized = normalized + "/";
        addedTrailingSlash = true;
    }

    // Resolve occurrences of "//" in the normalized path
    while (true) {
        int index = normalized.indexOf("//");
        if (index < 0) {
            break;
        }
        normalized = normalized.substring(0, index) + normalized.substring(index + 1);
    }

    // Resolve occurrences of "/./" in the normalized path
    while (true) {
        int index = normalized.indexOf("/./");
        if (index < 0) {
            break;
        }
        normalized = normalized.substring(0, index) + normalized.substring(index + 2);
    }

    // 在这里检查,超出根目录返回null。
    // Resolve occurrences of "/../" in the normalized path
    while (true) {
        int index = normalized.indexOf("/../");
        if (index < 0) {
            break;
        }
        if (index == 0) {
            return null;  // Trying to go outside our context
        }
        int index2 = normalized.lastIndexOf('/', index - 1);
        normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
    }

    if (normalized.length() > 1 && addedTrailingSlash) {
        // Remove the trailing '/' we added to that input and output are
        // consistent w.r.t. to the presence of the trailing '/'.
        normalized = normalized.substring(0, normalized.length() - 1);
    }

    // Return the normalized path that we have completed
    return normalized;
}

おすすめ

転載: www.cnblogs.com/jiangbo44/p/11948981.html