Проверка целостности дистрибутивов
Программное обеспечение, загружаемое по сети, в ряде случаев может быть подменено злоумышленниками, поэтому существуют способы убедиться, что была получена подлинная копия файла. В некоторых случаях проверка осуществляется автоматически, но в некоторых случаях её проводят вручную.
Необходимость проверки
Исходный текст программы, инсталляция или, например, образ диска дистрибутива, доступные по сети, теоретически могут быть подменены на модифицированные копии, содержащие те или иные вредоносные компоненты (примеры подобного известны). Это может произойти из-за взлома сайта, с которого загружается приложение, а также из-за злонамеренных действий кого-либо из множества людей, которые имеют техническую возможность подменить файл тем или иным способом (это может быть администратора сайта, сотрудника хостинг-провайдера, Интернет-провайдера и т.д.). Ситуацию усугубляет наличие зеркал, которые часто используются для уменьшения нагрузки на основной сайт, переадресация на которые может происходить во время загрузки файлов незаметно для пользователя. Использование защищённого соединения не решает проблемы (например, у зеркала, контролируемого злоумышленниками, будет вполне валидный сертификат для их домена).
Поэтому существуют и применяются ряд способов проверки подлинности загружаемых программ при помощи электронной подписи. Более того, они позволяют обнаружить ошибки при загрузке (которые возникают гораздо чаще, чем подмена файлов злоумышленниками, хотя последнее, конечно, наносит жертвам намного больший ущерб).
Использование электронной подписи
Способы проверки подлинности в целом сводятся к использованию электронной подписи, создаваемой при помощи криптографических алгоритмов с открытым ключом, и различаются в деталях реализации, которые подходят для той или иной ситуации. Для Linux основной способ проверки электронной подписи — это использование утилиты GnuPG.
Обычно данная утилита установлена по умолчанию. В случае, если она, например, не установлена в дистрибутиве Debian (что является скорее нештатной ситуацией), её легко установить командой:
apt install gnupg
При этом, для проверки электронной подписи необходимо обладать соответствующим открытым ключом, которые обычно распространяются вместе с подписываемыми файлами и файлами электронной подписи, но есть важный момент с проверкой подлинности открытого ключа: если скачать его с того же сайта, где находится подпись, то, в случае подмены файла, будет скорее всего подменена подпись и открытый ключ. Поэтому, если вы хотите проверить подлинность загружаемого программного обеспечения, можно предпринять дополнительные меры предосторожности, например, скачать открытый ключ заранее (если случаются инциденты с подменой файлов, то они относительно быстро обнаруживаются). Также дистрибутивы Linux могут содержать ряд нужных для проверки ключей. Например, в Debian Linux вы можете установить несколько пактов с ключами используя команду (скорее всего один из них уже будет установлен):
apt install debian-keyring debian-archive-keyring debian-ports-archive-keyring fasttrack-archive-keyring
После этого в каталоге /usr/share/keyrings/ появятся новые файлы с открытыми ключами, связанными с рядом проектов.
Проверка подлинности при помощи электронной подписи для файла
Для файла, подлинность которого нужно подтвердить, создаётся файл электронной подписи, который размещается рядом с ним. Обычно файл подписи имеет расширения .asc, .sig или .sign. Чтобы её проверить, нужно скачать ещё файл ключа, проверить его подлинность, импортировать его и установить степень доверия к нему. Чтобы было понятнее, рассмотрим это на практическом примере, скачаем и проверим целостность исходных текстов Python. Чтобы выполнить все проверки, вам потребуется своя пара ключей, о том, как её сгенерировать, написано в статье про GnuPG.
Откроем в браузере адрес https://www.python.org/ftp/python/, там найдём подкаталог с последней версией, на момент написания данного материала это 3.12.0, перейдём в него и загрузим оттуда файлы Python-3.12.1.tar.xz (исходные тексты Python), Python-3.12.1.tar.xz.asc (файл подписи). Или можно скачать из командной строки эти файлы командой:
wget 'https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tar.xz' 'https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tar.xz.asc'
Теперь мы можем попробовать проверить подлинность файла командой:
gpg --verify Python-3.12.1.tar.xz.asc
Результат получился такой:
gpg: предполагается, что подписанные данные находятся в 'Python-3.12.1.tar.xz'
gpg: Подпись сделана Пт 08 дек 2023 00:02:02 MSK
gpg: ключом RSA с идентификатором 7169605F62C751356D054A26A821E680E5FA6305
gpg: Не могу проверить подпись: No public key
Как видно, проверить подпись не удаётся из-за отсутствия нужного открытого ключа (его идентификатор 7169605F62C751356D054A26A821E680E5FA6305 указан в сообщении об ошибке, которое вывела программа gpg). Ключи для проверки дистрибутивов Python можно скачать на странице https://www.python.org/downloads/ — на странице есть раздел «OpenPGP Public Keys», где мы видим нужный ключ (указан идентификатор ключа, точнее, его последняя часть, которая соответствует идентификатору того ключа, который мы ищем. Скачаем его (его можно загрузить по ссылке https://github.com/Yhg1s.gpg). Откроем в консоли каталог, где был сохранён ключ, и импортируем его базу ключей GnuPG:
gpg --import Yhg1s.gpg
Если мы повторно выполним команду gpg --verify Python-3.12.1.tar.xz.asc, то получим уже новый результат, показывающий, что подпись верна, но уверенности в подлинности ещё нет, поскольку у системы нет данных, позволяющих убедиться, что открытый ключ принадлежит владельцу:
gpg: предполагается, что подписанные данные находятся в 'Python-3.12.1.tar.xz'
gpg: Подпись сделана Пт 08 дек 2023 00:02:02 MSK
gpg: ключом RSA с идентификатором 7169605F62C751356D054A26A821E680E5FA6305
gpg: Действительная подпись пользователя "Thomas Wouters <thomas@python.org>" [неизвестно]
gpg: или "Thomas Wouters <thomas@xs4all.nl>" [неизвестно]
gpg: или "Thomas Wouters <twouters@google.com>" [неизвестно]
gpg: Внимание: Данный ключ не заверен доверенной подписью!
gpg: Нет указаний на то, что подпись принадлежит владельцу.
Отпечаток первичного ключа: 7169 605F 62C7 5135 6D05 4A26 A821 E680 E5FA 6305
Мы скачали ключ по ссылке с официального сайта, но давайте проявим дополнительную бдительность и посмотрим, каким был файл в прошлом, на web.archive.org: http://web.archive.org/web/20230101004252/https://www.python.org/downloads/ — там мы увидим соответствующую ссылку для скачивания, и, если откроем сохранённую версию ключа, то можем убедиться, что она идентична той, что мы уже скачали, наверное можно уже считать, что мы проявили достаточную осмотрительность и убедились, что ключ подлинный. Поэтому мы можем подписать этот ключ, чтобы в дальнейшем проверка подписи при помощи GnuPG не вызывала ошибок. Для этого в командной строке введём команду:
gpg --edit-key 7169605F62C751356D054A26A821E680E5FA6305
Увидим приглашение для ввода команд вида gpg> и введём там команду lsign (завершив ввод переводом строки). Эта команда означает, что вы подписываете ключ только для себя, подпись не будет экспортироваться (есть также варианты sign, tsign и т.д., о которых вы можете прочитать в документации), при её выполнении нужно будет дважды подтвердить осуществляемые действия введя «y», после чего можно завершить работу в GnuPG с сохранением командой save.
Теперь команда gpg --verify Python-3.12.1.tar.xz.asc покажет нам результат проверки подлинности дистрибутива Python:
gpg: предполагается, что подписанные данные находятся в 'Python-3.12.1.tar.xz'
gpg: Подпись сделана Пт 08 дек 2023 00:02:02 MSK
gpg: ключом RSA с идентификатором 7169605F62C751356D054A26A821E680E5FA6305
gpg: проверка таблицы доверия
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: глубина: 0 достоверных: 5 подписанных: 5 доверие: 0-, 0q, 0n, 0m, 0f, 5u
gpg: глубина: 1 достоверных: 5 подписанных: 1 доверие: 5-, 0q, 0n, 0m, 0f, 0u
gpg: срок следующей проверки таблицы доверия 2024-12-28
gpg: Действительная подпись пользователя "Thomas Wouters <thomas@python.org>" [полное]
gpg: или "Thomas Wouters <thomas@xs4all.nl>" [полное]
gpg: или "Thomas Wouters <twouters@google.com>" [полное]
Итак, GnuPG сообщила нам: «Действительная подпись пользователя "Thomas Wouters <thomas@python.org>" [полное]» — как мы видим, архив подписан одним из участников проекта Python.
Проверка подлинности при помощи подписанных файлов контрольных сумм
Иногда подписывается не файл дистрибутива, а файл, содержащий контрольные суммы загружаемых с сервера файлов. Этот вариант обычно применяется, когда на сервер выкладывается множество вариантов дистрибутива (для разных платформ, для разных языков и т.д.).