All rules
CA2312Security Enabled by default: No

Ensure NetDataContractSerializer.Binder is set before deserializing

Ensure NetDataContractSerializer.Binder is set before deserializing

Microsoft docs

Description

This rule finds System.Runtime.Serialization.NetDataContractSerializer deserialization method calls or references when the System.Runtime.Serialization.NetDataContractSerializer.Binder might be null. If you want to disallow any deserialization with System.Runtime.Serialization.NetDataContractSerializer regardless of the System.Runtime.Serialization.NetDataContractSerializer.Binder property, disable this rule and CA2311, and enable rule CA2310.

NetDataContractSerializer is insecure and can't be made secure. For more information, see the BinaryFormatter security guide.

Cause

A System.Runtime.Serialization.NetDataContractSerializer deserialization method was called or referenced and the System.Runtime.Serialization.NetDataContractSerializer.Binder property may be null.

This rule is similar to CA2311, but analysis can't determine if the System.Runtime.Serialization.NetDataContractSerializer.Binder is definitely null.

By default, this rule analyzes the entire codebase, but this is configurable. Restricting types with a SerializationBinder can't prevent all attacks. For more information, see the BinaryFormatter security guide.

Example

using System;
using System.IO;
using System.Runtime.Serialization;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[DataContract]
public class BookRecord
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public AisleLocation Location { get; set; }
}

[DataContract]
public class AisleLocation
{
    [DataMember]
    public char Aisle { get; set; }

    [DataMember]
    public byte Shelf { get; set; }
}

public class Binders
{
    public static SerializationBinder BookRecord = new BookRecordSerializationBinder();
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        NetDataContractSerializer serializer = new NetDataContractSerializer();
        serializer.Binder = Binders.BookRecord;
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) serializer.Deserialize(ms);
        }
    }
}

using System;
using System.IO;
using System.Runtime.Serialization;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[DataContract]
public class BookRecord
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public AisleLocation Location { get; set; }
}

[DataContract]
public class AisleLocation
{
    [DataMember]
    public char Aisle { get; set; }

    [DataMember]
    public byte Shelf { get; set; }
}

public class Binders
{
    public static SerializationBinder BookRecord = new BookRecordSerializationBinder();
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        NetDataContractSerializer serializer = new NetDataContractSerializer();

        // Ensure that Binder is always non-null before deserializing
        serializer.Binder = Binders.BookRecord ?? throw new Exception("Expected non-null");

        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) serializer.Deserialize(ms);
        }
    }
}

using System;
using System.IO;
using System.Runtime.Serialization;

[DataContract]
public class BookRecord
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public string Author { get; set; }

    [DataMember]
    public int PageCount { get; set; }

    [DataMember]
    public AisleLocation Location { get; set; }
}

[DataContract]
public class AisleLocation
{
    [DataMember]
    public char Aisle { get; set; }

    [DataMember]
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public NetDataContractSerializer Serializer { get; set; }

    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) this.Serializer.Deserialize(ms);    // CA2312 violation
        }
    }
}

using System;
using System.IO;
using System.Runtime.Serialization;

public class BookRecordSerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        // One way to discover expected types is through testing deserialization
        // of **valid** data and logging the types used.

        ////Console.WriteLine($"BindToType('{assemblyName}', '{typeName}')");

        if (typeName == "BookRecord")
        {
            return typeof(BookRecord);
        }
        else if (typeName == "AisleLocation")
        {
            return typeof(AisleLocation);
        }
        else
        {
            throw new ArgumentException("Unexpected type", nameof(typeName));
        }
    }
}

[DataContract]
public class BookRecord
{
    [DataMember]
    public string Title { get; set; }

    [DataMember]
    public string Author { get; set; }

    [DataMember]
    public int PageCount { get; set; }

    [DataMember]
    public AisleLocation Location { get; set; }
}

[DataContract]
public class AisleLocation
{
    [DataMember]
    public char Aisle { get; set; }

    [DataMember]
    public byte Shelf { get; set; }
}

public class ExampleClass
{
    public BookRecord DeserializeBookRecord(byte[] bytes)
    {
        NetDataContractSerializer serializer = new NetDataContractSerializer();
        serializer.Binder = new BookRecordSerializationBinder();
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            return (BookRecord) serializer.Deserialize(ms);
        }
    }
}

When to suppress

NetDataContractSerializer is insecure and can't be made secure.

Group results
0 yes 0 no
ConsensusNone (disabled)
Severity preference (yes voters)
Suggestion0
Warning0
Error0