Интересности      Книги      Утилиты    

26 апреля 2010 г.

От чего защищает strong name в .net cборках?

Основная цель strong name или подписи сборки это ее уникальность в GAC(Global assembly cache). На основании сборки во время подписи вычисляется криптографический открытый ключ, закрытый хранится в секрете у производителя сборки, хеш-функция от которого и составляет public token, что, по сути, есть strong name для сборки. Public token сохраняется в метаданных сборки и в паре с именем сборки, версией, и культурой, и служит для уникальной ее идентификации.

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

Но многие заблуждаются думая, что сборка со строгим именем защищена от модификации. Справедливости ради, стоит заметить, что если производитель сборки опубликовал public token или открытый ключ, например на своем сайте, то всегда можно проверить соответствует ли этот ключ или токен тому ключу, который зашит в используемые сборки, но это скорее придется проверить вручную. Важно другое, что в случае строгое имя не защитит сборку от модификации, как многие думают, и соответственно механизм в CLR не отработает, как положено и загрузит модифицированную сборку.

Как такое возможно спросите вы? Все очень просто, так как Public token (маркер открытого ключа) зашивается в сборку то его можно просто удалить от туда.

Но ведь другие сборки, которые ссылаются на эту сборку и ее строгое имя, не загрузят ее и не будут выполняться, как следует, скажете вы. Да не загрузят. Пока они тоже подписаны тем же строгим и пока в зависимостях у них указано связь со сборкой со строгим именем. Но если и у этих сборок убрать строгие имена или ссылки на сборки со строгими именами заменить на те же только без строгого имени. Тогда приложение отработает, как следует.

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

Давайте рассмотрим на примере. Пусть некая компания выпускает свой продукт. Не важно какой. Важно другое, что их продукт состоит с определенного числа собственных сборок подписанных одним закрытым ключом, а следовательно с одинаковым public token. Также их продукт содержит 3rd party сборки, сборки сторонних разработчиков, компоненты, которые поставляются с продуктом. Компания решает как-то ограничить функционал продукта, естественно код ограничения и условия, при которых оно срабатывает, находятся в сборках компании. Злоумышленнику необходимо модифицировать какую-то одну сборку, чтобы снять ограничение. Он ее модифицирует и снимет строгое имя, так что сборка станет не подписанной. Чтобы другие сборки, которые ссылаются на нее, отработали правильно, он снимет подпись и с них, а также поменяет зависимости этих сборок на сборки без подписи.

Возможно, вы думаете, что сделать это сложно? Нет, сделать такое может любой школьник. Что для этого нужно? Рефлектор и плагин для него ReflexIL.

В составе ReflexIL есть strong name remover. Работает он очень просто. Выбираем сборку, жмем «Auto scan assembly directory», если будут найдены сборки со строгим именем они добавятся в список. А дальше нажимаем «Remove strong name and update referencing assemblies» и все. Теперь мы сняли подпись со сборки.

image

Т.е. не смотря на то, что нас уверяют, что строгое имя помимо отношения к глобальному кэшу сборок защищает еще и от модификации сборки, это далеко не так на практике.
Так что не стоит полагаться на строгое имя как надежную защиту от модификации.
Но как же быть спросите вы? На самом деле это уже тема другой статьи. Но ответ ясен, использовать стандартные для .NET механизмы защиты – обфускация, использование смешанного управляемого и неуправляемого кода.

Можно также проверять строгое имя сборки вручную, а в сочетании с PostSharp или каким либо другим АОП подходом, маркировать необходимые методы в коде атрибутом, сообщающим, что перед его вызовом необходимо проверить строгое имя. И проверять собственным методом строгое имя сборки с жестко зашитой константой. Только при этом куски кода с проверкой и вызовом проверки, а также константой с public token должны быть обфусцированы зашифрованы. Либо переосмыслить продукт и вынести какие-то его части в качестве веб-сервисов, хотя такое не всегда возможно. Проверить вручную строгое имя можно следующим способом.

    private static bool IsPublicTokenValid(byte[] tokenExpected)
    {
      // Retrieve token from current assembly
      byte[] tokenCurrent = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();

      // Check that lengths match
      if (tokenExpected.Length == tokenCurrent.Length)
      {
        // Check that token contents match
        for (int i = 0; i < tokenCurrent.Length; i++)
          if (tokenExpected[i] != tokenCurrent[i])
            return false;
      }
      else
      {
        return false;
      }
      return true;
    }

Так от чего же защищает строгое имя? Грубо говоря, ни от чего. Это средство для уникальной идентификации сборок, с помощью которого возможно сосуществование нескольких версий одних и тех же сборок в GAC.

Помогает ли строгое имя защитится от модификации сборки? Строгое имя не может защитить от подмены сборки, оно не остановит злоумышленника от удаления подписи сборки, переподписания сборки своим собственным ключом и распространения ее в таком виде. Правда, переподписаная сборка будет иметь другой public key, который можно вручную сравнить с открытым ключом издателя сборки.

Возможно ли использовать подпись сборки строгим именем для определения автора сборки? Строгое имя не подразумевает уровень доверия к сборки, который обеспечивает, например, Authenticode.

6 комментариев:

  1. Есть такое понятие, как "дружественная сборка". Это когда с помощью атрибута InternalsVisibleTo можно разрешить некоторым сборкам доступ к классам определенным как "internal". В качестве аргумента передается строка включающая с имя сборки и публичный ключ (PublicKey не путать с PublicKeyToken). Следовательно как только мы удаляем строгое имя из сборки, она тут же перестанет работать...

    ОтветитьУдалить
  2. 2alexey-algel

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

    ОтветитьУдалить
  3. Если в дружественной сборке удалить строгое имя, то она потеряет доступ к внутренним типам основной сборки. Если в основной сборке удалить атрибут, то эффект будет тот же. Так что единственный вариант, это подписать дружественную сборку новым строгим именем, и изменить атрибут в основной сборке... Это можно сделать без перекомпиляции?

    ОтветитьУдалить
  4. Да Вы правы, это можно сделать без перекомпиляции так как затрагивается только атрибут который хранится в метаданных. Т.е. атрибут изменить можно, строгое имя тоже

    ОтветитьУдалить
  5. Да Вы правы, это можно сделать без перекомпиляции так как затрагивается только атрибут который хранится в метаданных. Т.е. атрибут изменить можно, строгое имя тоже

    ОтветитьУдалить
  6. 2alexey-algel

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

    ОтветитьУдалить