Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dangerous type blacklist feature to Akka.Serialization.Hyperion #5208

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void Hyperion_serializer_should_have_correct_defaults()
Assert.True(serializer.Settings.VersionTolerance);
Assert.True(serializer.Settings.PreserveObjectReferences);
Assert.Equal("NoKnownTypes", serializer.Settings.KnownTypesProvider.Name);
Assert.True(serializer.Settings.DisallowUnsafeType);
}
}

Expand All @@ -50,6 +51,7 @@ public void Hyperion_serializer_should_allow_to_setup_custom_flags()
serialization-settings.hyperion {
preserve-object-references = false
version-tolerance = false
disallow-unsafe-type = true
}
}
");
Expand All @@ -59,6 +61,7 @@ public void Hyperion_serializer_should_allow_to_setup_custom_flags()
Assert.False(serializer.Settings.VersionTolerance);
Assert.False(serializer.Settings.PreserveObjectReferences);
Assert.Equal("NoKnownTypes", serializer.Settings.KnownTypesProvider.Name);
Assert.False(serializer.Settings.DisallowUnsafeType);
}
}

Expand All @@ -82,6 +85,7 @@ public void Hyperion_serializer_should_allow_to_setup_custom_types_provider_with
Assert.True(serializer.Settings.VersionTolerance);
Assert.True(serializer.Settings.PreserveObjectReferences);
Assert.Equal(typeof(DummyTypesProviderWithDefaultCtor), serializer.Settings.KnownTypesProvider);
Assert.True(serializer.Settings.DisallowUnsafeType);
}
}

Expand All @@ -105,6 +109,7 @@ public void Hyperion_serializer_should_allow_to_setup_custom_types_provider_with
Assert.True(serializer.Settings.VersionTolerance);
Assert.True(serializer.Settings.PreserveObjectReferences);
Assert.Equal(typeof(DummyTypesProvider), serializer.Settings.KnownTypesProvider);
Assert.True(serializer.Settings.DisallowUnsafeType);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
Expand Down Expand Up @@ -36,14 +41,16 @@ public void Setup_should_be_converted_to_settings_correctly()
{
var setup = HyperionSerializerSetup.Empty
.WithPreserveObjectReference(true)
.WithKnownTypeProvider<NoKnownTypes>();
.WithKnownTypeProvider<NoKnownTypes>()
.WithDisallowUnsafeType(false);
var settings =
new HyperionSerializerSettings(
false,
false,
typeof(DummyTypesProvider),
new Func<string, string>[] { s => $"{s}.." },
new Surrogate[0]);
new Surrogate[0],
true);
var appliedSettings = setup.ApplySettings(settings);

appliedSettings.PreserveObjectReferences.Should().BeTrue(); // overriden
Expand All @@ -52,6 +59,7 @@ public void Setup_should_be_converted_to_settings_correctly()
appliedSettings.PackageNameOverrides.Count().Should().Be(1); // from settings
appliedSettings.PackageNameOverrides.First()("a").Should().Be("a..");
appliedSettings.Surrogates.ToList().Count.Should().Be(0); // from settings
appliedSettings.DisallowUnsafeType.ShouldBe(false); // overriden
}

[Fact]
Expand Down Expand Up @@ -115,5 +123,26 @@ public void Setup_surrogate_should_work()
surrogated.Count.Should().Be(1);
surrogated[0].Should().BeEquivalentTo(expected);
}

[Theory]
[MemberData(nameof(DangerousObjectFactory))]
public void Setup_disallow_unsafe_type_should_work(object dangerousObject, Type type)
{
var serializer = new HyperionSerializer((ExtendedActorSystem)Sys, HyperionSerializerSettings.Default);
var serialized = serializer.ToBinary(dangerousObject);
serializer.Invoking(s => s.FromBinary(serialized, type)).Should().Throw<SerializationException>();
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
}

public static IEnumerable<object[]> DangerousObjectFactory()
{
yield return new object[]{ new FileInfo("C:\\Windows\\System32"), typeof(FileInfo) };
yield return new object[]{ new ClaimsIdentity(), typeof(ClaimsIdentity)};
yield return new object[]{ WindowsIdentity.GetAnonymous(), typeof(WindowsIdentity) };
yield return new object[]{ new WindowsPrincipal(WindowsIdentity.GetAnonymous()), typeof(WindowsPrincipal)};
#if NET471
yield return new object[]{ new Process(), typeof(Process)};
#endif
yield return new object[]{ new ClaimsIdentity(), typeof(ClaimsIdentity)};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using Akka.Actor;
Expand Down Expand Up @@ -86,7 +86,8 @@ public HyperionSerializer(ExtendedActorSystem system, HyperionSerializerSettings
serializerFactories: null,
knownTypes: provider.GetKnownTypes(),
ignoreISerializable:true,
packageNameOverrides: settings.PackageNameOverrides));
packageNameOverrides: settings.PackageNameOverrides,
disallowUnsafeTypes: settings.DisallowUnsafeType));
}

/// <summary>
Expand Down Expand Up @@ -164,7 +165,8 @@ public sealed class HyperionSerializerSettings
versionTolerance: true,
knownTypesProvider: typeof(NoKnownTypes),
packageNameOverrides: new List<Func<string, string>>(),
surrogates: new Surrogate[0]);
surrogates: new Surrogate[0],
disallowUnsafeType: true);

/// <summary>
/// Creates a new instance of <see cref="HyperionSerializerSettings"/> using provided HOCON config.
Expand All @@ -185,7 +187,7 @@ public static HyperionSerializerSettings Create(Config config)
throw ConfigurationException.NullOrEmptyConfig<HyperionSerializerSettings>("akka.actor.serialization-settings.hyperion");

var typeName = config.GetString("known-types-provider", null);
var type = !string.IsNullOrEmpty(typeName) ? Type.GetType(typeName, true) : null;
var type = !string.IsNullOrWhiteSpace(typeName) ? Type.GetType(typeName, true) : null;

var framework = RuntimeInformation.FrameworkDescription;
string frameworkKey;
Expand Down Expand Up @@ -232,7 +234,8 @@ public static HyperionSerializerSettings Create(Config config)
versionTolerance: config.GetBoolean("version-tolerance", true),
knownTypesProvider: type,
packageNameOverrides: packageNameOverrides,
surrogates: surrogates);
surrogates: surrogates,
disallowUnsafeType: config.GetBoolean("disallow-unsafe-type", true));
}

/// <summary>
Expand Down Expand Up @@ -268,6 +271,12 @@ public static HyperionSerializerSettings Create(Config config)
/// Hyperion directly.
/// </summary>
public readonly IEnumerable<Surrogate> Surrogates;

/// <summary>
/// If set, will cause the Hyperion serializer to block potentially dangerous and unsafe types
/// from being deserialized during run-time
/// </summary>
public readonly bool DisallowUnsafeType;

/// <summary>
/// Creates a new instance of a <see cref="HyperionSerializerSettings"/>.
Expand All @@ -278,7 +287,7 @@ public static HyperionSerializerSettings Create(Config config)
/// <exception cref="ArgumentException">Raised when `known-types-provider` type doesn't implement <see cref="IKnownTypesProvider"/> interface.</exception>
[Obsolete]
public HyperionSerializerSettings(bool preserveObjectReferences, bool versionTolerance, Type knownTypesProvider)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, new List<Func<string, string>>())
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, new List<Func<string, string>>(), new Surrogate[0], true)
{ }

/// <summary>
Expand All @@ -295,16 +304,8 @@ public HyperionSerializerSettings(
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides)
{
knownTypesProvider = knownTypesProvider ?? typeof(NoKnownTypes);
if (!typeof(IKnownTypesProvider).IsAssignableFrom(knownTypesProvider))
throw new ArgumentException($"Known types provider must implement an interface {typeof(IKnownTypesProvider).FullName}");

PreserveObjectReferences = preserveObjectReferences;
VersionTolerance = versionTolerance;
KnownTypesProvider = knownTypesProvider;
PackageNameOverrides = packageNameOverrides;
}
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, new Surrogate[0], true)
{ }

/// <summary>
/// Creates a new instance of a <see cref="HyperionSerializerSettings"/>.
Expand All @@ -321,6 +322,26 @@ public HyperionSerializerSettings(
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates)
: this(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, true)
{ }

/// <summary>
/// Creates a new instance of a <see cref="HyperionSerializerSettings"/>.
/// </summary>
/// <param name="preserveObjectReferences">Flag which determines if serializer should keep track of references in serialized object graph.</param>
/// <param name="versionTolerance">Flag which determines if field data should be serialized as part of type manifest.</param>
/// <param name="knownTypesProvider">Type implementing <see cref="IKnownTypesProvider"/> to be used to determine a list of types implicitly known by all cooperating serializer.</param>
/// <param name="packageNameOverrides">An array of package name overrides for cross platform compatibility</param>
/// <param name="surrogates">A list of <see cref="Surrogate"/> instances that are used to de/serialize complex objects into a much simpler serialized objects.</param>
/// <param name="disallowUnsafeType">Block unsafe types from being deserialized.</param>
/// <exception cref="ArgumentException">Raised when `known-types-provider` type doesn't implement <see cref="IKnownTypesProvider"/> interface.</exception>
public HyperionSerializerSettings(
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates,
bool disallowUnsafeType)
{
knownTypesProvider = knownTypesProvider ?? typeof(NoKnownTypes);
if (!typeof(IKnownTypesProvider).IsAssignableFrom(knownTypesProvider))
Expand All @@ -331,6 +352,7 @@ public HyperionSerializerSettings(
KnownTypesProvider = knownTypesProvider;
PackageNameOverrides = packageNameOverrides;
Surrogates = surrogates;
DisallowUnsafeType = disallowUnsafeType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,52 @@ namespace Akka.Serialization.Hyperion
public class HyperionSerializerSetup : Setup
{
public static readonly HyperionSerializerSetup Empty =
new HyperionSerializerSetup(Option<bool>.None, Option<bool>.None, null, null, null);
new HyperionSerializerSetup(Option<bool>.None, Option<bool>.None, null, null, null, Option<bool>.None);

public static HyperionSerializerSetup Create(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider)
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, null, null);
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, null, null, Option<bool>.None);

public static HyperionSerializerSetup Create(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides)
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, null);
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, null, Option<bool>.None);

public static HyperionSerializerSetup Create(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates)
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates);
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, Option<bool>.None);

public static HyperionSerializerSetup Create(
bool preserveObjectReferences,
bool versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates,
bool disallowUnsafeType)
=> new HyperionSerializerSetup(preserveObjectReferences, versionTolerance, knownTypesProvider, packageNameOverrides, surrogates, disallowUnsafeType);

private HyperionSerializerSetup(
Option<bool> preserveObjectReferences,
Option<bool> versionTolerance,
Type knownTypesProvider,
IEnumerable<Func<string, string>> packageNameOverrides,
IEnumerable<Surrogate> surrogates)
IEnumerable<Surrogate> surrogates,
Option<bool> disallowUnsafeType)
{
PreserveObjectReferences = preserveObjectReferences;
VersionTolerance = versionTolerance;
KnownTypesProvider = knownTypesProvider;
PackageNameOverrides = packageNameOverrides;
Surrogates = surrogates;
DisallowUnsafeType = disallowUnsafeType;
}

/// <summary>
Expand Down Expand Up @@ -88,14 +99,21 @@ private HyperionSerializerSetup(
/// into a much simpler serialized objects.
/// </summary>
public IEnumerable<Surrogate> Surrogates { get; }

/// <summary>
/// If set, will cause the Hyperion serializer to block potentially dangerous and unsafe types
/// from being deserialized during run-time
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public Option<bool> DisallowUnsafeType { get; }

internal HyperionSerializerSettings ApplySettings(HyperionSerializerSettings settings)
=> new HyperionSerializerSettings(
PreserveObjectReferences.HasValue ? PreserveObjectReferences.Value : settings.PreserveObjectReferences,
VersionTolerance.HasValue ? VersionTolerance.Value : settings.VersionTolerance,
KnownTypesProvider ?? settings.KnownTypesProvider,
PackageNameOverrides ?? settings.PackageNameOverrides,
Surrogates ?? settings.Surrogates
Surrogates ?? settings.Surrogates,
DisallowUnsafeType.HasValue ? DisallowUnsafeType.Value : settings.DisallowUnsafeType
);

public HyperionSerializerSetup WithPreserveObjectReference(bool preserveObjectReference)
Expand All @@ -116,17 +134,23 @@ public HyperionSerializerSetup WithPackageNameOverrides(IEnumerable<Func<string,
public HyperionSerializerSetup WithSurrogates(IEnumerable<Surrogate> surrogates)
=> Copy(surrogates: surrogates);

public HyperionSerializerSetup WithDisallowUnsafeType(bool disallowUnsafeType)
=> Copy(disallowUnsafeType: disallowUnsafeType);

private HyperionSerializerSetup Copy(
bool? preserveObjectReferences = null,
bool? versionTolerance = null,
Type knownTypesProvider = null,
IEnumerable<Func<string, string>> packageNameOverrides = null,
IEnumerable<Surrogate> surrogates = null)
IEnumerable<Surrogate> surrogates = null,
bool? disallowUnsafeType = null
)
=> new HyperionSerializerSetup(
preserveObjectReferences ?? PreserveObjectReferences,
versionTolerance ?? VersionTolerance,
knownTypesProvider ?? KnownTypesProvider,
packageNameOverrides ?? PackageNameOverrides,
surrogates ?? Surrogates);
surrogates ?? Surrogates,
disallowUnsafeType ?? DisallowUnsafeType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,35 @@
# between actor systems using different assembly versions, making incremental
# cluster updates less restrictive.
version-tolerance = true

# If true, hyperion serializer will block potentially dangerous and unsafe types
# from being deserialized during run-time. The types that are blocked are:
Aaronontheweb marked this conversation as resolved.
Show resolved Hide resolved
# System.Security.Claims.ClaimsIdentity
# System.Windows.Forms.AxHost.State
# System.Windows.Data.ObjectDataProvider
# System.Management.Automation.PSObject
# System.Web.Security.RolePrincipal
# System.IdentityModel.Tokens.SessionSecurityToken
# SessionViewStateHistoryItem
# TextFormattingRunProperties
# ToolboxItemContainer
# System.Security.Principal.WindowsClaimsIdentity
# System.Security.Principal.WindowsIdentity
# System.Security.Principal.WindowsPrincipal
# System.CodeDom.Compiler.TempFileCollection
# System.IO.FileSystemInfo
# System.Activities.Presentation.WorkflowDesigner
# System.Windows.ResourceDictionary
# System.Windows.Forms.BindingSource
# Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider
# System.Diagnostics.Process
# System.Management.IWbemClassObjectFreeThreaded
disallow-unsafe-type = true

# A fully qualified type name with assembly to a type implementing
# `Akka.Serialization.IKnownTypesProvider` interface, that can be used to supply
# hyperion serializer with a list of types, that are expected to be well-known for
# all communicating parties, effectivelly reducing a manifests size and serialization
# all communicating parties, effectively reducing a manifests size and serialization
# time. No types are known by default. Implementing class must expose either a default
# constructor or constructor accepting an `ExtendedActorSystem` as its only parameter.
known-types-provider = "Akka.Serialization.NoKnownTypes, Akka.Serialization.Hyperion"
Expand Down