Пиков / КАПО
Как читать авторский курс и нормативные материалы

Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.

П09. VDR и VEX: различие факта и решения

Контекст Эта практика без сканера. Её задача — научиться отличать VDR-факт (машинная связь «компонент ↔ CVE», которую выдал инструмент) от VEX-решения (человеческий вывод о применимости с обоснованием, issuer/владельцем и сроком). На проектах эти два слоя постоянно сваливают в одну кучу: «сканер сказал High — патчим». VEX превращает поток находок в управляемые статусы; кто выпускает VEX и какие evidence нужны, разобрано в VEX в процессе РБПО.

Цель

Взять одну находку из VDR (полученного в П06. Grype поверх готового SBOM или П08. Dependency-Track как портфель SBOM) и оформить поверх неё корректное VEX-решение not_affected в формате CycloneDX — с обоснованием из разрешённого списка justification, автором/issuer и ссылкой на evidence.

Проверяемый результат: валидный VEX-фрагмент, где у находки заполнены analysis.state, analysis.justification, analysis.detail и analysis.response, а affects[].ref указывает на конкретный компонент. Автором решения должна быть ответственная за продукт сторона, а не база уязвимостей или сканер.

Команда или действие

Сначала вычленяем факт из VDR, затем дописываем поверх него решение. jq здесь — только просмотр, не сканер.

# 1. Достать из VDR один факт: id, severity, что затронуто
jq '.vulnerabilities[] | {id, severity: .ratings[0].severity, affects}' vdr.cdx.json

# 2. Оформить VEX-решение руками (это и есть содержание практики)
cat > vex.cdx.json <<'JSON'
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "version": 1,
  "metadata": {
    "authors": [{ "name": "Product Security / Организация" }],
    "component": { "type": "application", "name": "my-product", "version": "1.0.0" }
  },
  "vulnerabilities": [
    {
      "id": "CVE-2022-25883",
      "source": { "name": "NVD", "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-25883" },
      "analysis": {
        "state": "not_affected",
        "justification": "code_not_reachable",
        "detail": "semver вызывается только на доверенном вводе в build-time, в рантайме недостижим; evidence: build log + call graph + issue SEC-123",
        "response": ["will_not_fix"]
      },
      "affects": [{ "ref": "pkg:npm/semver@7.3.7" }]
    }
  ]
}
JSON

# 3. Самопроверка структуры
jq '.metadata.authors[0].name as $issuer | .vulnerabilities[] | {issuer: $issuer, id, state: .analysis.state, just: .analysis.justification}' vex.cdx.json

Разрешённые значения, а не свободный текст state ∈ {resolved, exploitable, in_triage, false_positive, not_affected} (CycloneDX) либо {affected, not_affected, fixed, under_investigation} (модель OpenVEX/SSVC). justification для not_affected — из списка: code_not_present, code_not_reachable, requires_configuration, requires_dependency, requires_environment, protected_by_compiler, protected_at_runtime, protected_at_perimeter, protected_by_mitigating_control. Свободный текст идёт только в detail, не в justification.

Что вы должны увидеть

Шаг 1 (факт из VDR) — без всякого решения:

{ "id": "CVE-2022-25883", "severity": "high", "affects": [{ "ref": "pkg:npm/semver@7.3.7" }] }

Шаг 3 (решение поверх факта) — появился слой analysis и issuer:

{ "issuer": "Product Security / Организация", "id": "CVE-2022-25883", "state": "not_affected", "just": "code_not_reachable" }

Ключевая разница, которую вы должны проговорить: в VDR нет поля analysis вообще — там только факты (id, ratings, affects). VEX добавляет именно analysis (state + justification + detail + response). Один и тот же факт допускает разные VEX в разных продуктах.

Один факт — три решения CVE-2021-44228 (Log4Shell) в log4j-core 2.14.1: - сервис, где класс не на classpath в рантайме → not_affected, justification: code_not_reachable; - сервис на периметре, ещё не обновлён → affected / exploitable, response: ["update"], SLA по severity; - после обновления до 2.17.1 → fixed / resolved. Факт во всех трёх случаях один; различает их триаж.

Если не получилось

Типичные ошибки - not_affected без justification. Это не триаж, а отписка. CycloneDX и здравый смысл требуют обоснование из разрешённого списка; пустой justification = находка не разобрана. - Свободный текст в justification. "мы посмотрели, не страшно" — невалидно. Свободное описание идёт в detail; justification — только из перечня. - affects[].ref не совпадает с bom-ref/PURL компонента. Решение «висит в воздухе»: формально VEX есть, но ни к какому компоненту не привязан. Сверьте ref с PURL из исходного SBOM. - Нет issuer или evidence. VEX без автора решения и доказательств превращается в ручное подавление finding. Укажите ответственную роль и evidence: SBOM, build log, reachability report, triage issue. - Просроченное not_affected. Обоснование приняли для версии 1.2, продукт уехал на 2.0. Решение надо пересмотреть — у not_affected тоже есть срок жизни.

Критерий зачёта

Показать преподавателю: 1. факт из VDR (шаг 1) и VEX-решение поверх него (шаг 3) — рядом, чтобы видна была разница слоёв; 2. валидный justification из разрешённого списка и осмысленный detail; 3. issuer решения и минимум одно evidence, подтверждающее применимость именно к вашему продукту; 4. устно: почему один и тот же VDR-факт может дать разные VEX в разных продуктах; 5. кто владелец этого решения и когда оно подлежит пересмотру (роль, не сканер).

Нормативная связка

VEX в процессе РБПО · М06. Поиск уязвимостей и управление VDR/VEX · CycloneDX ECMA-424 (VEX-расширение) · OpenVEX · CSAF · NIST SP 800-218 SSDF (RV.2 — оценка и реагирование) · Политика управления уязвимостями компонентов · Регламент ретеста после исправления

Смежные практики: П06. Grype поверх готового SBOM · П08. Dependency-Track как портфель SBOM · П35. VEX triage · П10. БДУ ФСТЭК как национальный источник