Подтвердить что ты не робот

Безопасные сборки С# от неавторизованных абонентов

Есть ли способ защитить вашу сборку до уровня класса/свойства и класса/метода, чтобы предотвратить использование/вызов из другой сборки, которая не подписана нашей компанией?

Я хотел бы сделать это без каких-либо требований к сильному наименованию (например, используя StrongNameIdentityPermission) и придерживаться того, как подписывается сборка. Я действительно не хочу прибегать к использованию атрибута InternalsVisibleTo, поскольку он не поддерживается в постоянно меняющейся экосистеме программного обеспечения.

Например:

Сценарий 1

Foo.dll подписана моей компанией, а Bar.dll не подписано.

Foo имеет класс A Бар имеет класс B

Класс A имеет открытый метод GetSomething() Класс B пытается вызвать Foo.A.GetSomething() и отклоняется

Отклонено может быть исключением или быть проигнорировано каким-то образом

Сценарий 2

Foo.dll подписана моей компанией, а Moo.dll также подписана моей компанией.

Foo имеет класс A Moo имеет класс C

Класс A имеет открытый метод GetSomething() Класс C пытается вызвать Foo.A.GetSomething() и не отклоняется

4b9b3361

Ответ 1

Если вы хотите ограничить вызывающих абонентов только кодом, который был аутентифицирован определенным сертификатом, вы все равно можете использовать CAS (просто не StrongNameIdentityPermission).

Используйте PublisherIdentityPermission так же, как вы использовали бы разрешения CAS. Или, если вы хотите сделать это декларативно, использовать атрибут.

Ответ 2

Очевидно, что вам нужно выполнить проверку на каждый вызов из вызываемого метода - любая внешняя система, пытающаяся обеспечить соблюдение ограничений, легко обойти с помощью отражения.

В рамках метода вы можете использовать

new StackTrace().GetFrame(1).GetMethod().Module.Assembly

чтобы получить вызывающую сборку. Теперь вы можете использовать

callingAssembly.GetName().GetPublicKey()

чтобы получить открытый ключ вызывающей сборки и сравнить его с открытым ключом вызываемой сборки. Если они совпадают - если все ваши сборки подписаны с одной и той же парой ключей - вызывающий абонент принимается как узаконивший вызывающий.

Но есть одно сквозное отверстие - сборка третьей стороны может задерживаться под подпиской с вашим открытым ключом компаний и исключаться из проверки цифровой подписи. Вследствие этого загрузчик будет загружать стороннюю сборку с сильным именем и открытым ключом ваших компаний, даже если он еще не подписан. Чтобы закрыть это отверстие петли, вы должны проверить подпись. Нет управляемого API, и вы должны P/Invoke

Boolean StrongNameSignatureVerificationEx(
   String wszFilePath,
   Boolean fForceVerification,
   ref Boolean  pfWasVerified)

с fForceVerification установлен в true и проверьте, соответствует ли результат true.

Во всех случаях это может быть довольно много накладных расходов. Возможно, искушение заключается в том, чтобы кэшировать результат, но при условии, что вызывающий объект с разрешением отражения, вероятно, не так сложно манипулировать таким кешем. С другой стороны, вы никогда не будете на 100% уверены. Кто когда-либо контролирует систему, имеет право делать (почти) все, что он хочет - приложить отладчик, изменить содержимое памяти, манипулировать библиотеками или всей средой выполнения. Наконец, вы также должны эффективно защитить свою сборку от декомпиляции и модификации.

Ответ 3

Я видел DLL, написанную компаниями (в первую очередь Pegasus Imaging), которые используют систему вызова/ответа, чтобы разблокировать сборку. Покупателю DLL предоставляется "Лицензионный код", привязанный к имени покупателя, который затем использует пользователь DLL для разблокировки определенного подмножества функций DLL.

Итак, когда сборка впервые используется приложением, в сборке вызывается метод Unlock(). Имя пользователя и код разблокировки передаются и запускаются через алгоритм, который проверяет идентификатор, предположительно используя алгоритм шифрования открытого ключа.

В коде разблокировки есть некоторые биты, которые указывают функции; эти биты затем устанавливают некоторые флаги функций в сборке. Все вызывающие функции должны проверять эти флаги, чтобы определить, включена ли соответствующая функция. Метод Unlock() вызывается только один раз и хорош для срока службы загруженной сборки.

Конечно, поскольку вы должны предоставить "закрытый ключ" в сборке, эта процедура не является взломанной (что такое?), но она достаточно безопасна и будет честно честным человеком.

Ответ 4

Прежде всего, как вы понимаете, недостаточно использовать InternalsVisibleTo - вам также нужно будет подписывать и строго называть каждую сборку, чтобы кто-то не мог просто обмануть имя.

Теперь, когда это не так, вам придется самостоятельно разработать реализацию ответа на запрос-ответ - это не то, что вы можете сделать, если не хотите использовать подход InternalsVisibleTo, который вы явно описываете не хотите использовать.

В модели C-R вам нужно будет передать какой-то токен каждому вызову метода (или, возможно, просто создать экземпляр объекта). Токен будет классом, который только ваш код может создать экземпляр - я бы сделал это внутренним классом сборки, который вы хотите использовать, и сделать его доступным с помощью InternalsVisibleTo - таким образом, нужно управлять только одним классом:

// SharedAssembly.dll
// marks ConsumingAssembly.dll as having access to internals...

internal sealed class AccessToken { }

public class SecuredClass
{
   public static bool WorkMethod( AccessToken token, string otherParameter )
   {
       if( token == null )
           throw new ArgumentException(); // you may want a custom exception.

       // do your business logic...
       return true;        
   }
}



// ConsumingAssembly.dll  (has access via InternalsVisibleTo)

public class MainClass
{
  public static void Main()
  {
      var token = new AccessToken(); // can create this because of IVT access
      SecuredClass.WorkMethod( token, "" );  // tada...
  }
}

Вы можете поместить класс AccessToken в третью сборку, о которой знают как поставщик услуг, так и пользователь, чтобы вам не приходилось постоянно поддерживать другую группу для доступа к классам токенов для разных сборок.

Построение механизма C-R для каждого метода является громоздким и утомительным. Он также не является на 100% надежным - кто-то с достаточным временем и терпением мог бы найти способ обойти его.

Лучшим вариантом (который может или не может быть возможным в вашем случае) было бы сохранить ваш частный код на ваших собственных серверах и только разоблачить его как веб-сервис (или что-то подобное). Это позволяет вам активно управлять доступом к вашему IP-адресу и позволяет вам обновлять, кто имеет доступ в централизованном (а не распространенном) порядке. Технологии уже существуют для ограничения доступа к веб-сервисам с использованием сертификатов, сигнатур сообщений и шифрования. Это был бы самый надежный (и проверенный) способ контроля доступа к IP-адресу.

Ответ 5

Я думаю, что это слишком шумно! Если вам действительно нужна безопасность, поместите свой код за сервер и используйте архитектуру клиент-сервер. Или веб-сервисы. Или что-то среднее между WCF или удалением. Затем используйте аутентификацию для аутентификации клиента.

Если вы можете сделать все приватным, выставить открытый API и локально локализовать вызовы.

Защита dll от неавторизованных абонентов в среде только для настольных компьютеров только усложняет работу и усложняет работу. Не говоря уже о том, что это выглядело бы довольно уродливо внутри.

Я вижу, как появляются некоторые соглашения. И это может сработать для вас. Но это не дает вам "полной безопасности", которую вы требуете. Если у вас есть сборка, которая должна быть скрыта от клиентов, не помещайте ее в GAC. Используйте пространства имен с надписью "ВНУТРЕННИЙ".

Ответ 6

Я не думаю, что есть способ сделать это, если вы не контролируете среду исполнения, под которой выполняется код. Код, работающий с полным доверием на пользовательском компьютере, сможет обойти любые введенные вами ограничения. Например, полный код доверия может вызывать частные или внутренние методы с API-интерфейсом отражения, поэтому даже использование InternalsVisibleToAttribute не будет работать.

Если вы контролируете среду исполнения, вы можете создать AppDomain, где ваш код полностью доверен, а сторонний код частично доверен и не может вызвать ваш код, если вы не поместите AllowPartiallyTrustedCallersAttribute (APTCA) на сборке. Вы можете ограничить, какие методы можно вызвать в сборке APTCA с помощью SecurityCritical и SecuritySafeCritical.

Как выполнить частично доверенный код в песочнице