Нужно ли публиковать открытый ключ из файла.snk?

Из описания утилиты sn.exe и этого вопроса я вижу, что копия открытого ключа добавляется в каждую сборку, подписанную строгим именем. Этого достаточно, чтобы проверить, что двоичный файл сборки не был изменен.

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

3 ответа

Решение

Нет, вам не нужно публиковать ваш открытый ключ вне сборки, поскольку он хэшируется и хранится в виде токена вместе со ссылкой внутри клиентского приложения:

AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bcd6707151635d07"

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

Более подробную информацию о том, как эта информация мешает другому источнику притворяться вами, можно найти в моем другом ответе.

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

Я приобретаю библиотеку шифрования у компании A, вскоре после этого компания B получает мои данные электронной почты и отправляет мне бесплатное обновление сборки, выдавая себя за серьезную ошибку безопасности в компании A, когда она действительно внедряет скрытый метод в мой код, который отправляет все данные, которые я пытался зашифровать, на серверы компании B. Предполагая, что я идиот и слепо добавляю эту новую dll в каталог bin моего приложения, тот факт, что он не был подписан тем же закрытым ключом, что и старая версия, будет обнаружен во время выполнения, что вызовет исключение и защитит мои данные.

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

Википедия говорит примерно то же самое (только в значительно меньшем количестве слов).


Отредактировано, чтобы добавить дополнительную информацию в попытке сделать это более понятным...

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

Итак, пользователь Z, который использует библиотеку шифрования из компании А, которая находится в его папке bin приложений. Для этого он ссылается на DLL следующим образом:

Encryption, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bcd6707151635d07"

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

Во-первых, он предоставляет уникальное имя для сборки - это не дает нам дополнительной безопасности, но останавливает dll Hell в стиле C, когда две разные компании могут выпустить две разные библиотеки с именем Encyption версии 1.0.0.0, и вы не сможете их хранить в тот же каталог, так как нет никакого способа их дифференцировать.

Во-вторых, это предотвращает сценарий, который я обрисовал в своем первоначальном посте. Компания B не может создать другую версию библиотеки Encryption, которая также является версией 1.0.0.0 и имеет тот же открытый ключ (чтобы полное имя совпадало, и вы вызывали бы их код вместо компании A). Они не могут этого сделать, потому что если их открытый ключ совпадает, то закрытый ключ также должен совпадать (поскольку каждая пара уникальна). Единственный способ получить закрытый ключ - это поставить под угрозу безопасность компании А.

Наконец, он обеспечивает целостность файла (либо изменен в результате повреждения или внедрения вредоносного кода). DLL хэшируется во время выполнения (когда оно является приватным и находится в папке bin приложения) или во время установки (когда вы помещаете его в GAC) с использованием открытого ключа, и этот хэш сравнивается с хешем, который был зашифрован приватным ключ и хранится в сборке. На этой странице есть некоторые диаграммы и более подробная информация. Еще раз, единственный способ подделать этот хэш - это знать закрытый ключ.

Итак, чтобы охватить конкретный сценарий, который я описал выше, представьте, что я Компания B, пытающаяся предоставить Пользователю Z вредоносную версию DLL шифрования. Моя первая попытка состоит в том, чтобы просто создать свою собственную dll с именем Encryption и Version 1.0.0.0 и подписать ее с моей собственной парой ключей. К сожалению, я не могу изменить ссылочный код в приложении пользователя Z, поэтому он не проходит проверку полного имени и не загружается. "Хорошо, - говорит я, закручивая усы, - я просто изменю открытый ключ своей сборки, чтобы он соответствовал ключу компании А". Как только я это сделаю, проверка имени проходит, но проверка хеша не удастся, потому что приложение пользователя Z не сможет расшифровать хэш, сохраненный в сборке (которая была зашифрована с помощью закрытого ключа компании B) с помощью открытого ключа (Company А), который был поставлен. Следовательно, единственный способ для компании B создать библиотеку, которая претендует на звание компании A, - это узнать закрытый ключ компании A. Ни одна из этих проверок безопасности не зависит от компании А, публикующей открытый ключ где-либо еще, кроме первоначального выпуска сборки.

Также обратите внимание, что все эти функции не гарантируют (и не утверждают, что гарантируют), что исходная сборка была получена от Компании A, которая обрабатывается другими системами, такими как Verisign или служба Microsoft Authenticode, они только гарантируют, что у вас есть ссылается только на сборку. Компания А может вносить изменения в этот код.

  1. Вы можете обратиться к какому-либо стороннему поставщику сертификатов (например, VeriSign) и приобрести у него сертификат ( Code Signing At Verisign).
  2. Вы используете данный сертификат с названием вашей компании, URL-адресом и т. Д. Для подписи вашего кода.
  3. Я загружаю ваше приложение и смотрю список сертификатов, с которыми ваше приложение было подписано.
  4. Я использую ваш сертификат, возвращаюсь к VeriSign и проверяю, что сертификат действительно был выдан MyCompany, LLC.
  5. Я смотрю на сертификаты, которые использовались для выдачи вашего сертификата, и проверяю, что VeriSign является одним из них (Windows поставляется с несколькими установленными доверенными сертификатами).

Резюме:
Вы не только проверяете, что код не был возделан, но и подписаны сертификатом, выданным стороной, которой вы доверяете.

Другие вопросы по тегам