Опирается на правила:
R-SEC-DEP-1…R-SEC-DEP-4иR-SEC-DEP-X1…R-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 Score | Severity | Действие |
|---|---|---|
| 9.0-10.0 | CRITICAL | Сборка падает, hotfix < 24h |
| 7.0-8.9 | HIGH | Сборка падает, патч в текущем спринте (≤ 2 недели) |
| 4.0-6.9 | MEDIUM | Отчёт, патч ≤ 30 дней |
| 0.1-3.9 | LOW | Игнор, не отображаем |
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, не на всю библиотеку.
Без until — R-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 в production | R-SEC-DEP-X2 | только release versions |
| DepCheck на каждом PR | R-SEC-DEP-1 | merge в main + nightly + release |
Без NVD_API_KEY | R-SEC-DEP-1 | бесплатно, обязательно |
failBuildOnCVSS отсутствует | R-SEC-DEP-3 | 7.0 минимум |
| Без Renovate / Dependabot | R-SEC-DEP-2 | один из двух |
| Auto-merge major updates | R-SEC-DEP-2 | major — manual review |
Suppression на всю библиотеку (<packageUrl> без <cve>) | R-SEC-DEP-4 | per-CVE, не per-library |
Куда дальше
- Security → раздел 2. CVE в зависимостях — нормативные формулировки.
- SAST по коду — параллельный слой для кода.
- Секреты в коде и истории — Gitleaks.
- Container/image-уязвимости — Trivy сканирует image включая dependencies.
- Реакция на findings — SLA per severity.
- Auth → PII и секреты — secrets через Vault, не в build.