Защищенные сборки C # от неавторизованных абонентов - PullRequest
18 голосов
/ 11 мая 2010

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

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

Например:

Сценарий один

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

Фу имеет класс А Бар имеет класс B

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

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

Сценарий второй

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

Фу имеет класс А Му имеет класс C

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

Ответы [ 6 ]

6 голосов
/ 11 мая 2010

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

Из метода, который вы можете использовать

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%. Тот, кто когда-либо контролирует систему, может делать (почти) все, что ему нужно - подключать отладчик, изменять содержимое памяти, управлять библиотеками или всем временем выполнения. Наконец, вы также должны эффективно защитить свою сборку от декомпиляции и модификации.

6 голосов
/ 11 мая 2010

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

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

2 голосов
/ 11 мая 2010

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

Черт возьми, вы можете сделать все конфиденциальным, предоставить публичный API и выполнить локальные вызовы.

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

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

2 голосов
/ 11 мая 2010

Прежде всего, как вы понимаете, недостаточно использовать 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.

2 голосов
/ 11 мая 2010

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

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

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

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

0 голосов
/ 11 мая 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...