From 7860d635a92dd3a4c81fb74debbba1cd928b4491 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Fri, 4 Mar 2016 17:38:48 -0500 Subject: [PATCH] ensured deserialization is secure --- .../maven/BaseDependencyCheckMojo.java | 22 ++++- .../utils/ExpectedOjectInputStream.java | 70 ++++++++++++++ .../utils/ExpectedOjectInputStreamTest.java | 96 +++++++++++++++++++ .../dependencycheck/utils/SimplePojo.java | 29 ++++++ 4 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStream.java create mode 100644 dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStreamTest.java create mode 100644 dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SimplePojo.java diff --git a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java index c6ff64a13..fd319b90f 100644 --- a/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java +++ b/dependency-check-maven/src/main/java/org/owasp/dependencycheck/maven/BaseDependencyCheckMojo.java @@ -49,6 +49,7 @@ import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.reporting.ReportGenerator; +import org.owasp.dependencycheck.utils.ExpectedOjectInputStream; import org.owasp.dependencycheck.utils.Settings; import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; @@ -1035,9 +1036,26 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma } List ret = null; final String path = (String) oPath; - ObjectInputStream ois = null; + //ObjectInputStream ois = null; + ExpectedOjectInputStream ois = null; try { - ois = new ObjectInputStream(new FileInputStream(path)); + //ois = new ObjectInputStream(new FileInputStream(path)); + ois = new ExpectedOjectInputStream(new FileInputStream(path), + "java.util.ArrayList", + "java.util.HashSet", + "java.util.TreeSet", + "java.lang.AbstractSet", + "java.lang.AbstractCollection", + "java.lang.Enum", + "org.owasp.dependencycheck.dependency.Confidence", + "org.owasp.dependencycheck.dependency.Dependency", + "org.owasp.dependencycheck.dependency.Evidence", + "org.owasp.dependencycheck.dependency.EvidenceCollection", + "org.owasp.dependencycheck.dependency.Identifier", + "org.owasp.dependencycheck.dependency.Reference", + "org.owasp.dependencycheck.dependency.Vulnerability", + "org.owasp.dependencycheck.dependency.VulnerabilityComparator", + "org.owasp.dependencycheck.dependency.VulnerableSoftware"); ret = (List) ois.readObject(); } catch (FileNotFoundException ex) { //TODO fix logging diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStream.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStream.java new file mode 100644 index 000000000..7b1272e05 --- /dev/null +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStream.java @@ -0,0 +1,70 @@ +/* + * This file is part of dependency-check-core. + * + * 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. + * + * Copyright (c) 2016 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * An ObjectInputStream that will only deserialize expected classes. + * + * @author Jeremy Long + */ +public class ExpectedOjectInputStream extends ObjectInputStream { + + /** + * The list of fully qualified class names that are able to be deserialized. + */ + List expected = new ArrayList(); + + /** + * Constructs a new ExpectedOjectInputStream that can be used to securely deserialize an object by restricting the classes + * that can deserialized to a known set of expected classes. + * + * @param inputStream the input stream that contains the object to deserialize + * @param expected the fully qualified class names of the classes that can be deserialized + * @throws IOException thrown if there is an error reading from the stream + */ + public ExpectedOjectInputStream(InputStream inputStream, String... expected) throws IOException { + super(inputStream); + this.expected.addAll(Arrays.asList(expected)); + } + + /** + * Only deserialize instances of expected classes by validating the class name prior to deserialization. + * + * @param the class from the object stream to validate + * @return the resolved class + * @throws java.io.IOException thrown if the class being read is not one of the expected classes or if there is an error + * reading from the stream + * @throws java.lang.ClassNotFoundException thrown if there is an error finding the class to deserialize + */ + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + if (!this.expected.contains(desc.getName())) { + throw new InvalidClassException("Unexpected deserialization", desc.getName()); + } + return super.resolveClass(desc); + } +} diff --git a/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStreamTest.java b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStreamTest.java new file mode 100644 index 000000000..867dd1e7e --- /dev/null +++ b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/ExpectedOjectInputStreamTest.java @@ -0,0 +1,96 @@ +/* + * This file is part of dependency-check-core. + * + * 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. + * + * Copyright (c) 2016 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.utils; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * + * @author jeremy + */ +public class ExpectedOjectInputStreamTest { + + public ExpectedOjectInputStreamTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of resolveClass method, of class ExpectedOjectInputStream. + */ + @Test + public void testResolveClass() throws Exception { + List data = new ArrayList(); + data.add(new SimplePojo()); + + ByteArrayOutputStream mem = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(mem)); + out.writeObject(data); + out.flush(); + byte[] buf = mem.toByteArray(); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(buf); + + ExpectedOjectInputStream instance = new ExpectedOjectInputStream(in, "java.util.ArrayList", "org.owasp.dependencycheck.utils.SimplePojo", "java.lang.Integer", "java.lang.Number"); + instance.readObject(); + } + + /** + * Test of resolveClass method, of class ExpectedOjectInputStream. + */ + @Test(expected = java.io.InvalidClassException.class) + public void testResolveClassException() throws Exception { + List data = new ArrayList(); + data.add(new SimplePojo()); + + ByteArrayOutputStream mem = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(mem)); + out.writeObject(data); + out.flush(); + byte[] buf = mem.toByteArray(); + out.close(); + ByteArrayInputStream in = new ByteArrayInputStream(buf); + + ExpectedOjectInputStream instance = new ExpectedOjectInputStream(in, "java.util.ArrayList", "org.owasp.dependencycheck.utils.SimplePojo"); + instance.readObject(); + } +} diff --git a/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SimplePojo.java b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SimplePojo.java new file mode 100644 index 000000000..b3b5e2504 --- /dev/null +++ b/dependency-check-utils/src/test/java/org/owasp/dependencycheck/utils/SimplePojo.java @@ -0,0 +1,29 @@ +/* + * Copyright 2016 OWASP. + * + * 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 org.owasp.dependencycheck.utils; + +import java.io.Serializable; + +/** + * Simple pojo used to test the ExpectedObjectInputStream. + * + * @author jeremy + */ +public class SimplePojo implements Serializable { + + public String s = "3"; + public Integer i = 3; +}