001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2022, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.net;
015
016import java.io.IOException;
017import java.io.InputStream;
018import java.io.InvalidClassException;
019import java.io.ObjectInputStream;
020import java.io.ObjectStreamClass;
021import java.util.ArrayList;
022import java.util.List;
023
024/**
025 * HardenedObjectInputStream restricts the set of classes that can be
026 * deserialized to a set of explicitly whitelisted classes. This prevents
027 * certain type of attacks from being successful.
028 * 
029 * <p>
030 * It is assumed that classes in the "java.lang" and "java.util" packages are
031 * always authorized.
032 * </p>
033 * 
034 * @author Ceki G&uuml;lc&uuml;
035 * @since 1.2.0
036 */
037public class HardenedObjectInputStream extends ObjectInputStream {
038
039    final List<String> whitelistedClassNames;
040    final static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util" };
041
042    public HardenedObjectInputStream(InputStream in, String[] whilelist) throws IOException {
043        super(in);
044
045        this.whitelistedClassNames = new ArrayList<String>();
046        if (whilelist != null) {
047            for (int i = 0; i < whilelist.length; i++) {
048                this.whitelistedClassNames.add(whilelist[i]);
049            }
050        }
051    }
052
053    public HardenedObjectInputStream(InputStream in, List<String> whitelist) throws IOException {
054        super(in);
055
056        this.whitelistedClassNames = new ArrayList<String>();
057        this.whitelistedClassNames.addAll(whitelist);
058    }
059
060    @Override
061    protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException {
062
063        String incomingClassName = anObjectStreamClass.getName();
064
065        if (!isWhitelisted(incomingClassName)) {
066            throw new InvalidClassException("Unauthorized deserialization attempt", anObjectStreamClass.getName());
067        }
068
069        return super.resolveClass(anObjectStreamClass);
070    }
071
072    private boolean isWhitelisted(String incomingClassName) {
073        for (int i = 0; i < JAVA_PACKAGES.length; i++) {
074            if (incomingClassName.startsWith(JAVA_PACKAGES[i]))
075                return true;
076        }
077        for (String whiteListed : whitelistedClassNames) {
078            if (incomingClassName.equals(whiteListed))
079                return true;
080        }
081        return false;
082    }
083
084    protected void addToWhitelist(List<String> additionalAuthorizedClasses) {
085        whitelistedClassNames.addAll(additionalAuthorizedClasses);
086    }
087}