From cf25f49d1eff39a1db1fa091bc1969319321dbc0 Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 21:09:03 +0200 Subject: [PATCH 1/7] Updated changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67744e1c3..9197b9c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Fixed #### Changed +- [#466]: Updated `FastJson` tp latest version 1.2.51 #### Added From a82347d9d3358e98c89b48579d4285d807a57cc0 Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 21:12:56 +0200 Subject: [PATCH 2/7] Fix issue #458 --- .../java/ro/pippo/session/ClassFilter.java | 24 ++++++++++++++++++ .../session/FilteringObjectInputStream.java | 25 +++++++++++++++++++ .../SerializationSessionDataTranscoder.java | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java create mode 100644 pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java new file mode 100644 index 000000000..50a39b41c --- /dev/null +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java @@ -0,0 +1,24 @@ +package ro.pippo.session; + +import java.util.ArrayList; + +/** + * @author idealzh + */ +public class ClassFilter { + private ArrayList WhiteList= null; + public ClassFilter() { + WhiteList=new ArrayList(); + WhiteList.add("ro.pippo.session.SessionData"); + WhiteList.add("java.util.HashMap"); + WhiteList.add("ro.pippo.core.Flash"); + WhiteList.add("java.util.ArrayList"); + } + + public boolean isWhiteListed(String className) { + if (className==null) return false; + for(String name:WhiteList) { + if(name.equals(className)) return true; + } return false; + } +} \ No newline at end of file diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java new file mode 100644 index 000000000..e213be71d --- /dev/null +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java @@ -0,0 +1,25 @@ +package ro.pippo.session; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; + +/** + * @author idealzh + */ +public class FilteringObjectInputStream extends ObjectInputStream { + public FilteringObjectInputStream(InputStream in) throws IOException { + super(in); + } + + protected Class resolveClass(java.io.ObjectStreamClass descriptor) throws ClassNotFoundException, IOException { + String className = descriptor.getName(); + ClassFilter classFilter = new ClassFilter(); + if(className != null && className.length() > 0 && !classFilter.isWhiteListed(className)) { + throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName()); + } else { + return super.resolveClass(descriptor); + } + } +} diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java index 3510839e2..c7e99a876 100644 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java @@ -48,7 +48,7 @@ public String encode(SessionData sessionData) { public SessionData decode(String data) { byte[] bytes = Base64.getDecoder().decode(data); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); - ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) { + FilteringObjectInputStream objectInputStream = new FilteringObjectInputStream(inputStream)) { return (SessionData) objectInputStream.readObject(); } catch (IOException | ClassNotFoundException e) { throw new PippoRuntimeException(e, "Cannot deserialize session. A new one will be created."); From 066f8a280517da1b765af059363f2207dd49cc70 Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 21:15:40 +0200 Subject: [PATCH 3/7] Added changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9197b9c0b..c7a96e225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### [Unreleased][unreleased] #### Fixed +- [#458]: Java deserialization vulnerability in SerializationSessionDataTranscoder.decode() #### Changed - [#466]: Updated `FastJson` tp latest version 1.2.51 From fe30912538767945c428fcfe32977d0fb2c2f5bc Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 21:40:02 +0200 Subject: [PATCH 4/7] Whitelisted 'ro.pippo.session.DefaultSessionData' instead of 'ro.pippo.session.SessionData'. --- .../src/main/java/ro/pippo/session/ClassFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java index 50a39b41c..c43be44c5 100644 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java @@ -9,7 +9,7 @@ public class ClassFilter { private ArrayList WhiteList= null; public ClassFilter() { WhiteList=new ArrayList(); - WhiteList.add("ro.pippo.session.SessionData"); + WhiteList.add("ro.pippo.session.DefaultSessionData"); WhiteList.add("java.util.HashMap"); WhiteList.add("ro.pippo.core.Flash"); WhiteList.add("java.util.ArrayList"); From 59eb2eee1b5ab4fea02edc73168577a10473098a Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 22:11:12 +0200 Subject: [PATCH 5/7] Updated Code. --- .../java/ro/pippo/session/ClassFilter.java | 24 ------------ .../session/FilteringObjectInputStream.java | 39 +++++++++++++++++-- 2 files changed, 36 insertions(+), 27 deletions(-) delete mode 100644 pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java deleted file mode 100644 index c43be44c5..000000000 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/ClassFilter.java +++ /dev/null @@ -1,24 +0,0 @@ -package ro.pippo.session; - -import java.util.ArrayList; - -/** - * @author idealzh - */ -public class ClassFilter { - private ArrayList WhiteList= null; - public ClassFilter() { - WhiteList=new ArrayList(); - WhiteList.add("ro.pippo.session.DefaultSessionData"); - WhiteList.add("java.util.HashMap"); - WhiteList.add("ro.pippo.core.Flash"); - WhiteList.add("java.util.ArrayList"); - } - - public boolean isWhiteListed(String className) { - if (className==null) return false; - for(String name:WhiteList) { - if(name.equals(className)) return true; - } return false; - } -} \ No newline at end of file diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java index e213be71d..b45397d67 100644 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java @@ -1,25 +1,58 @@ +/* + * Copyright (C) 2016 the original author or authors. + * + * 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 ro.pippo.session; 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 static ro.pippo.core.util.StringUtils.isNullOrEmpty; /** * @author idealzh */ public class FilteringObjectInputStream extends ObjectInputStream { + private ArrayList whiteClassNames = new ArrayList(); + public FilteringObjectInputStream(InputStream in) throws IOException { super(in); + + whiteClassNames.add("ro.pippo.session.DefaultSessionData"); + whiteClassNames.add("java.util.HashMap"); + whiteClassNames.add("ro.pippo.core.Flash"); + whiteClassNames.add("java.util.ArrayList"); } - protected Class resolveClass(java.io.ObjectStreamClass descriptor) throws ClassNotFoundException, IOException { + protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFoundException, IOException { String className = descriptor.getName(); - ClassFilter classFilter = new ClassFilter(); - if(className != null && className.length() > 0 && !classFilter.isWhiteListed(className)) { + if (isNullOrEmpty(className) && !isWhiteListed(className)) { throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName()); } else { return super.resolveClass(descriptor); } } + + private boolean isWhiteListed(String className) { + if (className == null) return false; + for (Object name : whiteClassNames) { + if (name.equals(className)) return true; + } + return false; + } } From 79646fb3220694ae8fdfab7bd195717d2f61d611 Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Thu, 25 Oct 2018 22:37:19 +0200 Subject: [PATCH 6/7] Fixed typo. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7a96e225..e7dede781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - [#458]: Java deserialization vulnerability in SerializationSessionDataTranscoder.decode() #### Changed -- [#466]: Updated `FastJson` tp latest version 1.2.51 +- [#466]: Updated `FastJSON` to latest version 1.2.51 #### Added From 6e7176a2924fb6f900f10482de696497b55656fa Mon Sep 17 00:00:00 2001 From: Alexander Brandt Date: Fri, 26 Oct 2018 16:39:59 +0200 Subject: [PATCH 7/7] More fixes. --- CHANGELOG.md | 2 ++ .../core/util/WhitelistObjectInputStream.java | 35 ++++++++++++++++--- .../SerializationSessionDataTranscoder.java | 4 +-- 3 files changed, 34 insertions(+), 7 deletions(-) rename pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java => pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java (57%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7dede781..f4557660f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -535,8 +535,10 @@ Initial release. [0.3.0]: https://github.com/decebals/pippo/compare/pippo-parent-0.2.0...pippo-parent-0.3.0 [0.2.0]: https://github.com/decebals/pippo/compare/pippo-parent-0.1.0...pippo-parent-0.2.0 +[#466]: https://github.com/pippo-java/pippo/issues/466 [#460]: https://github.com/pippo-java/pippo/issues/460 [#459]: https://github.com/pippo-java/pippo/issues/459 +[#458]: https://github.com/pippo-java/pippo/issues/458 [#456]: https://github.com/pippo-java/pippo/pull/456 [#452]: https://github.com/pippo-java/pippo/pull/452 [#447]: https://github.com/pippo-java/pippo/pull/447 diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java b/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java similarity index 57% rename from pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java rename to pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java index b45397d67..fd100cadd 100644 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/FilteringObjectInputStream.java +++ b/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ro.pippo.session; +package ro.pippo.core.util; import java.io.IOException; import java.io.InputStream; @@ -21,16 +21,19 @@ import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; import static ro.pippo.core.util.StringUtils.isNullOrEmpty; /** * @author idealzh */ -public class FilteringObjectInputStream extends ObjectInputStream { - private ArrayList whiteClassNames = new ArrayList(); +public class WhitelistObjectInputStream extends ObjectInputStream { + private static List whiteClassNames = new ArrayList(); - public FilteringObjectInputStream(InputStream in) throws IOException { + public WhitelistObjectInputStream(InputStream in) throws IOException { super(in); whiteClassNames.add("ro.pippo.session.DefaultSessionData"); @@ -49,10 +52,32 @@ protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFou } private boolean isWhiteListed(String className) { - if (className == null) return false; for (Object name : whiteClassNames) { if (name.equals(className)) return true; } return false; } + + /** + * Load the whitelist from the properties file + */ + static void loadWhitelist() { + Properties whitelistProperties = new Properties(); + InputStream stream = null; + try { + stream = WhitelistObjectInputStream.class.getResourceAsStream("src/main/resources/pippo/whitelist-serialization.txt"); + whitelistProperties.load(stream); + } catch (IOException e) { + throw new RuntimeException("Error loading the whitelist-serialization.properties file", e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + throw new RuntimeException("Error closing the resource-serialization.properties file", e); + } + } + } + Collections.addAll(whiteClassNames, whitelistProperties.getProperty("whitelist").split(",")); + } } diff --git a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java index c7e99a876..5d103da02 100644 --- a/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java +++ b/pippo-session-parent/pippo-session/src/main/java/ro/pippo/session/SerializationSessionDataTranscoder.java @@ -16,11 +16,11 @@ package ro.pippo.session; import ro.pippo.core.PippoRuntimeException; +import ro.pippo.core.util.WhitelistObjectInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Base64; @@ -48,7 +48,7 @@ public String encode(SessionData sessionData) { public SessionData decode(String data) { byte[] bytes = Base64.getDecoder().decode(data); try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); - FilteringObjectInputStream objectInputStream = new FilteringObjectInputStream(inputStream)) { + WhitelistObjectInputStream objectInputStream = new WhitelistObjectInputStream(inputStream)) { return (SessionData) objectInputStream.readObject(); } catch (IOException | ClassNotFoundException e) { throw new PippoRuntimeException(e, "Cannot deserialize session. A new one will be created.");