Анализ инструментов Go для проверки уязвимостей безопасности

С ростом сообщества Go все больше и больше пакетов с открытым ПО становились причиной возникновения уязвимостей безопасности. Такая тенденция вызвала озабоченность официальных представителей Go, вследствие чего в сентябре 2022 года был представлен инструмент сканирования безопасности Go Vulnerability Check (Проверка уязвимостей Go)  —  govulncheck.

Источник

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

Применение инструмента для проверки уязвимостей Go (govulncheck)

Приступаем к испытанию данного инструмента.

Устанавливаем (поддерживается только с версии Go 1.18):

go install golang.org/x/vuln/cmd/govulncheck@latest

Запускаем в каталоге проекта, в котором находится файл go.mod:

govulncheck ./...

В качестве демо воспользуемся одним из моих проектов Kubernetes Operator. В отчете отображены две уязвимости.

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

Сканирование зависимостей с известными уязвимостями. Обнаружено 3 известных уязвимости.

Уязвимость # 1: GO-2022–0236

Вредоносный HTTP-сервер или клиент способны нарушить работу net/http клиента или сервера и сгенерировать панику (англ. panic). ReadRequest и ReadResponse могут привести к необратимой панике при чтении слишком длинного заголовка, превышающего 7 МБ на 64-битных архитектурах или 4 МБ на 32-битных. Transport и Client уязвимы, и вредоносный сервер может вызвать дисфункцию программы. По умолчанию сервер не является уязвимым, но может таким стать, если переопределить максимальный размер заголовка по умолчанию в 1 МБ, установив более высокое значение для Server.MaxHeaderBytes. В этом случае сбой программы может быть вызван вредоносным клиентом. Это также затрагивает golang.org/x/net/http2/h2c и HeaderValuesContaintsToken в golang.org/x/net/http/httpguts.

  • Нижеследующие уязвимости содержатся в импортируемых пакетах. Они представляют собой уязвимости в зависимостях проекта и устраняются путем обновления соответствующих зависимостей пакетов.

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

Уязвимость # 1: GO-2022–0969

Соединения сервера HTTP/2 могут надолго зависнуть в ожидании чистого закрытия системы, прерванного критической ошибкой. Этим состоянием может воспользоваться вредоносный клиент, чтобы спровоцировать отказ в работе сервиса.

В обоих случаях выводятся следующие сведения об уязвимостях:

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

Запуск govulncheck в CI/CD​

Для большей эффективности следует интегрировать инструмент в конвейер CI/CD. С этой целью экспортируем результат файла JSON и задействуем флаг -json:

govulncheck -json ./...

Файл JSON  —  это подробный вывод, включающий процесс и результаты сканирования, а также записи вызовов:

Calls  —  проверка, связанная с нативным кодом; Imports  —  проверка зависимостей; Vulns  —  проверка результатов.

Для jq '.Vulns | length' устанавливаем != 0. Для текущего оператора помещаем соответствующую оболочку bash в Makefile и запускаем в CI/CD.

vuln также поддерживает тестирование двоичных файлов, заменяя ./… на имя нужного файла. Кроме того, при интеграции в CI/CD vuln применяется для обнаружения уязвимостей в проектах Go, содержащих только Docker-образы.

Проверка тестового кода

vuln не проверяет тестовый код по умолчанию. Однако просканировать тестовые файлы можно с помощью:

-test flag govulncheck -test pkg/test/*

​Внутренний механизм govulncheck

Инструмент vuln запускает инструмент командной строки и считывает базу данных vuln для анализа файла go.mod и кода Go. Таким образом, он в основном состоит из двух частей:

  • разработка инструмента командной строки vuln;
  • обслуживание базы данных vulndb.

Инструмент командной строки Vuln

Как правило, чтение кода инструмента командной строки начинается с места определения командной строки. Процесс простой и включает в себя 5 шагов для проверки исходного кода:

  • чтение и настройка клиента базы данных;
  • загрузка конфигурации;
  • чтение исходного кода и последовательности;
  • обнаружение;
  • обработка результатов.

Основу составляет метод vulncheck.source():

Source обнаруживает уязвимости в пакетах. Результат включает:

  1. ImportGraph, связанный с импортом пакета, который содержит известные уязвимости.
  2. RequireGraph, связанный с требованием модуля, который включает пакет с известными уязвимостями.
  3. CallGraph, приводящий к использованию известной уязвимой функции или методу.

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

База данных Vuln

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

Подробное описание каждой уязвимости состоит из 6 атрибутов.

Организованный набор данных. Команда безопасности Go Security активно обслуживает базу данных, поэтому она предоставляет согласованные метаданные и единообразный анализ выявленных уязвимостей, обеспечивая возможность не только обнаружения, но и точной оценки последствий.

Основные метаданные. Записи включают уникальный идентификатор базы данных для уязвимости, диапазон затронутых пакетов и версий, приблизительную степень серьезности и по необходимости GOOS/GOARCH. Уязвимости также присваивается номер CVE (англ. Common Vulnerabilities and Exposures, т.е. известные уязвимости и дефекты безопасности).

Целевые метаданные. Каждая запись базы данных включает метаданные, достаточные для обнаружения затронутых нисходящих приложений с низким уровнем ложноположительных срабатываний. Например, такая запись содержит затронутые символы (функции, методы, типы, переменные…), позволяя с помощью статического анализа определить незатронутые объекты-получатели.

Веб-страницы. Каждая уязвимость содержит ссылку на веб-страницу с описанием уязвимости, инструкциями по устранению и дополнительными ссылками.

Единый источник истины. База данных обслуживается как публичный git-репозиторий, по аналогии с другими репозиториями Go. Записи базы данных доступны через устоявшийся протокол. Содержимое самого репозитория находится во внутреннем формате, который может меняться без уведомления.

Процесс отбора. Потенциальные записи поступают из существующих потоков (таких как база данных CVE и списки рассылки по безопасности), а также из материалов, предоставляемых сообществом. Для обеспечения согласованности метаданных и анализа все полученные сведения обрабатываются командой. Специалистам по обслуживанию настоятельно рекомендовано сообщать об уязвимостях, обнаруженных в своих модулях.

В процессе реализации vulndb также предоставляет набор команд cmd для обслуживания базы данных, онлайн-верификации и т.д. Например, команда worker локально запускает сервер и сканирует файлы в Git:

Команда cve запрашивает и обновляет данные об уязвимости, вызывая HTTP-запросы для получения соответствующей информации.

RetrieveRecord запрашивает запись CVE

Мы можем скачать код vulndb и командой git clone клонировать этот репозиторий, после чего протестировать и локально выполнить все эти команды через скрипт в devtools.

Альтернативные варианты

vuln  —  это официальный продукт Go, который по прогнозам приобретет популярность в ближайшем будущем. Тем не менее отметим ряд его недостатков.

  • vuln  —  это всего лишь экспериментальный инструмент.
  • Он поддерживает проверки двоичного кода, только начиная с версии Go 1.18 и выше.
  • vuln обнаруживает уязвимости только в текущей версии Go. Например, если вы обновляете Go до последней версии 1.19, то перестаете получать отчеты об уязвимостях зависимостей в версии 1.18.
  • Ограниченный метод вывода. Вывод JSON отличается чрезмерной сложностью, а text предназначен только для локальной среды. Например, формат итогового вывода в исходном коде поддерживает только среду разработки и тестирования.
  • vuln возвращает ложноположительные и неточные отчеты стека при сканировании интерфейсов и указателей на функции.

Не стоит зацикливаться на vuln. Почему бы не рассмотреть другие инструменты сканирования безопасности зависимостей Go в ожидании его улучшения? В настоящее время наиболее известные из них  —  это Github security dependency scan (Сканирование зависимостей на уязвимости безопасности GitHub) и gosec.

Инструмент сканирования безопасности зависимостей GitHub

Применительно к Go-проектам с открытым исходным кодом на GitHub мы можем выполнять регулярные сканирования зависимостей, активируя в настройках Dependabot alerts:

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

Инструмент gosec

Инструмент gosec очень похож на vuln. Они оба являются инструментами командной строки и сканируют уязвимости Go по схожим правилам.

Действующие правила

  • G101: Поиск жестко заданных учетных данных.
  • G102: Привязка ко всем интерфейсам.
  • G 103: Аудит использования небезопасного блока.
  • G 104: Аудит непроверенных ошибок.
  • G 106: Аудит использования ssh.InsecureIgnoreHostKey.
  • G 107: Url, указанный в HTTP-запросе в качестве “зараженных” (англ. taint) входных данных.
  • G 108: Конечная точка профилирования, автоматически отображаемая в /debug/pprof.
  • G 109: Потенциальное целочисленное переполнение, вызванное преобразованием результата strconv.Atoi в int16/32.
  • G 110: Потенциальная DoS-уязвимость через декомпрессионную бомбу.
  • G 111: Потенциальный обход каталога.
  • G 112: Потенциальная атака slowloris.
  • G 113: Использование Rat.SetString в math/big c переполнением (CVE-2022–23772).
  • G 114: Использование функции serve пакета net/http, которая не поддерживает установку тайм-аутов.
  • G 201: Построение SQL-запроса с использованием формата string.
  • G 202: Построение SQL-запроса с использованием конкатенации строк.
  • G 203: Применение неэкранированных данных в HTML- шаблонах.
  • G 204: Аудит использования выполнения команд.
  • G 301: Некорректные права доступа к файлам, применяемые для создания каталогов.
  • G 302: Некорректные права доступа к файлам, применяемые с chmod.
  • G 303: Создание временного файла с использованием прогнозируемого пути.
  • G 304: Путь к файлу, предоcтавляемый в качестве “зараженных” входных данных.
  • G 305: Обход файлов при распаковке архива zip/tar.
  • G 306: Некорректные права доступа к файлам при записи в новый файл.
  • G 307: Откладывание метода, который возвращает ошибку.
  • G 401: Обнаружение случаев применения DES, RC4, MD5 , SHA1.
  • G 402: Поиск некорректных настроек TLS-соединений.
  • G 403: Обеспечение минимальной длины ключа RSA в 2048 бит.
  • G 404: Небезопасный генератор случайный чисел (rand).
  • G 501: Импорт списка блокировки: crypto/md5.
  • G 502: Импорт списка блокировки: crypto/des.
  • G 503: Импорт списка блокировки: crypto/rc4.
  • G 504: Импорт списка блокировки: net/http/cgi.
  • G 505: Импорт списка блокировки: crypto/sha1.
  • G 601: Неявные конфликты в доступе к элементам в памяти из инструкции range.

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

Скажем так, на данный момент gosec более разработан по сравнению с vuln, которому есть куда совершенствоваться.

Заключение

С развитием Go и возросшим числом проблем безопасности актуальным становится тщательный отбор зависимостей и их систематическое обновление. Однако реализация этой задачи представляет определенную сложность при необходимости регулярных обновлений пул-реквестов и слияния (англ. merge), которые игнорируются некоторыми пользователями. Решение заключается в сканировании зависимостей, которое вынуждает пользователей проводить обновления в результате сбоя сборки непосредственно в CI/CD.

Что касается инструмента vuln, его ждет дальнейшая оптимизация и усовершенствование.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Stefanie Lai: Secure Your Go Code With Vulnerability Check Tool

Предыдущая статья7 самых популярных библиотек React
Следующая статья4 расширения VS Code, которые пригодятся дата-инженеру