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. ISerializable
Arayü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:
SecurityPermission
iki farklı MS makalesi tarafından önerilmektedir ( birinci , ikinci ), ancak ilginç bir şekilde açık / örtük arayüz uygulaması etrafında farklı şeyler yaparlarSecurityCritical
Noda Time'ın şu anda sahip olduğu ve bu sorunun cevabının önerdiğiSecuritySafeCritical
Kod Analizi kural mesajları tarafından bir şekilde önerilmektedir- Olmadan herhangi nitelikler, Kod Analizi kuralları mutluyuz - biriyle
SecurityPermission
veyaSecurityCritical
mevcut 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
AllowPartiallyTrustedCallers
ona uyguladı; buradaki örnek, öznitelik uygulanmış veya uygulanmamış olarak çalışmaz.
Bir istisnasız kod çalışır ben eklerseniz [assembly: SecurityRules(SecurityRuleSet.Level1)]
için UntrustedCode
montaj (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 ISerializable
ve 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.)
AllowPartiallyTrustedCallers
hile yapması gerektiğini öne sürüyor , ancak bu bir fark yaratmıyor