मैं विरासत सुरक्षा नियमों का उल्लंघन किए बिना .NET 4+ में ISerializable कैसे लागू कर सकता हूं?


109

बैकग्राउंडर: नोदा टाइम में कई धारावाहिक संरचनाएँ होती हैं। जब मैं बाइनरी सीरियलाइजेशन को नापसंद करता हूं, तो हमें इसे समर्थन देने के लिए कई अनुरोध प्राप्त हुए, 1.x समय में वापस। हम ISerializableइंटरफ़ेस को लागू करके इसका समर्थन करते हैं ।

हमें .NET फिडल के भीतर Noda Time 2.x में विफल रहने की हालिया समस्या रिपोर्ट मिली है । Noda Time 1.x का उपयोग करने वाला समान कोड ठीक काम करता है। इस अपवाद को फेंक दिया गया है:

सदस्य को ओवरराइड करते समय इनहेरिटेंस सुरक्षा नियमों का उल्लंघन हुआ: 'NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'। ओवरराइडिंग मेथड की सिक्योरिटी एक्सेसिबिलिटी ओवरराइड होने के तरीके की सिक्योरिटी एक्सेसिबिलिटी से मेल खाना चाहिए।

मैंने इसे उस फ़्रेमवर्क तक सीमित कर दिया है जो लक्षित है: 1.x लक्ष्य .NET 3.5 (क्लाइंट प्रोफ़ाइल); 2.x लक्ष्य .NET 4.5। वे PCL बनाम .NET कोर और प्रोजेक्ट फ़ाइल संरचना के समर्थन में बड़े अंतर हैं, लेकिन ऐसा लगता है कि यह अप्रासंगिक है।

मैं इसे एक स्थानीय परियोजना में पुन: पेश करने में कामयाब रहा हूं, लेकिन मुझे इसका कोई हल नहीं मिला है।

VS2017 में प्रजनन के लिए कदम:

  • एक नया समाधान बनाएँ
  • एक नया क्लासिक विंडोज कंसोल एप्लिकेशन बनाएं जिसका लक्ष्य .NET 4.5.1 है। मैंने इसे "कोडरनर" कहा।
  • परियोजना गुणों में, साइनिंग पर जाएं और एक नई कुंजी के साथ विधानसभा पर हस्ताक्षर करें। पासवर्ड की आवश्यकता को अनटिक करें, और किसी भी कुंजी फ़ाइल नाम का उपयोग करें।
  • प्रतिस्थापित करने के लिए निम्न कोड चिपकाएँ Program.cs। यह इस Microsoft नमूने में कोड का संक्षिप्त संस्करण है । मैंने सभी रास्तों को एक समान रखा है, इसलिए यदि आप फुलर कोड पर वापस जाना चाहते हैं, तो आपको कुछ और बदलने की आवश्यकता नहीं है।

कोड:

using System;
using System.Security;
using System.Security.Permissions;

class Sandboxer : MarshalByRefObject  
{  
    static void Main()  
    {  
        var adSetup = new AppDomainSetup();  
        adSetup.ApplicationBase = System.IO.Path.GetFullPath(@"..\..\..\UntrustedCode\bin\Debug");  
        var permSet = new PermissionSet(PermissionState.None);  
        permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));  
        var fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<System.Security.Policy.StrongName>();  
        var newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
        var handle = Activator.CreateInstanceFrom(  
            newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,  
            typeof(Sandboxer).FullName  
            );  
        Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
        newDomainInstance.ExecuteUntrustedCode("UntrustedCode", "UntrustedCode.UntrustedClass", "IsFibonacci", new object[] { 45 });  
    }  

    public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)  
    {  
        var target = System.Reflection.Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);
        target.Invoke(null, parameters);
    }  
}
  • "अनट्रस्टेडकोड" नामक एक और प्रोजेक्ट बनाएं। यह एक क्लासिक डेस्कटॉप क्लास लाइब्रेरी प्रोजेक्ट होना चाहिए।
  • विधानसभा पर हस्ताक्षर; आप कोडरनर के लिए एक नई कुंजी या उसी का उपयोग कर सकते हैं। (यह आंशिक रूप से नोदा समय की स्थिति की नकल करने के लिए है, और आंशिक रूप से कोड विश्लेषण को खुश रखने के लिए है।)
  • निम्नलिखित कोड पेस्ट करें Class1.cs(ओवरराइटिंग क्या है):

कोड:

using System;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;

// [assembly: AllowPartiallyTrustedCallers]

namespace UntrustedCode
{
    public class UntrustedClass
    {
        // Method named oddly (given the content) in order to allow MSDN
        // sample to run unchanged.
        public static bool IsFibonacci(int number)
        {
            Console.WriteLine(new CustomStruct());
            return true;
        }
    }

    [Serializable]
    public struct CustomStruct : ISerializable
    {
        private CustomStruct(SerializationInfo info, StreamingContext context) { }

        //[SecuritySafeCritical]
        //[SecurityCritical]
        //[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new NotImplementedException();
        }
    }
}

कोडरनर प्रोजेक्ट चलाना निम्नलिखित अपवाद देता है (पठनीयता के लिए सुधारित):

अखंडित अपवाद: System.Reflection.TargetInvocationException:
अपवाद को एक मंगलाचरण के लक्ष्य से फेंक दिया गया है।
--->
System.TypeLoadException:
सदस्य को ओवरराइड करते समय इनहेरिटेंस सुरक्षा नियमों का उल्लंघन किया गया:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData (...)।
ओवरराइडिंग मेथड की सिक्योरिटी
एक्सेसिबिलिटी ओवरराइड होने के तरीके की सिक्योरिटी एक्सेसिबिलिटी से मेल खाना चाहिए ।

टिप्पणी की गई विशेषताएँ उन चीज़ों को दिखाती हैं जिन्हें मैंने आज़माया है:

  • SecurityPermissionदो अलग-अलग एमएस लेखों ( पहले , दूसरे ) द्वारा अनुशंसित है , हालांकि दिलचस्प रूप से वे स्पष्ट / अंतर्निहित इंटरफ़ेस कार्यान्वयन के आसपास अलग-अलग चीजें करते हैं
  • SecurityCriticalवर्तमान में नोदा टाइम क्या है, और इस प्रश्न का उत्तर क्या है
  • SecuritySafeCritical कुछ हद तक कोड विश्लेषण नियम संदेशों द्वारा सुझाया गया है
  • किसी भी विशेषता के बिना , कोड विश्लेषण नियम खुश हैं - SecurityPermissionया तो या SecurityCritical वर्तमान के साथ, नियम आपको विशेषताओं को हटाने के लिए कहते हैं - जब तक आपके पास नहीं है AllowPartiallyTrustedCallers। दोनों मामलों में सुझावों का पालन करने से कोई मदद नहीं मिलती है।
  • नोडा टाइम ने इसके लिए AllowPartiallyTrustedCallersआवेदन किया है; यहां उदाहरण लागू विशेषता के साथ या उसके बिना काम नहीं करता है।

एक अपवाद के बिना कोड रन अगर मैं जोड़ने [assembly: SecurityRules(SecurityRuleSet.Level1)]के लिए UntrustedCodeविधानसभा (और टिप्पणी हटाएं AllowPartiallyTrustedCallersविशेषता), लेकिन मुझे विश्वास है कि समस्या यह है कि अन्य कोड में बाधा सकता है के लिए एक गरीब समाधान है।

मैं पूरी तरह से खो जाने की बात मानता हूँ जब यह .NET के सुरक्षा पहलू पर आता है। तो मैं .NET 4.5 को लक्षित करने के लिए क्या कर सकता हूं और फिर भी अपने प्रकारों को कार्यान्वित करने की अनुमति देता हूं ISerializableऔर अभी भी .NET Fiddle जैसे वातावरण में उपयोग किया जा सकता है?

(जब मैं .NET 4.5 को लक्षित कर रहा हूं, मेरा मानना ​​है कि यह .NET 4.0 सुरक्षा नीति में परिवर्तन है, जो इस समस्या का कारण है, इसलिए टैग।)


दिलचस्प रूप से पर्याप्त है, 4.0 में सुरक्षा मॉडल में परिवर्तन की यह व्याख्या बताती है कि बस हटाने AllowPartiallyTrustedCallersसे चाल चलनी चाहिए, लेकिन इससे कोई फर्क नहीं पड़ता
Mathias R. Jessen

जवाबों:


56

MSDN के अनुसार , .NET 4.0 में मूल रूप से आपको ISerializableआंशिक रूप से विश्वसनीय कोड के लिए उपयोग नहीं करना चाहिए , और इसके बजाय आपको ISafeSerificationizationata का उपयोग करना चाहिए

Https://docs.microsoft.com/en-us/dotnet/standard/serialization/custom-serialization से उद्धरण

जरूरी

.NET फ्रेमवर्क 4.0 के पिछले संस्करणों में, GetObjectData का उपयोग करके आंशिक रूप से विश्वसनीय विधानसभा में कस्टम उपयोगकर्ता डेटा का क्रमांकन पूरा किया गया था। संस्करण 4.0 से शुरू होकर, उस विधि को SecurityCriticalAttribute विशेषता के साथ चिह्नित किया गया है जो आंशिक रूप से विश्वसनीय असेंबलियों में निष्पादन को रोकता है। इस स्थिति के आसपास काम करने के लिए, ISafeSerializationData इंटरफ़ेस लागू करें।

तो शायद नहीं जो आप सुनना चाहते थे यदि आपको इसकी आवश्यकता है, लेकिन मुझे नहीं लगता कि इसका उपयोग करते समय इसके आसपास कोई रास्ता है ISerializable( Level1सुरक्षा में वापस जाने के अलावा , जो आपने कहा था कि आप नहीं चाहते हैं)।

पुनश्च: ISafeSerializationDataडॉक्स राज्य है कि यह सिर्फ अपवादों के लिए है, लेकिन यह सब विशिष्ट नहीं लगता है, आप इसे एक शॉट देना चाह सकते हैं ... मैं मूल रूप से इसे आपके नमूना कोड ( ISerializableकामों को हटाने के अलावा) के साथ परीक्षण नहीं कर सकता हूं । लेकिन आप पहले से ही जानते थे कि ... आपको यह देखना होगा कि क्या ISafeSerializationDataआपको पर्याप्त सूट करता है।

PS2: SecurityCriticalविशेषता काम नहीं करती है क्योंकि जब विधानसभा को आंशिक विश्वास मोड ( लेवल 2 सुरक्षा पर ) में लोड किया जाता है तो इसे अनदेखा कर दिया जाता है । आप इसे अपने नमूना कोड पर देख सकते हैं, अगर आप डिबग targetमें चर ExecuteUntrustedCodeयह लागू करने से पहले सही है, यह होगा IsSecurityTransparentकरने के लिए trueऔर IsSecurityCriticalकरने के लिए falseभले ही आप के साथ विधि निशान SecurityCriticalविशेषता)


अहा - स्पष्टीकरण के लिए धन्यवाद। शर्म करो अपवाद यहाँ बहुत भ्रामक है। क्या करना है बाहर काम करने की आवश्यकता होगी ...
जॉन स्कीट

@JonSkeet ईमानदारी से, मैं पूरी तरह से द्विआधारी क्रमांकन खाई हूँ ... लेकिन मैं समझता हूँ कि आपके userbase इसे पसंद नहीं कर सकते
Jcl

मुझे लगता है कि हमें वह करना होगा - जिसका अर्थ है v3.0 पर जाना। हालांकि इसके अन्य लाभ हैं ... मुझे नोदा समय समुदाय से परामर्श करने की आवश्यकता होगी।
जॉन स्कीट

12
@JonSkeet btw, यदि आप रुचि रखते हैं, तो यह लेख स्तर 1 और स्तर 2 सुरक्षा के बीच अंतर बताता है (और यह काम क्यों नहीं करता है)
Jcl

8

स्वीकृत उत्तर इतना आश्वस्त है कि मेरा मानना ​​है कि यह बग नहीं था। लेकिन अब कुछ प्रयोग करने के बाद मैं कह सकता हूं कि Level2 सुरक्षा पूरी तरह से गड़बड़ है; कम से कम, वास्तव में कुछ गड़बड़ है।

कुछ दिनों पहले मैं अपने पुस्तकालयों के साथ इसी मुद्दे पर टकराया था। मैंने जल्दी से एक इकाई परीक्षण बनाया; हालाँकि, मैं .NET फ़ेल्ड में अनुभव की गई समस्या को पुन: उत्पन्न नहीं कर सका, जबकि एक ही कोड "सफलतापूर्वक" ने एक कंसोल ऐप में अपवाद को फेंक दिया। अंत में मुझे इस मुद्दे पर काबू पाने के लिए दो अजीब तरीके मिले।

टीएल; डीआर : यह पता चलता है कि यदि आप अपने उपभोक्ता प्रोजेक्ट में आंतरिक प्रकार के उपयोग किए गए पुस्तकालय का उपयोग करते हैं, तो आंशिक रूप से विश्वसनीय कोड अपेक्षित रूप से काम करता है: यह ISerializableकार्यान्वयन को तत्काल करने में सक्षम है (और सुरक्षा महत्वपूर्ण कोड को सीधे नहीं कहा जा सकता है, लेकिन नीचे देखें)। या, जो और भी हास्यास्पद है, आप सैंडबॉक्स को फिर से बनाने की कोशिश कर सकते हैं यदि यह पहली बार काम नहीं किया ...

लेकिन कुछ कोड देखते हैं।

ClassLibrary.dll:

चलो दो मामलों को अलग करते हैं: एक सुरक्षा महत्वपूर्ण सामग्री के साथ एक नियमित वर्ग के लिए और एक ISerializable कार्यान्वयन के लिए:

public class CriticalClass
{
    public void SafeCode() { }

    [SecurityCritical]
    public void CriticalCode() { }

    [SecuritySafeCritical]
    public void SafeEntryForCriticalCode() => CriticalCode();
}

[Serializable]
public class SerializableCriticalClass : CriticalClass, ISerializable
{
    public SerializableCriticalClass() { }

    private SerializableCriticalClass(SerializationInfo info, StreamingContext context) { }

    [SecurityCritical]
    public void GetObjectData(SerializationInfo info, StreamingContext context) { }
}

समस्या को दूर करने का एक तरीका उपभोक्ता विधानसभा से आंतरिक प्रकार का उपयोग करना है। कोई भी प्रकार यह करेगा; अब मैं एक विशेषता परिभाषित करता हूं:

[AttributeUsage(AttributeTargets.All)]
internal class InternalTypeReferenceAttribute : Attribute
{
    public InternalTypeReferenceAttribute() { }
}

और संबंधित गुण विधानसभा पर लागू होते हैं:

[assembly: InternalsVisibleTo("UnitTest, PublicKey=<your public key>")]
[assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]

असेंबली पर हस्ताक्षर करें, कुंजी को InternalsVisibleToविशेषता पर लागू करें और परीक्षण परियोजना के लिए तैयार करें:

UnitTest.dll (NUnit और ClassLibrary का उपयोग करता है):

आंतरिक चाल का उपयोग करने के लिए परीक्षण विधानसभा पर भी हस्ताक्षर किए जाने चाहिए। विधानसभा विशेषताएं:

// Just to make the tests security transparent by default. This helps to test the full trust behavior.
[assembly: AllowPartiallyTrustedCallers] 

// !!! Comment this line out and the partial trust test cases may fail for the fist time !!!
[assembly: InternalTypeReference]

नोट : विशेषता कहीं भी लागू की जा सकती है। मेरे मामले में यह एक यादृच्छिक परीक्षण कक्षा में एक विधि पर था मुझे खोजने में कुछ दिन लगे।

नोट 2 : यदि आप सभी परीक्षण विधियों को एक साथ चलाते हैं तो ऐसा हो सकता है कि परीक्षण पास हो जाएंगे।

परीक्षण वर्ग का कंकाल:

[TestFixture]
public class SecurityCriticalAccessTest
{
    private partial class Sandbox : MarshalByRefObject
    {
    }

    private static AppDomain CreateSandboxDomain(params IPermission[] permissions)
    {
        var evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
        var permissionSet = GetPermissionSet(permissions);
        var setup = new AppDomainSetup
        {
            ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
        };

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var strongNames = new List<StrongName>();
        foreach (Assembly asm in assemblies)
        {
            AssemblyName asmName = asm.GetName();
            strongNames.Add(new StrongName(new StrongNamePublicKeyBlob(asmName.GetPublicKey()), asmName.Name, asmName.Version));
        }

        return AppDomain.CreateDomain("SandboxDomain", evidence, setup, permissionSet, strongNames.ToArray());
    }

    private static PermissionSet GetPermissionSet(IPermission[] permissions)
    {
        var evidence = new Evidence();
        evidence.AddHostEvidence(new Zone(SecurityZone.Internet));
        var result = SecurityManager.GetStandardSandbox(evidence);
        foreach (var permission in permissions)
            result.AddPermission(permission);
        return result;
    }
}

और आइए एक-एक करके परीक्षण मामलों को देखें

केस 1: ISerializable कार्यान्वयन

प्रश्न में जैसा मुद्दा है। परीक्षा पास हो जाती है

  • InternalTypeReferenceAttribute लागू है
  • सैंडबॉक्स को कई बार बनाने की कोशिश की जाती है (कोड देखें)
  • या, यदि सभी परीक्षण मामलों को एक ही बार में निष्पादित किया जाता है और यह पहला नहीं है

अन्यथा, Inheritance security rules violated while overriding member...जब आप तत्काल करते हैं तो पूरी तरह से अनुचित अपवाद आता है SerializableCriticalClass

[Test]
[SecuritySafeCritical] // for Activator.CreateInstance
public void SerializableCriticalClass_PartialTrustAccess()
{
    var domain = CreateSandboxDomain(
        new SecurityPermission(SecurityPermissionFlag.SerializationFormatter), // BinaryFormatter
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    var handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    var sandbox = (Sandbox)handle.Unwrap();
    try
    {
        sandbox.TestSerializableCriticalClass();
        return;
    }
    catch (Exception e)
    {
        // without [InternalTypeReference] it may fail for the first time
        Console.WriteLine($"1st try failed: {e.Message}");
    }

    domain = CreateSandboxDomain(
        new SecurityPermission(SecurityPermissionFlag.SerializationFormatter), // BinaryFormatter
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    sandbox = (Sandbox)handle.Unwrap();
    sandbox.TestSerializableCriticalClass();

    Assert.Inconclusive("Meh... succeeded only for the 2nd try");
}

private partial class Sandbox
{
    public void TestSerializableCriticalClass()
    {
        Assert.IsFalse(AppDomain.CurrentDomain.IsFullyTrusted);

        // ISerializable implementer can be created.
        // !!! May fail for the first try if the test does not use any internal type of the library. !!!
        var critical = new SerializableCriticalClass();

        // Critical method can be called via a safe method
        critical.SafeEntryForCriticalCode();

        // Critical method cannot be called directly by a transparent method
        Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
        Assert.Throws<MethodAccessException>(() => critical.GetObjectData(null, new StreamingContext()));

        // BinaryFormatter calls the critical method via a safe route (SerializationFormatter permission is required, though)
        new BinaryFormatter().Serialize(new MemoryStream(), critical);
    }

}

केस 2: सुरक्षा महत्वपूर्ण सदस्यों के साथ नियमित कक्षा

परीक्षण पहले वाले के समान शर्तों से गुजरता है। हालाँकि, समस्या पूरी तरह से यहाँ है: आंशिक रूप से विश्वसनीय कोड सीधे सुरक्षा महत्वपूर्ण सदस्य तक पहुँच सकता है

[Test]
[SecuritySafeCritical] // for Activator.CreateInstance
public void CriticalClass_PartialTrustAccess()
{
    var domain = CreateSandboxDomain(
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess), // Assert.IsFalse
        new EnvironmentPermission(PermissionState.Unrestricted)); // Assert.Throws (if fails)
    var handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    var sandbox = (Sandbox)handle.Unwrap();
    try
    {
        sandbox.TestCriticalClass();
        return;
    }
    catch (Exception e)
    {
        // without [InternalTypeReference] it may fail for the first time
        Console.WriteLine($"1st try failed: {e.Message}");
    }

    domain = CreateSandboxDomain(
        new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)); // Assert.IsFalse
    handle = Activator.CreateInstance(domain, Assembly.GetExecutingAssembly().FullName, typeof(Sandbox).FullName);
    sandbox = (Sandbox)handle.Unwrap();
    sandbox.TestCriticalClass();

    Assert.Inconclusive("Meh... succeeded only for the 2nd try");
}

private partial class Sandbox
{
    public void TestCriticalClass()
    {
        Assert.IsFalse(AppDomain.CurrentDomain.IsFullyTrusted);

        // A type containing critical methods can be created
        var critical = new CriticalClass();

        // Critical method can be called via a safe method
        critical.SafeEntryForCriticalCode();

        // Critical method cannot be called directly by a transparent method
        // !!! May fail for the first time if the test does not use any internal type of the library. !!!
        // !!! Meaning, a partially trusted code has more right than a fully trusted one and is       !!!
        // !!! able to call security critical method directly.                                        !!!
        Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
    }
}

केस 3-4: केस 1-2 का पूर्ण विश्वास संस्करण

पूर्णता की खातिर यहां वही मामले हैं जो पूरी तरह से विश्वसनीय डोमेन में निष्पादित किए गए हैं। यदि आप [assembly: AllowPartiallyTrustedCallers]परीक्षणों को विफल करते हैं क्योंकि तब आप महत्वपूर्ण कोड को सीधे एक्सेस कर सकते हैं (क्योंकि विधियां डिफ़ॉल्ट रूप से पारदर्शी नहीं हैं)।

[Test]
public void CriticalClass_FullTrustAccess()
{
    Assert.IsTrue(AppDomain.CurrentDomain.IsFullyTrusted);

    // A type containing critical methods can be created
    var critical = new CriticalClass();

    // Critical method cannot be called directly by a transparent method
    Assert.Throws<MethodAccessException>(() => critical.CriticalCode());

    // Critical method can be called via a safe method
    critical.SafeEntryForCriticalCode();
}

[Test]
public void SerializableCriticalClass_FullTrustAccess()
{
    Assert.IsTrue(AppDomain.CurrentDomain.IsFullyTrusted);

    // ISerializable implementer can be created
    var critical = new SerializableCriticalClass();

    // Critical method cannot be called directly by a transparent method (see also AllowPartiallyTrustedCallersAttribute)
    Assert.Throws<MethodAccessException>(() => critical.CriticalCode());
    Assert.Throws<MethodAccessException>(() => critical.GetObjectData(null, default(StreamingContext)));

    // Critical method can be called via a safe method
    critical.SafeEntryForCriticalCode();

    // BinaryFormatter calls the critical method via a safe route
    new BinaryFormatter().Serialize(new MemoryStream(), critical);
}

उपसंहार:

बेशक, यह आपकी समस्या को .NET फिडल के साथ हल नहीं करेगा। लेकिन अब मुझे बहुत आश्चर्य होगा अगर यह फ्रेम में बग नहीं था।

मेरे लिए अब सबसे बड़ा प्रश्न स्वीकृत उत्तर में उद्धृत भाग है। वे इस बकवास के साथ कैसे निकले? ISafeSerializationDataस्पष्ट रूप से कुछ भी के लिए एक समाधान नहीं है: यह विशेष रूप से आधार द्वारा किया जाता है Exceptionवर्ग और अगर आप सदस्यता SerializeObjectStateघटना (क्यों नहीं है कि एक overridable विधि है?), फिर राज्य भी द्वारा भस्म हो जाएगाException.GetObjectData अंत में।

AllowPartiallyTrustedCallers/ SecurityCritical/ SecuritySafeCriticalविशेषताओं की तिकड़ी वास्तव में उपयोग ऊपर दिखाए गए के लिए डिजाइन किए गए थे। यह मेरे लिए पूरी तरह से बकवास लगता है कि आंशिक रूप से विश्वसनीय कोड भी अपने सुरक्षा महत्वपूर्ण सदस्यों का उपयोग करने के प्रयास की परवाह किए बिना एक प्रकार का संकेत नहीं दे सकता है। लेकिन यह और भी बड़ा बकवास है ( सुरक्षा छेद वास्तव में) जो कि आंशिक रूप से भरोसेमंद कोड सीधे सुरक्षा महत्वपूर्ण विधि तक पहुंच सकता है ( केस 2 देखें ) जबकि यह पूरी तरह से विश्वसनीय डोमेन से भी पारदर्शी तरीकों के लिए मना किया गया है।

इसलिए यदि आपकी उपभोक्ता परियोजना एक परीक्षण या अन्य प्रसिद्ध विधानसभा है, तो आंतरिक चाल का पूरी तरह से उपयोग किया जा सकता है। .NET फ़ेल्ड और अन्य वास्तविक जीवन के सैंडबॉक्स वाले वातावरण के लिए एकमात्र समाधान SecurityRuleSet.Level1Microsoft द्वारा तय किए जाने तक वापस लौट रहा है ।


अद्यतन: मुद्दे के लिए एक डेवलपर समुदाय टिकट बनाया गया है।


2

MSDN के अनुसार देखें:

उल्लंघन कैसे ठीक करें?

इस नियम के उल्लंघन को ठीक करने के लिए, GetObjectData विधि को दृश्यमान और अधिक उपयोग योग्य बनाएं और सुनिश्चित करें कि सभी उदाहरण फ़ील्ड क्रमांकन प्रक्रिया में शामिल हैं या स्पष्ट रूप से NonSerializedAttribute के साथ चिह्नित हैं विशेषता ।

निम्न उदाहरण पुस्तक वर्ग पर ISerializable.GetObjectData का एक अतिव्यापी कार्यान्वयन प्रदान करके और पुस्तकालय वर्ग पर ISerializable.GetObjectData का कार्यान्वयन प्रदान करके पिछले दो उल्लंघनों को ठीक करता है।

using System;
using System.Security.Permissions;
using System.Runtime.Serialization;

namespace Samples2
{
    [Serializable]
    public class Book : ISerializable
    {
        private readonly string _Title;

        public Book(string title)
        {
            if (title == null)
                throw new ArgumentNullException("title");

            _Title = title;
        }

        protected Book(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            _Title = info.GetString("Title");
        }

        public string Title
        {
            get { return _Title; }
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Title", _Title);
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new ArgumentNullException("info");

            GetObjectData(info, context);
        }
    }

    [Serializable]
    public class LibraryBook : Book
    {
        private readonly DateTime _CheckedOut;

        public LibraryBook(string title, DateTime checkedOut)
            : base(title)
        {
            _CheckedOut = checkedOut;
        }

        protected LibraryBook(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            _CheckedOut = info.GetDateTime("CheckedOut");
        }

        public DateTime CheckedOut
        {
            get { return _CheckedOut; }
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        protected override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);

            info.AddValue("CheckedOut", _CheckedOut);
        }
    }
}

2
आपके द्वारा जोड़ा गया लेख CA2240 के लिए है, जिसे निकाल नहीं दिया गया है - कोड इसका उल्लंघन नहीं करता है। यह एक संरचना है, इसलिए यह प्रभावी रूप से सील है; इसका कोई क्षेत्र नहीं है; यह GetObjectDataस्पष्ट रूप से लागू होता है , लेकिन ऐसा करने से कोई फायदा नहीं होता है।
जॉन स्कीट

15
ज़रूर, और कोशिश करने के लिए धन्यवाद - लेकिन मैं समझा रहा हूँ कि यह काम क्यों नहीं करता है। (और एक सिफारिश के रूप में - इस तरह से कुछ मुश्किल के लिए, जहां प्रश्न में एक सत्यापन योग्य उदाहरण शामिल है, यह सुझाव दिया गया फिक्स को लागू करने की कोशिश करना और यह देखना है कि क्या यह वास्तव में मदद करता है , यह एक अच्छा विचार है ।)
जॉन स्कीट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.