Запуск CodeQL в базе данных

Завершено

С помощью кода, извлеченного в базу данных, теперь его можно проанализировать с помощью запросов CodeQL. Эксперты GitHub, исследователи безопасности и участники сообщества записывают и поддерживают запросы CodeQL по умолчанию. Вы также можете написать собственные запросы.

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

Существует два важных типа запросов:

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

Простой запрос CodeQL

Базовая структура запроса CodeQL содержит расширение файла .ql и содержит предложение select. Ниже приведен пример структуры запросов:

/**
 *
 * Query metadata
 *
 */
import /* ... CodeQL libraries or modules ... */
/* ... Optional, define CodeQL classes and predicates ... */
from /* ... variable declarations ... /
where / ... logical formula ... /
select / ... expressions ... */

Метаданные запроса

Использование CodeQL со сканированием кода преобразует результаты так, чтобы выделить потенциальные проблемы, которые запросы предназначены находить. Запросы содержат свойства метаданных, указывающие, как следует интерпретировать результаты. Используйте метаданные запроса для:

  • Определите пользовательские запросы при добавлении их в репозиторий GitHub.
  • Укажите сведения о назначении запроса.

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

GitHub содержит рекомендуемое руководство по стилю для метаданных запроса. Его можно найти в документации CodeQL .

В этом примере показаны метаданные для одного из стандартных запросов Java:

Снимок экрана: метаданные запроса.

CodeQL не интерпретирует запросы, у которых нет метаданных. Он отображает эти результаты в виде таблицы и не отображает их в исходном коде.

Синтаксис QL

QL — это декларативный объектно-ориентированный язык запросов. Она оптимизирована для эффективного анализа иерархических структур данных и, в частности, баз данных, представляющих артефакты программного обеспечения.

Синтаксис QL аналогичен SQL, но семантика QL основана на журнале данных. Журнал данных — это декларативный язык программирования логики, который часто используется в качестве языка запросов. Поскольку QL является главным образом языком логики, все операции в QL являются логическими операциями. QL также наследует рекурсивные предикаты из журнала данных. QL добавляет поддержку агрегатов, чтобы сделать даже сложные запросы краткими и простыми.

Язык QL состоит из логических формул. В нем используются распространенные логические соединители, такие как and, orи not, а также квантификаторы, такие как forall и exists. Так как QL наследует рекурсивные предикаты, можно также создавать сложные рекурсивные запросы с помощью базового синтаксиса QL и агрегатов, таких как count, sumи average.

Дополнительные сведения о языке QL см. в документации по CodeQL.

Запросы пути

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

Создание запросов пути поможет визуализировать поток информации с помощью базы кода. Запрос может отслеживать путь, который данные принимают из возможных начальных точек (source) до возможных конечных точек (sink). Чтобы моделировать пути, запрос должен предоставить сведения об источнике, приемнике и шагах потока данных, которые связывают их.

Самый простой способ начать написание собственного запроса пути — использовать один из существующих запросов в качестве шаблона. Чтобы получить эти запросы для поддерживаемых языков, см. документацию по CodeQL .

Запрос пути требует определенных метаданных, предикатов запросов и структур инструкций select. Многие встроенные запросы пути в CodeQL соответствуют базовой структуре. Структура зависит от того, как CodeQL моделирует язык, который вы анализируете.

Ниже приведен пример шаблона для запроса пути:

/**
 * ...
 * @kind path-problem
 * ...
 */

import <language>
// For some languages (Java/C++/Python/Swift), you need to explicitly import the data-flow library, such as
// import semmle.code.java.dataflow.DataFlow or import codeql.swift.dataflow.DataFlow
...

module Flow = DataFlow::Global<MyConfiguration>;
import Flow::PathGraph

from Flow::PathNode source, Flow::PathNode sink
where Flow::flowPath(source, sink)
select sink.getNode(), source, sink, "<message>"

В этом шаблоне:

  • MyConfiguration — это модуль, содержащий предикаты, определяющие, как данные проходят между source и sink.
  • Flow результат вычисления потока данных на основе MyConfiguration.
  • Flow::Pathgraph — это результирующий модуль графа потока данных, который необходимо импортировать для включения объяснений пути в запрос.
  • source и sink являются узлами в графе, как определено в конфигурации, и Flow::PathNode их тип.
  • DataFlow::Global<..> — это вызов потока данных. Вместо этого вы можете включить набор шагов по умолчанию с помощью TaintTracking::Global<..>.

Как написать запрос на поиск пути

Запрос должен вычислить граф пути для создания объяснений пути. Для этого определите предикат запроса с именем edges. Предикат запроса — это нечленский предикат с аннотацией query. Аннотация запроса возвращает все кортежи, которые вычисляет предикат.

Предикат edges определяет пограничные отношения графа, который вы вычисляете. Он используется для вычисления путей, связанных с каждым результатом, создаваемым запросом. Вы также можете импортировать предикат edges из модуля графа путей в одной из стандартных библиотек управления потоком данных.

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

Ниже приведен пример инструкции, которая импортирует модуль pathgraph из библиотеки потока данных (DataFlow.qll), в которой определен edges:

import DataFlow::PathGraph

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

Класс PathNode предназначен для реализации анализа потока данных. Его Node дополнен контекстом вызова (за исключением приемников), пути доступа и конфигурации. Создаются только значения PathNode, которые доступны из источника.

Ниже приведен пример пути импорта:

import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl

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

Анализ базы данных

При использовании запросов для анализа базы данных CodeQL вы получаете значимые результаты в контексте исходного кода. Результаты оформляются как оповещения или пути в SARIF или другом интерпретированном формате.

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

codeql database analyze --format=<format> ---output=<output> [--threads=<num>] [--ram=<MB>] <options>... -- <database> <query|dir|suite>...

Эта команда объединяет эффекты codeql database run-queries и codeql database interpret-results команд сантехники.

Кроме того, можно выполнять запросы, которые не соответствуют требованиям, которые интерпретируются как оповещения исходного кода. Для этого используйте codeql-database run-queries или codeql query run. Затем используйте codeql bqrs decode для преобразования необработанных результатов в читаемую нотацию.

Полный список доступных команд CLI CodeQL можно получить в руководстве по cli CodeQL.

Использование ФАЙЛА SARIF с категориями

CodeQL поддерживает SARIF для совместного использования результатов статического анализа. SARIF предназначен для представления выходных данных широкого спектра статических средств анализа.

Необходимо указать категорию при использовании выходных данных SARIF для анализа CodeQL. Категории могут различать несколько анализов, проводимых в одном репозитории, и на разных языках или в различных частях кода. Однако ФАЙЛЫ SARIF с той же категорией перезаписывают друг друга.

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

Вот один пример. Значение категории отображается (с добавленной косой чертой, если она еще не присутствует) в качестве свойства <run>.automationId в SARIF версии 1, свойства <run>.automationLogicalId в SARIF версии 2 и свойства <run>.automationDetails.id в SARIF версии 2.1.0.

Публикация результатов SARIF в GitHub

После готовности базы данных можно выполнять интерактивный запрос. Кроме того, можно запустить набор запросов, чтобы создать набор результатов в формате SARIF и отправить результаты в целевой репозиторий на GitHub.com:

codeql github upload-results --sarif=<file> [--github-auth-stdin] [--github-url=<url>] [--repository=<repository-name>] [--ref=<ref>] [--commit=<commit>] [--checkout-path=<path>] <options>...

Чтобы передать результаты на GitHub, убедитесь, что на каждом сервере непрерывной интеграции (CI) есть приложение GitHub или личный маркер доступа для используемого интерфейса командной строки CodeQL. Необходимо использовать маркер доступа или приложение GitHub с разрешением на запись security_events.

Вы можете разрешить CLI CodeQL использовать тот же токен, если серверы CI уже используют токен с той же областью для извлечения репозиториев из GitHub. В противном случае создайте новый маркер с разрешением на запись security_events и добавьте этот маркер в хранилище секретов системы CI. Наилучшей практикой по обеспечению безопасности является установка флага --github-auth-stdin и передача токена команде через стандартный ввод.

Отправка результатов SARIF

Чтобы результаты сканирования кода из средства статического анализа, не от компании Microsoft, отображались в вашем репозитории GitHub, ваши результаты должны храниться в файле SARIF, поддерживающем определенное подмножество схемы JSON SARIF 2.1.0. Результаты можно отправить с помощью API сканирования кода или интерфейса командной строки CodeQL.

Каждый раз, когда вы отправляете результаты проверки нового кода, CodeQL обрабатывает результаты и добавляет оповещения в репозиторий. Чтобы предотвратить дублирование оповещений для одной и той же проблемы, сканирование кода использует свойство SARIF partialFingerprints для сопоставления результатов в различных запусках, чтобы они отображались только один раз в последнем запуске для выбранной ветви. Устранение дубликатов позволяет сопоставить оповещения с правильной строкой кода при изменении файлов.

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

Спецификации SARIF используют имя свойства JSON partialFingerprints, в котором словарь сопоставляет именованные типы отпечатков с самими отпечатками. Это свойство содержит, как минимум, значение для primaryLocationLineHash, которое предоставляет отпечаток пальца на основе контекста основного местоположения.

GitHub пытается заполнить поле partialFingerprints из исходных файлов, если вы загружаете файл SARIF с помощью действия upload-sarif и эти данные отсутствуют. Кроме того, если вы отправляете файл SARIF без данных фингерпринтов с помощью API-конечной точки /code-scanning/sarifs, пользователи могут видеть повторяющиеся оповещения при обработке и отображении оповещений проверки кода.

Чтобы избежать повторяющихся оповещений во время работы со статическими средствами анализа, вычислите данные отпечатков пальцев и заполните свойство partialFingerprints перед отправкой ФАЙЛА SARIF. Полезной отправной точкой является использование того же скрипта, что и действие upload-sarif.