Arka plan: Noda Time birçok serileştirilebilir yapı içerir. İkili serileştirmeyi sevmesem de, 1.x zaman çizelgesinde onu desteklemek için birçok istek aldık. ISerializableArayüzü uygulayarak bunu destekliyoruz .
Noda Time 2.x'in .NET Fiddle'da başarısız olduğuna dair yeni bir sorun raporu aldık . Noda Time 1.x kullanan aynı kod iyi çalışıyor. Atılan istisna şudur:
Üyeyi geçersiz kılarken devralma güvenlik kuralları ihlal edildi: 'NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. Geçersiz kılma yönteminin güvenlik erişilebilirliği, geçersiz kılınan yöntemin güvenlik erişilebilirliğiyle eşleşmelidir.
Bunu hedeflenen çerçeveye daralttım: 1.x .NET 3.5'i (istemci profili) hedefliyor; 2.x, .NET 4.5'i hedefler. Destek PCL ile .NET Core ve proje dosya yapısı açısından büyük farklılıkları var, ancak bu alakasız görünüyor.
Bunu yerel bir projede yeniden üretmeyi başardım, ancak buna bir çözüm bulamadım.
VS2017'de yeniden oluşturma adımları:
- Yeni bir çözüm oluşturun
- .NET 4.5.1'i hedefleyen yeni bir klasik Windows konsol uygulaması oluşturun. Ben buna "CodeRunner" adını verdim.
- Proje özelliklerinde, İmzalama'ya gidin ve montajı yeni bir anahtarla imzalayın. Parola gereksiniminin işaretini kaldırın ve herhangi bir anahtar dosyası adı kullanın.
- Değiştirmek için aşağıdaki kodu yapıştırın
Program.cs. Bu, bu Microsoft örneğindeki kodun kısaltılmış bir sürümüdür . Tüm yolları aynı tuttum, bu yüzden daha tam koda geri dönmek isterseniz, başka hiçbir şeyi değiştirmenize gerek kalmaz.
Kod:
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);
}
}
- "UntrustedCode" adlı başka bir proje oluşturun. Bu bir Klasik Masaüstü Sınıf Kitaplığı projesi olmalıdır.
- Montajı imzalayın; yeni bir anahtar veya CodeRunner ile aynı olanı kullanabilirsiniz. (Bu kısmen Noda Saati durumunu taklit etmek ve kısmen Kod Analizini mutlu etmek içindir.)
- Aşağıdaki kodu içine yapıştırın
Class1.cs(orada olanın üzerine yazın):
Kod:
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();
}
}
}
CodeRunner projesini çalıştırmak aşağıdaki istisnayı verir (okunabilirlik için yeniden biçimlendirilmiş):
İşlenmemiş Özel Durum: System.Reflection.TargetInvocationException:
Bir çağrının hedefi tarafından özel durum oluşturuldu.
--->
System.TypeLoadException:
Üye geçersiz kılarken devralma güvenlik kuralları ihlal edildi:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData (...).
Geçersiz kılma yönteminin güvenlik
erişilebilirliği , geçersiz kılınan yöntemin güvenlik erişilebilirliğiyle eşleşmelidir .
Yorumlanmış öznitelikler denediğim şeyleri gösterir:
SecurityPermissioniki farklı MS makalesi tarafından önerilmektedir ( birinci , ikinci ), ancak ilginç bir şekilde açık / örtük arayüz uygulaması etrafında farklı şeyler yaparlarSecurityCriticalNoda Time'ın şu anda sahip olduğu ve bu sorunun cevabının önerdiğiSecuritySafeCriticalKod Analizi kural mesajları tarafından bir şekilde önerilmektedir- Olmadan herhangi nitelikler, Kod Analizi kuralları mutluyuz - biriyle
SecurityPermissionveyaSecurityCriticalmevcut kurallar özelliklerini kaldırmak için size - Eğer sürece yapmak zorundaAllowPartiallyTrustedCallers. Her iki durumda da önerileri takip etmek yardımcı olmaz. - Noda Time
AllowPartiallyTrustedCallersona uyguladı; buradaki örnek, öznitelik uygulanmış veya uygulanmamış olarak çalışmaz.
Bir istisnasız kod çalışır ben eklerseniz [assembly: SecurityRules(SecurityRuleSet.Level1)]için UntrustedCodemontaj (ve yorumsuz AllowPartiallyTrustedCallersözniteliği), ama bu başka bir kod engel olacağı sorununa fakir çözüm olduğuna inanıyoruz.
.NET'in bu tür bir güvenlik yönü söz konusu olduğunda oldukça kaybolduğumu tamamen itiraf ediyorum. Öyleyse , .NET 4.5'i hedeflemek ISerializableve yine de türlerimin .NET Fiddle gibi ortamlarda uygulanmasına ve kullanılmasına izin vermek için ne yapabilirim ?
(.NET 4.5'i hedeflerken, soruna neden olanın .NET 4.0 güvenlik politikası değişikliklerinin, dolayısıyla etiketinin olduğunu düşünüyorum.)
AllowPartiallyTrustedCallershile yapması gerektiğini öne sürüyor , ancak bu bir fark yaratmıyor