// Copyright (c) All contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using MessagePack.Formatters;
using MessagePack.Internal;
namespace MessagePack
{
///
/// Settings related to security, particularly relevant when deserializing data from untrusted sources.
///
public class MessagePackSecurity
{
///
/// Gets an instance preconfigured with settings that omit all protections. Useful for deserializing fully-trusted and valid msgpack sequences.
///
public static readonly MessagePackSecurity TrustedData = new MessagePackSecurity();
///
/// Gets an instance preconfigured with protections applied with reasonable settings for deserializing untrusted msgpack sequences.
///
public static readonly MessagePackSecurity UntrustedData = new MessagePackSecurity
{
HashCollisionResistant = true,
MaximumObjectGraphDepth = 500,
};
private readonly ObjectFallbackEqualityComparer objectFallbackEqualityComparer;
private MessagePackSecurity()
{
this.objectFallbackEqualityComparer = new ObjectFallbackEqualityComparer(this);
}
///
/// Initializes a new instance of the class
/// with properties copied from a provided template.
///
/// The template to copy from.
protected MessagePackSecurity(MessagePackSecurity copyFrom)
: this()
{
if (copyFrom is null)
{
throw new ArgumentNullException(nameof(copyFrom));
}
this.HashCollisionResistant = copyFrom.HashCollisionResistant;
this.MaximumObjectGraphDepth = copyFrom.MaximumObjectGraphDepth;
}
///
/// Gets a value indicating whether data to be deserialized is untrusted and thus should not be allowed to create
/// dictionaries or other hash-based collections unless the hashed type has a hash collision resistant implementation available.
/// This can mitigate some denial of service attacks when deserializing untrusted code.
///
///
/// The value is false for and true for .
///
public bool HashCollisionResistant { get; private set; }
///
/// Gets the maximum depth of an object graph that may be deserialized.
///
///
///
/// This value can be reduced to avoid a stack overflow that would crash the process when deserializing a msgpack sequence designed to cause deep recursion.
/// A very short callstack on a thread with 1MB of total stack space might deserialize ~2000 nested arrays before crashing due to a stack overflow.
/// Since stack space occupied may vary by the kind of object deserialized, a conservative value for this property to defend against stack overflow attacks might be 500.
///
///
public int MaximumObjectGraphDepth { get; private set; } = int.MaxValue;
///
/// Gets a copy of these options with the property set to a new value.
///
/// The new value for the property.
/// The new instance; or the original if the value is unchanged.
public MessagePackSecurity WithMaximumObjectGraphDepth(int maximumObjectGraphDepth)
{
if (this.MaximumObjectGraphDepth == maximumObjectGraphDepth)
{
return this;
}
var clone = this.Clone();
clone.MaximumObjectGraphDepth = maximumObjectGraphDepth;
return clone;
}
///
/// Gets a copy of these options with the property set to a new value.
///
/// The new value for the property.
/// The new instance; or the original if the value is unchanged.
public MessagePackSecurity WithHashCollisionResistant(bool hashCollisionResistant)
{
if (this.HashCollisionResistant == hashCollisionResistant)
{
return this;
}
var clone = this.Clone();
clone.HashCollisionResistant = hashCollisionResistant;
return clone;
}
///
/// Gets an that is suitable to use with a hash-based collection.
///
/// The type of key that will be hashed in the collection.
/// The to use.
///
/// When is active, this will be a collision resistant instance which may reject certain key types.
/// When is not active, this will be .
///
public IEqualityComparer GetEqualityComparer()
{
return this.HashCollisionResistant ? GetHashCollisionResistantEqualityComparer() : EqualityComparer.Default;
}
///
/// Gets an that is suitable to use with a hash-based collection.
///
/// The to use.
///
/// When is active, this will be a collision resistant instance which may reject certain key types.
/// When is not active, this will be .
///
public IEqualityComparer GetEqualityComparer()
{
return this.HashCollisionResistant ? GetHashCollisionResistantEqualityComparer() : EqualityComparer