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.ObjectInputFilter; 020import java.io.ObjectInputStream; 021import java.io.ObjectStreamClass; 022import java.util.ArrayList; 023import java.util.List; 024 025/** 026 * HardenedObjectInputStream restricts the set of classes that can be 027 * deserialized to a set of explicitly whitelisted classes. This prevents 028 * certain type of attacks from being successful. 029 * 030 * <p> 031 * It is assumed that classes in the "java.lang" and "java.util" packages are 032 * always authorized. 033 * </p> 034 * 035 * @author Ceki Gülcü 036 * @since 1.2.0 037 */ 038public class HardenedObjectInputStream extends ObjectInputStream { 039 040 final private List<String> whitelistedClassNames; 041 final private static String[] JAVA_PACKAGES = new String[] { "java.lang", "java.util" }; 042 final private static int DEPTH_LIMIT = 16; 043 final private static int ARRAY_LIMIT = 10000; 044 045 public HardenedObjectInputStream(InputStream in, String[] whitelist) throws IOException { 046 super(in); 047 this.initObjectFilter(); 048 this.whitelistedClassNames = new ArrayList<String>(); 049 if (whitelist != null) { 050 for (int i = 0; i < whitelist.length; i++) { 051 this.whitelistedClassNames.add(whitelist[i]); 052 } 053 } 054 } 055 056 private void initObjectFilter() { 057 this.setObjectInputFilter(ObjectInputFilter.Config.createFilter( 058 "maxarray=" + ARRAY_LIMIT + ";maxdepth=" + DEPTH_LIMIT + ";" 059 )); 060 } 061 public HardenedObjectInputStream(InputStream in, List<String> whitelist) throws IOException { 062 super(in); 063 this.initObjectFilter(); 064 this.whitelistedClassNames = new ArrayList<String>(); 065 this.whitelistedClassNames.addAll(whitelist); 066 } 067 068 @Override 069 protected Class<?> resolveClass(ObjectStreamClass anObjectStreamClass) throws IOException, ClassNotFoundException { 070 071 String incomingClassName = anObjectStreamClass.getName(); 072 073 if (!isWhitelisted(incomingClassName)) { 074 throw new InvalidClassException("Unauthorized deserialization attempt", anObjectStreamClass.getName()); 075 } 076 077 return super.resolveClass(anObjectStreamClass); 078 } 079 080 private boolean isWhitelisted(String incomingClassName) { 081 for (int i = 0; i < JAVA_PACKAGES.length; i++) { 082 if (incomingClassName.startsWith(JAVA_PACKAGES[i])) 083 return true; 084 } 085 for (String whiteListed : whitelistedClassNames) { 086 if (incomingClassName.equals(whiteListed)) 087 return true; 088 } 089 return false; 090 } 091 092 protected void addToWhitelist(List<String> additionalAuthorizedClasses) { 093 whitelistedClassNames.addAll(additionalAuthorizedClasses); 094 } 095}