"Файл подписан, значит безопасный" - цифровая подпись отвечает не на тот вопрос
Фраза "программа подписана известным издателем" часто используется как окончательный аргумент в пользу установки стороннего приложения или включения его в корпоративную сборку. Пользователь открывает свойства файла, видит сообщение "Эта цифровая подпись действительна" и делает вывод, что перед ним безопасный продукт.
Однако цифровая подпись подтверждает гораздо более узкий набор фактов. Она показывает, что определённый файл был подписан закрытым ключом, связанным с конкретным сертификатом, а после подписания содержимое не изменялось. Но подпись сама по себе не доказывает, что программа безвредна, компания-издатель действует добросовестно, ключ не был украден и сертификат не использовался злоумышленниками.
Именно на разнице между реальным смыслом подписи и тем, что в неё хотят "прочитать", строятся многие атаки.
Что именно подтверждает цифровая подпись
При проверке подписанного файла обычно устанавливаются три обстоятельства:
- подпись математически соответствует содержимому файла;
- файл подписан ключом, связанным с определённым сертификатом;
- на момент, который учитывает механизм проверки, сертификат входил в доверенную цепочку.
Если после подписания изменить хотя бы один байт охватываемой подписью области, проверка целостности завершится ошибкой. Но из этого не следует, что исходный файл был безопасным. Вредоносная программа тоже может быть подписана, если атакующий получил доступ к легитимному ключу либо встроил вредоносный код в настоящий процесс сборки.
Подпись отвечает на вопрос "кто подписал файл и менялся ли он после этого", но не на вопросы "можно ли ему доверять сейчас" и "не был ли издатель скомпрометирован".
Как злоумышленники получают чужие сертификаты
Криптографически подписать файл именем другой компании без закрытого ключа невозможно. Поэтому проблема обычно возникает не в алгоритмах, а в процессах хранения и использования ключей.
Наиболее распространённый сценарий - компрометация сервера сборки. Закрытый ключ нередко хранится рядом с CI-системой, чтобы автоматически подписывать релизы. Если атакующий получает доступ к агенту сборки, он может скопировать ключ и использовать его уже за пределами инфраструктуры компании.
Известен и сценарий с кражей ключей из цепочки поставок. В атаке ShadowHammer, связанной с ASUS Live Update, вредоносное обновление распространялось с легитимной подписью ASUS. Пользователь видел настоящего издателя, потому что подпись действительно принадлежала ему, а проблема заключалась в подмене содержимого на этапе подготовки или доставки обновления.
Риск создают и посредники, которые оформляют сертификаты на подставные юридические лица или проводят недостаточную проверку заказчиков. Формально сертификат может быть выпущен корректно, но имя в нём не гарантирует реальную связь между программой и известной компанией.
Почему просроченный сертификат не всегда делает подпись недействительной
Проверка подписи не всегда оценивает сертификат по текущей дате. Важнее понять, был ли он действителен в момент подписания.
Например, сертификат мог завершить срок действия в 2024 году, но файл подписали в 2023-м. Если доказано, что подпись появилась в период действия сертификата, она может оставаться действительной и после его истечения.
В OpenSSL проверку цепочки на конкретную дату можно моделировать с помощью параметра `-attime`. При этом оценивается состояние всей цепочки: не только сертификата издателя, но и промежуточных и корневых центров сертификации. Если на выбранную дату один из них ещё не вступил в силу или уже был недействителен, проверка завершится ошибкой.
Authenticode в Windows основан на контейнере PKCS#7/CMS, поэтому тот же принцип применяется и к подписанным исполняемым файлам и драйверам.
Зачем нужна метка времени
Без отдельного доказательства времени проверяющей стороне пришлось бы ориентироваться на локальные часы компьютера. Это ненадёжно: системное время можно изменить вручную, политикой домена или вредоносным кодом.
Для решения этой проблемы применяется RFC 3161. Служба меток времени, или TSA, формирует специальный `TimeStampToken`. В нём фиксируется хеш объекта и момент, не позднее которого этот хеш уже существовал. Сам токен подписывается ключом службы времени.
В Authenticode метка времени хранится рядом с основной подписью как отдельный атрибут. Её иногда путают со старым механизмом контрподписи PKCS#9, хотя это разные варианты оформления временного подтверждения.
Сертификат TSA должен иметь специальное расширение, разрешающее заверять время. Обычный сертификат издателя для этой функции не подходит.
Если метка времени корректна, проверяющая система может установить: файл был подписан тогда, когда сертификат издателя ещё действовал. Поэтому последующее истечение срока не обязательно аннулирует подпись.
Почему отзыв сертификата не решает проблему мгновенно
Отзыв сертификата означает, что центр сертификации объявил его недействительным до окончания первоначального срока. Но проверка отзыва зависит от доступности CRL или OCSP, политики операционной системы и наличия сведений о времени компрометации.
Если ключ украли, а затем им подписали вредоносный файл с действительной меткой времени, возникает сложная ситуация. Необходимо определить, появилась подпись до компрометации или после неё. Если центр сертификации не указал точное время компрометации, а система доверяет исторической подписи, один только отзыв может оказаться недостаточным.
Кроме того, компьютеры не всегда могут обратиться к службам проверки отзыва. В изолированной сети, при сбое инфраструктуры или при особенностях политики безопасности система способна использовать ранее сохранённые сведения либо продолжить проверку по локальным правилам.
Что подпись не покрывает
Подпись может охватывать не весь файл. В некоторых форматах существуют области, которые намеренно исключаются из расчёта хеша: заголовки, служебные поля, каталоги, блоки метаданных или дополнительные секции.
Для PE-файлов Windows используется специальная схема, при которой часть структуры не входит непосредственно в подписанный хеш. Это необходимо для технической работы формата, но создаёт дополнительные требования к проверке. Нельзя ограничиваться вопросом "подпись отображается как действительная" - нужно понимать, какие именно данные реально защищены.
Особое внимание следует уделять установщикам, архивам, пакетам обновлений и контейнерам с дополнительными ресурсами. Подписанным может быть внешний загрузчик, тогда как он отдельно получает и запускает другой компонент. В такой конструкции безопасность нужно проверять для всей цепочки, а не только для первого файла.
Как проверять файл на практике
Начинать следует не с графического сообщения о действительности подписи, а с установления происхождения файла:
1. Сверить хеш с официальным значением, полученным по независимому каналу.
2. Проверить полное имя издателя и цепочку сертификатов.
3. Посмотреть дату подписи и наличие RFC 3161-метки.
4. Изучить статус отзыва сертификата.
5. Уточнить, не был ли сертификат отозван из-за компрометации ключа.
6. Проверить подписи всех вложенных компонентов, библиотек и драйверов.
7. Сопоставить версию файла с заявленной версией продукта.
8. Проанализировать поведение программы в песочнице или на тестовой машине.
В Windows полезно просматривать вкладки с сертификатом, цепочкой доверия и меткой времени, а также использовать PowerShell или системные средства проверки подписи. Для корпоративной среды желательно централизованно собирать сведения о подписантах, хешах и версиях программ.
Как защитить собственные ключи
Компаниям, выпускающим подписанные приложения, не следует хранить закрытый ключ обычным файлом на CI-сервере. Предпочтительный вариант - HSM или защищённый криптографический токен, из которого ключ нельзя извлечь.
Сервер сборки в таком случае передаёт в защищённое устройство только хеш или подготовленный объект для подписи. Даже при компрометации агента злоумышленник не получает копию ключа, хотя временно может попытаться воспользоваться активной сессией. Поэтому доступ к операции подписания нужно ограничивать ролями, временными токенами, журналированием и ручным подтверждением критических релизов.
Полезно разделять ключи для разных продуктов и сред: тестовой, внутренней и производственной. Компрометация одного сертификата тогда не поставит под угрозу все выпуски компании.
Итог
Действительная цифровая подпись - важный элемент доверия, но не универсальная гарантия безопасности. Она подтверждает происхождение файла в определённый момент и позволяет обнаружить последующие изменения в защищённой области. При этом подпись не исключает кражу ключа, компрометацию процесса сборки, злоупотребление со стороны издателя или наличие вредоносного кода в официальном обновлении.
Правильная формулировка звучит так: "Файл подписан сертификатом, связанным с этим издателем, и после подписания защищённые данные не менялись". А уже вывод о безопасности требует дополнительных проверок - анализа цепочки поставок, хешей, репутации версии, поведения программы и состояния ключей.
