Secure GetObjectData overrides

TypeName

SecureGetObjectDataOverrides

CheckId

CA2110

Category

Microsoft.Security

Breaking Change

Breaking

Cause

A method is named GetObjectData, is declared in a type that implements the System.Runtime.Serialization.ISerializable interface, and takes a System.Runtime.Serialization.SerializationInfo object and a System.Runtime.Serialization.StreamingContext object as parameters. The method is not protected by a demand for System.Security.Permissions.SecurityPermissionAttribute.SerializationFormatter security permission.

Rule Description

The System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) method is declared in the ISerializable interface. This interface is implemented by types that provide custom serialization logic. GetObjectData is protected by a security check for System.Security.Permissions.SecurityPermissionAttribute.SerializationFormatter security permission. If an implementation of GetObjectData is not protected by the same security check, callers can call the implementation to bypass security on the interface and gain access to data serialized by the type.

How to Fix Violations

To fix a violation of this rule, apply the following attribute to the GetObjectData method:

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)].

When to Exclude Warnings

Do not exclude a warning from this rule.

Example

The following code shows a library that violates the rule and an application that exploits the library's weakness.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;

namespace SecurityRulesLibrary
{
   [Serializable]
   public class MySerializableObject :ISerializable
   {
      private  int n1;
      private  DateTime date;
      private string str;
      
      private MySerializableObject (){}
      
      public MySerializableObject (string s, int num1)
      {
         n1 = num1;
         str = (s == null ? "<empty>" : s);
         // This value is intended to be private and unviewable.
         date = DateTime.Today; 
      }
      public MySerializableObject(SerializationInfo info, StreamingContext context)
      {
         n1 = (int) info.GetValue("n1", typeof(int));
         date = (DateTime) info.GetValue("date", typeof(DateTime));
         str = (string) info.GetValue("str", typeof(string));
      }

      // The ISerializable interface member that provides the serialization logic. 
      // Violates rule: GetObjectDataRequiresSerializationFormatterSecurityPermissionAttribute.
      
      public void GetObjectData(SerializationInfo info, StreamingContext context)
      {
         info.AddValue("n1", n1);
         info.AddValue("date", date);
         info.AddValue("str", str);
      }
   }
}

The following code exploits the library's weakness.

using System;
using System.Security;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;

[assembly: SecurityPermissionAttribute(
   SecurityAction.RequestRefuse, SerializationFormatter = true)]
namespace TestSecurityLibrary
{
    public class TestGetObjectData
    {
        int n1;
        DateTime date;
        string str;
        SerializationInfo info = new SerializationInfo(
           typeof(MySerializableObject),
           new FormatterConverter());
        StreamingContext context = new StreamingContext(
           StreamingContextStates.All);

        private void GetInformation(SerializationInfo info)
        {
            // Use the SerializationInfo to look at all of 
            // the serialized object's private data.
            n1 = info.GetInt32("n1");
            date = info.GetDateTime("date");
            str = info.GetString("str");
        }

        private void GetTheObjectDirectly(MySerializableObject obj)
        {
            // Bypasses security that protects the interface.
            obj.GetObjectData(info, context);
            GetInformation(info);
            Console.WriteLine("Directly: {0}, {1}, {2}", str, n1, date);
        }

        private void GetTheObjectThroughInterface(MySerializableObject obj)
        {
            // This call causes a security exception in a type that does
            // not have SerializationFormatter security permission.

            ((ISerializable)obj).GetObjectData(info, context);
            GetInformation(info);
            Console.WriteLine(
               "ISerializable: {0}, {1}, {2}", str, n1, date);
        }

        public static void Main()
        {
            // Get an instance of the object.
            MySerializableObject anObject =
               new MySerializableObject("test", 1);

            // Call GetObjectData directly and 
            // then call through the interface.

            TestGetObjectData getDirect = new TestGetObjectData();
            // Succeeds - Bypasses the security on the interface.
            getDirect.GetTheObjectDirectly(anObject);

            TestGetObjectData getIndirect = new TestGetObjectData();

            try
            {
                // Fails - Shows the security on the interface.
                getIndirect.GetTheObjectThroughInterface(anObject);
            }
            catch (SecurityException e)
            {
                Console.WriteLine(
                   "Object cannot be accessed through the interface - {0}",
                   e.Message);
            }

        }
    }
}

This example produces the following output.

Output

Directly: test, 1, 7/30/2002 12:00:00 AM
Object cannot be accessed through the interface - Request for the permission of type System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.

Secure serialization constructors

Implement serialization constructors

Mark ISerializable types with serializable

Override link demands should be identical to base

See Also

Reference

System.Runtime.Serialization.ISerializable
System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)
System.Runtime.Serialization.SerializationInfo
System.Runtime.Serialization.StreamingContext
System.Security.Permissions.SecurityPermissionAttribute.SerializationFormatter