Latar Belakang: Waktu Noda berisi banyak struct yang dapat bersambung. Meskipun saya tidak suka serialisasi biner, kami menerima banyak permintaan untuk mendukungnya, kembali ke timeline 1.x. Kami mendukungnya dengan mengimplementasikan ISerializable
antarmuka.
Kami telah menerima laporan masalah baru-baru ini tentang Noda Time 2.x yang gagal dalam .NET Fiddle . Kode yang sama menggunakan Noda Time 1.x berfungsi dengan baik. Pengecualian yang diberikan adalah ini:
Aturan keamanan pewarisan dilanggar saat menimpa anggota: 'NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. Aksesibilitas keamanan dari metode penggantian harus sesuai dengan aksesibilitas keamanan dari metode yang akan diganti.
Saya telah mempersempit ini ke kerangka kerja yang ditargetkan: 1.x target. NET 3.5 (profil klien); 2.x menargetkan .NET 4.5. Mereka memiliki perbedaan besar dalam hal dukungan PCL vs .NET Core dan struktur file proyek, tetapi sepertinya ini tidak relevan.
Saya telah berhasil mereproduksi ini dalam proyek lokal, tetapi saya belum menemukan solusi untuk itu.
Langkah-langkah untuk mereproduksi di VS2017:
- Buat solusi baru
- Buat aplikasi konsol Windows klasik baru yang menargetkan .NET 4.5.1. Saya menyebutnya "CodeRunner".
- Di properti proyek, buka Menandatangani dan menandatangani rakitan dengan kunci baru. Hapus centang persyaratan kata sandi, dan gunakan nama file kunci apa saja.
- Tempel kode berikut untuk mengganti
Program.cs
. Ini adalah versi kode yang disingkat dalam contoh Microsoft ini . Saya telah menyimpan semua jalur yang sama, jadi jika Anda ingin kembali ke kode yang lebih lengkap, Anda tidak perlu mengubah apa pun.
Kode:
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);
}
}
- Buat proyek lain yang disebut "UntrustedCode". Ini harus menjadi proyek Perpustakaan Kelas Desktop Klasik.
- Tanda tangani majelis; Anda dapat menggunakan kunci baru atau yang sama seperti untuk CodeRunner. (Ini sebagian untuk meniru situasi Waktu Noda, dan sebagian lagi untuk membuat Analisis Kode senang.)
- Tempel kode berikut
Class1.cs
(menimpa apa yang ada di sana):
Kode:
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();
}
}
}
Menjalankan proyek CodeRunner memberikan pengecualian berikut (diformat ulang agar mudah dibaca):
Unhandled Exception: System.Reflection.TargetInvocationException:
Exception telah dilemparkan oleh target pemanggilan.
--->
System.TypeLoadException:
Aturan keamanan warisan dilanggar saat mengganti anggota:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData (...).
Aksesibilitas keamanan
dari metode penggantian harus sesuai dengan aksesibilitas keamanan dari metode yang akan diganti.
Atribut yang diberi komentar menunjukkan hal-hal yang telah saya coba:
SecurityPermission
direkomendasikan oleh dua artikel MS yang berbeda ( pertama , kedua ), meskipun menariknya mereka melakukan hal yang berbeda seputar implementasi antarmuka eksplisit / implisitSecurityCritical
adalah apa yang saat ini Noda Waktu memiliki, dan apa jawaban ini pertanyaan ini menunjukkanSecuritySafeCritical
agak disarankan oleh pesan aturan Analisis Kode- Tanpa setiap atribut, aturan Analisis Kode senang - dengan baik
SecurityPermission
atauSecurityCritical
ini, aturan memberitahu Anda untuk menghapus atribut - kecuali Anda lakukan memilikiAllowPartiallyTrustedCallers
. Mengikuti saran dalam kedua kasus tidak membantu. - Waktu Noda telah
AllowPartiallyTrustedCallers
diterapkan padanya; contoh di sini tidak berfungsi baik dengan atau tanpa atribut diterapkan.
Kode berjalan tanpa pengecualian jika saya menambahkan [assembly: SecurityRules(SecurityRuleSet.Level1)]
ke UntrustedCode
assembly (dan menghapus komentar AllowPartiallyTrustedCallers
atribut), tetapi saya yakin itu adalah solusi yang buruk untuk masalah yang dapat menghambat kode lain.
Saya sepenuhnya mengaku sangat tersesat dalam hal aspek keamanan .NET semacam ini. Jadi apa yang dapat saya lakukan untuk menargetkan .NET 4.5 namun mengizinkan tipe saya untuk diimplementasikan ISerializable
dan masih digunakan di lingkungan seperti .NET Fiddle?
(Sementara saya menargetkan .NET 4.5, saya yakin itu adalah perubahan kebijakan keamanan .NET 4.0 yang menyebabkan masalah, oleh karena itu tagnya.)
AllowPartiallyTrustedCallers
, tetapi tampaknya tidak ada bedanya