diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index 5186d1dc48727c..9e3b8d332f4eb4 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -506,4 +506,7 @@ Cannot allocate a buffer of size {0}. + + Serialization and deserialization of 'System.Type' instances are not supported and should be avoided since they can lead to security issues. + \ No newline at end of file diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index ee9488ed2c0cb2..94c7b47f1b0c6f 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -109,6 +109,7 @@ + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TypeConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TypeConverter.cs new file mode 100644 index 00000000000000..1fae3f3a58ac86 --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/TypeConverter.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json.Serialization.Converters +{ + internal sealed class TypeConverter : JsonConverter + { + public override Type Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotSupportedException(SR.SerializeTypeInstanceNotSupported); + } + + public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options) + { + throw new NotSupportedException(SR.SerializeTypeInstanceNotSupported); + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index 3e884eb49621bc..8a241a13c9fd99 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -37,7 +37,7 @@ public sealed partial class JsonSerializerOptions private static Dictionary GetDefaultSimpleConverters() { - const int NumberOfSimpleConverters = 21; + const int NumberOfSimpleConverters = 22; var converters = new Dictionary(NumberOfSimpleConverters); // Use a dictionary for simple converters. @@ -59,6 +59,7 @@ private static Dictionary GetDefaultSimpleConverters() Add(new SByteConverter()); Add(new SingleConverter()); Add(new StringConverter()); + Add(new TypeConverter()); Add(new UInt16Converter()); Add(new UInt32Converter()); Add(new UInt64Converter()); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index 6ff469e1616d0d..f43c530a6eeda1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -28,7 +28,7 @@ public static void ThrowNotSupportedException_SerializationNotSupported(Type pro [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static NotSupportedException ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo constructorInfo, Type type) + public static void ThrowNotSupportedException_ConstructorMaxOf64Parameters(ConstructorInfo constructorInfo, Type type) { throw new NotSupportedException(SR.Format(SR.ConstructorMaxOf64Parameters, constructorInfo, type)); } diff --git a/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs b/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs index ae5a45b9431383..a9db0e73b64854 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs @@ -526,5 +526,58 @@ public static void UnsupportedTypeFromRoot() // Root-level Types (not from a property) do not include the Path. Assert.DoesNotContain("Path: $", ex.Message); } + + [Fact] + public static void DeserializeTypeInstance() + { + string json = @"""System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"""; + + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json)); + string exAsStr = ex.ToString(); + Assert.Contains("System.Type", exAsStr); + Assert.Contains("$", exAsStr); + + json = $@"{{""Type"":{json}}}"; + + ex = Assert.Throws(() => JsonSerializer.Deserialize(json)); + exAsStr = ex.ToString(); + Assert.Contains("System.Type", exAsStr); + Assert.Contains("$.Type", exAsStr); + + // NSE is not thrown because the serializer handles null. + Assert.Null(JsonSerializer.Deserialize("null")); + + ClassWithType obj = JsonSerializer.Deserialize(@"{""Type"":null}"); + Assert.Null(obj.Type); + } + + [Fact] + public static void SerializeTypeInstance() + { + Type type = typeof(int); + + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Serialize(type)); + string exAsStr = ex.ToString(); + Assert.Contains("System.Type", exAsStr); + Assert.Contains("$", exAsStr); + + type = null; + string serialized = JsonSerializer.Serialize(type); + Assert.Equal("null", serialized); + + ClassWithType obj = new ClassWithType { Type = typeof(int) }; + + ex = Assert.Throws(() => JsonSerializer.Serialize(obj)); + exAsStr = ex.ToString(); + Assert.Contains("System.Type", exAsStr); + Assert.Contains("$.Type", exAsStr); + + obj.Type = null; + serialized = JsonSerializer.Serialize(obj); + Assert.Equal(@"{""Type"":null}", serialized); + + serialized = JsonSerializer.Serialize(obj, new JsonSerializerOptions { IgnoreNullValues = true }); + Assert.Equal(@"{}", serialized); + } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs index 7d64e125493ea4..9be040589afe29 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs @@ -1853,4 +1853,9 @@ public void Verify() MyData.Verify(); } } + + public class ClassWithType + { + public Type Type { get; set; } + } }