Передумови: Noda Time містить безліч серійних структур. Хоча я не люблю бінарну серіалізацію, ми отримали багато запитів про її підтримку, ще на часовій шкалі 1.x. Ми підтримуємо його, реалізуючи ISerializable
інтерфейс.
Ми отримали нещодавній звіт про вихід з ладу Noda Time 2.x у .NET Fiddle . Той самий код, що використовує 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 Core та структури файлів проекту, але, схоже, це не має значення.
Мені вдалося відтворити це в локальному проекті, але я не знайшов рішення для нього.
Кроки до відтворення в VS2017:
- Створіть нове рішення
- Створіть нову класичну програму націлювання на консоль Windows. NET 4.5.1. Я назвав це "CodeRunner".
- У властивостях проекту перейдіть до Підписання та підпишіть збірку новим ключем. Скасуйте вимогу пароля та використовуйте будь-яке ключове ім’я файлу.
- Вставте наступний код для заміни
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);
}
}
- Створіть ще один проект під назвою "UntrustedCode". Це повинен бути проект бібліотеки Classic Desktop Class.
- Підпишіть збори; ви можете використовувати новий ключ або той самий, що і для CodeRunner. (Це частково імітує ситуацію в Noda Time, а частково - для того, щоб підтримувати аналіз коду.)
- Вставте наступний код у
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();
}
}
}
Запуск проекту CodeRunner дає наступний виняток (переформатований для читабельності):
Неопрацьоване виняток: System.Reflection.TargetInvocationException:
Виняток було кинуто ціллю виклику.
--->
System.TypeLoadException:
правила безпеки успадкування порушені під час переходу над основним членом:
'UntrustedCode.CustomStruct.System.Runtime.Serialization.ISerializable.GetObjectData (...).
Доступність безпеки методу, що перекриває, повинна відповідати безпеці
доступності методу, що перекривається.
Коментовані атрибути показують те, що я спробував:
SecurityPermission
рекомендується двома різними статтями MS ( перша , друга ), хоча цікаво, що вони роблять різні речі навколо явної / неявної реалізації інтерфейсуSecurityCritical
є те , що в даний час має Нод час, і то , що відповідь на це питання в пропонуєSecuritySafeCritical
дещо пропонується повідомленнями правил аналізу коду- Без будь - яких атрибутів, правила аналізу коду щасливі - або
SecurityPermission
чиSecurityCritical
немає, правила сказати вам , щоб видалити атрибути - якщо ви не зробите єAllowPartiallyTrustedCallers
. Виконання пропозицій в будь-якому випадку не допомагає. - До нього
AllowPartiallyTrustedCallers
застосував Noda Time ; приклад тут не працює ні з застосованим атрибутом, ні без нього.
Код працює без винятку, якщо я додаю [assembly: SecurityRules(SecurityRuleSet.Level1)]
до UntrustedCode
збірки (і відменюю AllowPartiallyTrustedCallers
атрибут), але я вважаю, що це погане рішення проблеми, яка може перешкоджати іншому коду.
Я повністю визнаю, що сильно розгубився, коли мова заходить про подібний аспект безпеки .NET. Так що можна зробити , щоб забезпечити роботу з .NET 4.5 і все ж дозволяють мої типи реалізувати ISerializable
і по- , як і раніше використовуватися в середовищах , таких як .NET Fiddle?
(Хоча я націлююсь на .NET 4.5, я вважаю, що зміни в політиці безпеки .NET 4.0 викликали проблему, звідси і тег.)
AllowPartiallyTrustedCallers
повинно зробити трюк, але це, схоже, не має значення