We recommend using Visual Studio 2017

Proteggere gli override di GetObjectData

TypeName

SecureGetObjectDataOverrides

CheckId

CA2110

Category

Microsoft.Security

Breaking Change

Breaking

Un metodo è denominato GetObjectData, è dichiarato in un tipo che implementa l'interfaccia System.Runtime.Serialization.ISerializable e accetta un oggetto System.Runtime.Serialization.SerializationInfo e un oggetto System.Runtime.Serialization.StreamingContext come parametri. Il metodo non è protetto da una richiesta per l'autorizzazione di protezione System.Security.Permissions.SecurityPermissionAttribute.SerializationFormatter.

Il metodo System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) è dichiarato nell'interfaccia ISerializable. Questa interfaccia è implementata da tipi che forniscono logica di serializzazione personalizzata. GetObjectData è protetto da un controllo di protezione per l'autorizzazione di protezione System.Security.Permissions.SecurityPermissionAttribute.SerializationFormatter. Se un'implementazione di GetObjectData non è protetta dallo stesso controllo di protezione, i chiamanti possono chiamare l'implementazione per ignorare la protezione sull'interfaccia e ottenere accesso ai dati serializzati dal tipo.

Per correggere una violazione di questa regola, applicare il seguente attributo al metodo GetObjectData:

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

Non escludere un avviso da questa regola.

Nel codice riportato di seguito viene illustrata una libreria che viola la regola e un'applicazione che sfrutta i punti deboli della libreria.

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);
      }
   }
}

Il codice riportato di seguito sfrutta i punti deboli della libreria.

using System;
using System.Security;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using SecurityRulesLibrary;
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);
         }
                        
      }
   }
}

Questo esempio produce l'output che segue.

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.
Mostra: