Опирается на правила: R-SEC-DEP-1R-SEC-DEP-4 и R-SEC-DEP-X1R-SEC-DEP-X2 из Security Style Guide → раздел 2. CVE в зависимостях.

Важно знать

  • OWASP Dependency-Check сканирует все runtime/test-зависимости против NIST NVD.
  • Запускается на merge в main + nightly + release-tag, не на каждом PR (медленно).
  • NVD_API_KEY обязателен — без ключа NVD-rate-limit убьёт CI.
  • Renovate / Dependabot — auto-PR на minor/patch updates, major — manual review.
  • CVSS ≥ 7.0 (HIGH/CRITICAL) ломает сборку; 4.0-6.9 — отчёт + 30 дней; ниже — игнор.
  • Suppressions с until= обязательны — бессрочное подавление запрещено.
  • Snapshot-зависимости в production — запрещены (неизменяемость артефакта).

Дополнительный класс vulnerability — не в твоём коде, а в библиотеках, которые ты используешь. Log4Shell, Spring4Shell, Jackson deserialization — все «жили» в зависимостях, разработчики не писали уязвимый код, но получили CVE в проде. UCP формулирует обязательный сканер + workflow обновления.

OWASP Dependency-Check

R-SEC-DEP-1: подключение.

plugins {
    id 'org.owasp.dependencycheck' version '11.1.0'
}

dependencyCheck {
    failBuildOnCVSS = 7.0
    formats = ['HTML', 'JSON', 'SARIF']
    suppressionFile = 'config/dependency-check-suppressions.xml'
    nvd {
        apiKey = System.getenv('NVD_API_KEY')
        delay = 16000
    }
    analyzers {
        nodeAuditEnabled = false
        retiredEnabled = true
        assemblyEnabled = false
    }
}

Где запускается — расслоение R-SEC-2:

ЭтапЗапускать DepCheck?Причина
IDE / каждый buildНет5-10 минут на build — невыносимо
Pre-commitНетТо же
PRНетCVE не появляется от твоего PR
Merge в mainДаBaseline обновляется
NightlyДаНовые CVE в существующих deps
Release tagДаФинальная проверка

CVE появляется в NVD, не из твоего PR. Гонять каждый PR — burnрить CI-минуты на то, что меняется раз в неделю.

NVD_API_KEY обязателен

R-SEC-DEP-1: rate limit.

NVD (NIST National Vulnerability Database) — публичная API с rate limit. Без API-key — 5 запросов/30 секунд. Dependency-Check за 1000 зависимостей выкачивает ~200 страниц — без ключа CI висит часами, либо упирается в timeout.

С NVD_API_KEY (бесплатный, получается за минуту на https://nvd.nist.gov/developers/request-an-api-key) — 50 запросов/30 секунд. CI завершается за 2-3 минуты.

- name: Run Dependency-Check
  env:
    NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
  run: ./gradlew dependencyCheckAnalyze

Renovate / Dependabot

R-SEC-DEP-2: автоматические PR на обновления.

# renovate.json
{
  "extends": ["config:base"],
  "schedule": ["before 8am on monday"],
  "labels": ["dependencies"],
  "packageRules": [
    {
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true,
      "automergeType": "pr",
      "platformAutomerge": true
    },
    {
      "matchUpdateTypes": ["major"],
      "automerge": false,
      "labels": ["dependencies", "major-update"]
    },
    {
      "matchPackagePatterns": ["spring-boot", "spring-cloud"],
      "matchUpdateTypes": ["minor"],
      "automerge": false
    }
  ],
  "vulnerabilityAlerts": {
    "enabled": true,
    "labels": ["security"]
  }
}

Что делает:

  • Minor/patch автоматически merge-ятся после прохождения CI.
  • Major — manual review (breaking changes возможны).
  • Spring Boot minor — manual review (часто содержит breaking).
  • Vulnerability alerts — отдельные PR с метками security, приоритет.

Без Renovate зависимости устаревают, CVE накапливаются, через полгода обновление превращается в «mega-migration».

CVSS → действие

R-SEC-DEP-3: severity per CVSS score.

CVSS ScoreSeverityДействие
9.0-10.0CRITICALСборка падает, hotfix < 24h
7.0-8.9HIGHСборка падает, патч в текущем спринте (≤ 2 недели)
4.0-6.9MEDIUMОтчёт, патч ≤ 30 дней
0.1-3.9LOWИгнор, не отображаем

failBuildOnCVSS = 7.0 в gradle config — стандарт.

Релиз блокируется только на новые HIGH+ findings относительно baseline (R-SEC-4). Старый долг (HIGH CVE без патча от upstream) трекается отдельной задачей, не блокирует выпуск — иначе первый протухший CVE остановит pipeline на неделю и команда начнёт игнорировать всю security.

Suppressions с until=

R-SEC-DEP-4: каждая suppression имеет срок.

<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">

    <suppress until="2026-08-01Z">
        <notes>CVE-2024-12345: библиотека foo-utils используется только в test scope, не попадает в production artifact. Ждём fix в foo-utils 2.5.0.</notes>
        <packageUrl regex="true">^pkg:maven/com\.example/foo-utils@.*$</packageUrl>
        <cve>CVE-2024-12345</cve>
    </suppress>

    <suppress until="2026-06-15Z">
        <notes>CVE-2024-67890 в transitive jackson-databind. False positive — мы не deserialize untrusted input. Patch будет в jackson 2.18.</notes>
        <cve>CVE-2024-67890</cve>
    </suppress>

</suppressions>

Правила:

  • until="YYYY-MM-DDZ" — обязательный срок (UTC, ISO 8601).
  • <notes> — объяснение: почему false positive, или когда патч, или почему acceptable risk.
  • <cve> либо <packageUrl> — точечная suppression, не на всю библиотеку.

Без untilR-SEC-DEP-X1 нарушение.

Что запрещено

Бессрочное suppression

R-SEC-DEP-X1:

<!-- ПЛОХО -->
<suppress>
    <cve>CVE-2024-12345</cve>
</suppress>

Через год никто не помнит, почему suppressed. Через два — этот CVE становится exploitable, а в репо «забыли». Каждое подавление обязано иметь срок пересмотра — раз в квартал проходим по просроченным.

Snapshot в production

R-SEC-DEP-X2:

// КАТАСТРОФА
implementation 'com.example:lib:1.5-SNAPSHOT'

-SNAPSHOT версия может измениться без warning — maven repository заменяет binary в любой момент. Production build от 1 января может содержать 1.5-SNAPSHOT от 1 января; rebuild 1 февраля — другой 1.5-SNAPSHOT. Это:

  • Невоспроизводимая сборка — нельзя rebuild старый release.
  • Невозможный rollback — старый 1.5-SNAPSHOT уже не существует в репо.
  • Supply chain attack vector — компрометация репо меняет binary без bump version.

Production — только release-версии (immutable).

Что запрещено — таблица

АнтипаттернПравилоЧто взамен
Suppression без until=R-SEC-DEP-X1срок обязателен
Snapshot в productionR-SEC-DEP-X2только release versions
DepCheck на каждом PRR-SEC-DEP-1merge в main + nightly + release
Без NVD_API_KEYR-SEC-DEP-1бесплатно, обязательно
failBuildOnCVSS отсутствуетR-SEC-DEP-37.0 минимум
Без Renovate / DependabotR-SEC-DEP-2один из двух
Auto-merge major updatesR-SEC-DEP-2major — manual review
Suppression на всю библиотеку (<packageUrl> без <cve>)R-SEC-DEP-4per-CVE, не per-library

Куда дальше

  • Security → раздел 2. CVE в зависимостях — нормативные формулировки.
  • SAST по коду — параллельный слой для кода.
  • Секреты в коде и истории — Gitleaks.
  • Container/image-уязвимости — Trivy сканирует image включая dependencies.
  • Реакция на findings — SLA per severity.
  • Auth → PII и секреты — secrets через Vault, не в build.