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ülcü 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}