Справочная система гипотез¶
В этом документе описывается многокритериальная система формирования и проверки гипотез безопасности, используемая для автоматического обнаружения уязвимостей в CodeGraph.
Содержание¶
- Обзор
- Архитектура конвейера
- Основные модели данных
- SecurityHypothesis
- Evidence
- ValidationStatus
- Уровни серьёзности
- Генерация гипотез
- Формат шаблона
- Шаблоны категорий
- Алгоритм генерации
- Сопоставление категорий CWE
- Многокритериальная оценка
- Формула оценки
- Компоненты оценки
- Множители бонусов
- Использование
- Синтез запросов
- Шаблоны SQL
- Примеры шаблонов
- Выполнение гипотез
- Использование исполнителя
- Сбор доказательств
- Проверка
- Процесс проверки
- Результаты проверки
- База знаний
- База данных CWE
- Языковые шаблоны
- Поддерживаемые CWE (частичный список)
- Python API
- Полный пример
- Производительность
- Результаты тестирования
- Проверенные CVE (PostgreSQL 17)
- См. также
Обзор¶
Система гипотез формирует проверяемые гипотезы безопасности, комбинируя:
- Шаблоны уязвимостей CWE (Common Weakness Enumeration — Перечень типовых уязвимостей)
- Шаблоны атак CAPEC (Common Attack Pattern Enumeration — Перечень типовых атак)
- Языковые шаблоны (стоки, источники, средства санации)
- Контекст кодовой базы (на основе анализа CPG)
Архитектура конвейера¶
+-----------------------------------------------------------+
| КОНВЕЙЕР ГИПОТЕЗ |
+-----------------------------------------------------------+
1. ГЕНЕРАЦИЯ
HypothesisGenerator.generate()
+-- База данных CWE (более 120 шаблонов)
+-- База данных CAPEC (более 50 шаблонов атак)
+-- Языковые шаблоны (C, Python, Java)
+-- Декартово произведение: CWE × CAPEC × шаблоны
+-- Инстанцирование шаблонов
+-- Результат: SecurityHypothesis[]
2. ОЦЕНКА
MultiCriteriaScorer.score_batch()
+-- Оценка частоты CWE (вес 0,40)
+-- Оценка схожести атаки (вес 0,30)
+-- Оценка экспозиции кодовой базы (вес 0,30)
+-- Бонусы: наличие известных CVE, критическая серьёзность
+-- Результат: приоритетные оценки [0,0–1,0]
3. СИНТЕЗ ЗАПРОСОВ
QuerySynthesizer.synthesize()
+-- Сопоставление гипотезы с шаблоном SQL
+-- Подстановка параметров
+-- Результат: SQL-запросы DuckDB / PGQ
4. ВЫПОЛНЕНИЕ
HypothesisExecutor.execute()
+-- Выполнение запросов к CPG
+-- Сбор доказательств
+-- Результат: Evidence[]
5. ВАЛИДАЦИЯ
HypothesisValidator.validate()
+-- Анализ доказательств
+-- Обновление статуса гипотезы
+-- Расчёт метрик
+-- Результат: ValidationResults
Основные модели данных¶
SecurityHypothesis¶
Центральная структура данных для анализа безопасности на основе гипотез.
@dataclass
class SecurityHypothesis:
id: str # Уникальный идентификатор
hypothesis_text: str # Читаемое утверждение
# Классификация
cwe_ids: List[str] # ["CWE-120", "CWE-119"]
capec_ids: List[str] # ["CAPEC-100"]
language: str # "C", "Python" и т.д.
category: str # "buffer_overflow", "injection"
# Шаблоны передачи заражённых данных (taint)
source_patterns: List[str] # ["PQgetvalue", "getenv"]
sink_patterns: List[str] # ["strcpy", "memcpy"]
sanitizer_patterns: List[str] # ["strlcpy", "sizeof"]
# Оценки
priority_score: float # 0.0–1.0, общая важность
confidence: float # 0.0–1.0, достоверность гипотезы
# Детализация по нескольким критериям
cwe_frequency_score: float
attack_similarity_score: float
codebase_exposure_score: float
# Сгенерированный SQL-запрос
sql_query: Optional[str]
# Подтверждение
evidence: List[Evidence]
validation_status: ValidationStatus
Evidence¶
Содержит результаты запросов, подтверждающие или опровергающие гипотезу.
@dataclass
class Evidence:
id: str
hypothesis_id: str
query_executed: str # SQL-запрос, который нашёл это
result_count: int
findings: List[Dict[str, Any]] # Результаты запроса
filename: Optional[str]
line_number: Optional[int]
code_snippet: Optional[str]
confidence: float # 0.0–1.0
ValidationStatus¶
class ValidationStatus(Enum):
PENDING = "pending"
IN_PROGRESS = "in_progress"
CONFIRMED = "confirmed"
REJECTED = "rejected"
INCONCLUSIVE = "inconclusive"
Уровни серьёзности¶
class Severity(Enum):
CRITICAL = "critical"
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
INFO = "info"
Генерация гипотез¶
Формат шаблона¶
Гипотезы следуют шаблону:
"Если [источник] передаёт данные в [приёмник] без [средства очистки], то [CWE] позволяет осуществить [атаку]"
Шаблоны категорий¶
| Категория | Шаблон |
|---|---|
| buffer_overflow | “Если недоверённые данные из {sources} передаются в {sinks} без проверки границ через {sanitizers}, то {cwe} позволяет осуществить атаку {attack}, потенциально приводящую к повреждению памяти или выполнению кода.” |
| sql_injection | “Если пользовательский ввод из {sources} включается в SQL-запросы через {sinks} без параметризации ({sanitizers}), то {cwe} позволяет осуществить атаку {attack}.” |
| command_injection | “Если недоверённые данные из {sources} передаются в выполнение команд через {sinks} без надлежащего экранирования ({sanitizers}), то {cwe} позволяет осуществить атаку {attack}.” |
| information_disclosure | “Если к конфиденциальным данным осуществляется доступ через {sinks} без проверки авторизации ({sanitizers}), то {cwe} позволяет осуществить атаку {attack}.” |
Алгоритм генерации¶
from src.security.hypothesis import HypothesisGenerator
generator = HypothesisGenerator()
# Генерация для конкретного CWE {#generate-for-specific-cwe}
hypotheses = generator.generate(
language="C",
cwe_filter=["CWE-120", "CWE-78"],
max_hypotheses=50
)
# Генерация по категории {#generate-for-category}
buffer_hypotheses = generator.generate_by_category("buffer_overflow")
# Полное перечисление {#full-enumeration}
all_hypotheses = generator.generate_all(language="C")
Сопоставление CWE и категорий¶
| CWE | Категория |
|---|---|
| CWE-120, CWE-119, CWE-787, CWE-125 | buffer_overflow |
| CWE-78, CWE-77, CWE-88 | command_injection |
| CWE-89 | sql_injection |
| CWE-94, CWE-95 | code_injection |
| CWE-134 | format_string |
| CWE-200, CWE-209, CWE-862 | information_disclosure |
| CWE-416 | use_after_free |
| CWE-190, CWE-191 | integer_overflow |
Многокритериальная оценка¶
Формула оценки¶
Приоритет = (Частота_CWE × 0.40)
+ (Схожесть_атаки × 0.30)
+ (Экспозиция_кода × 0.30)
Компоненты оценки¶
| Компонент | Вес | Описание |
|---|---|---|
| Частота CWE | 0.40 | Насколько часто данный CWE встречается в базе CVE |
| Схожесть атаки | 0.30 | Насколько атака похожа на известные шаблоны атак |
| Экспозиция кодовой базы | 0.30 | Насколько широко кодовая база подвержена воздействию |
Бонусные множители¶
| Бонус | Множитель | Условие |
|---|---|---|
| Известный CVE | 1.20 (+20%) | Соответствует известному шаблону CVE |
| Критическая серьёзность | 1.10 (+10%) | CWE критической степени серьёзности |
| Недавнее использование | 1.15 (+15%) | Недавно использовался в реальных атаках |
Использование¶
from src.security.hypothesis import MultiCriteriaScorer, CodebaseStats
# Сбор статистики по кодовой базе {#gather-codebase-statistics}
stats = CodebaseStats(
total_methods=52000,
total_calls=110000,
sink_counts={"strcpy": 150, "memcpy": 800},
source_counts={"getenv": 50, "recv": 30}
)
# Оценка гипотез {#score-hypotheses}
scorer = MultiCriteriaScorer(weights={
'cwe_frequency': 0.40,
'attack_similarity': 0.30,
'codebase_exposure': 0.30
})
scored_hypotheses = scorer.score_batch(hypotheses, stats)
# Получение наиболее приоритетных {#get-top-priority}
top_10 = sorted(scored_hypotheses, key=lambda h: h.priority_score, reverse=True)[:10]
Синтез запросов¶
Шаблоны SQL¶
Система генерирует запросы DuckDB SQL для каждой категории гипотез:
from src.security.hypothesis import QuerySynthesizer
synthesizer = QuerySynthesizer()
query = synthesizer.synthesize_query(hypothesis)
Примеры шаблонов¶
Обнаружение переполнения буфера:
SELECT DISTINCT nc.id, nc.name AS sink_function, nc.code,
nc.filename, nc.line_number
FROM nodes_call nc
WHERE nc.name IN ('strcpy', 'strcat', 'sprintf', 'memcpy')
LIMIT 100;
Обнаружение инъекции команд:
SELECT DISTINCT nc.id, nc.name AS sink_function, nc.code,
nc.filename, nc.line_number
FROM nodes_call nc
WHERE nc.name IN ('system', 'popen', 'execl', 'execv')
LIMIT 100;
Анализ потока данных с использованием SQL/PGQ:
FROM GRAPH_TABLE(cpg
MATCH (src:IDENTIFIER)-[:REACHING_DEF*1..5]->(sink:CALL_NODE)
WHERE src.name IN ('user_input', 'request')
AND sink.name IN ('execute', 'query')
COLUMNS (
src.name AS source_var,
sink.name AS sink_function,
sink.filename,
sink.line_number
)
)
LIMIT 100;
Выполнение гипотезы¶
Использование исполнителя¶
from src.security.hypothesis import HypothesisExecutor
import duckdb
conn = duckdb.connect("cpg.duckdb")
executor = HypothesisExecutor(conn)
# Выполнить одну гипотезу {#execute-single-hypothesis}
evidence = executor.execute(hypothesis)
# Выполнить пакетно {#execute-batch}
results = executor.execute_batch(hypotheses, parallel=True)
Сбор доказательств¶
Для каждого выполняемого запроса: 1. Выполнить SQL-запрос к CPG 2. Зафиксировать количество результатов и найденные фрагменты 3. Извлечь имя файла, номер строки, фрагмент кода 4. Рассчитать уровень достоверности доказательства 5. Связать доказательства с гипотезой
Валидация¶
Процесс валидации¶
from src.security.hypothesis import HypothesisValidator
validator = HypothesisValidator()
# Валидация одной гипотезы {#validate-single-hypothesis}
validator.validate(hypothesis)
# Валидация пакета {#validate-batch}
results = validator.validate_batch(hypotheses)
Результаты валидации¶
@dataclass
class ValidationResults:
batch_id: str
total_hypotheses: int
executed_queries: int
# Метрики обнаружения CVE
cves_found: List[str]
cves_missed: List[str]
# Точность/полнота
true_positives: int
false_positives: int
false_negatives: int
# Качество гипотез
confirmed_hypotheses: int
rejected_hypotheses: int
inconclusive_hypotheses: int
# Вычисляемые метрики
@property
def detection_rate(self) -> float: ...
@property
def precision(self) -> float: ...
@property
def recall(self) -> float: ...
@property
def f1_score(self) -> float: ...
База знаний¶
База данных CWE¶
from src.security.hypothesis import get_knowledge_base
kb = get_knowledge_base()
# Получение записи CWE {#get-cwe-entry}
cwe = kb.get_cwe("CWE-120")
print(f"Название: {cwe.name}")
print(f"Серьёзность: {cwe.severity}")
print(f"CVSS: {cwe.cvss_base}")
# Получение по категории {#get-by-category}
memory_cwes = kb.get_cwes_by_category("memory")
# Получение связанных CAPEC {#get-related-capecs}
capecs = kb.get_capecs_for_cwe("CWE-120")
Языковые паттерны¶
# Получение паттернов для C {#get-c-patterns}
c_patterns = kb.get_language_patterns("C")
for pattern in c_patterns:
print(f"Категория: {pattern.category}")
print(f"Приёмники: {pattern.sinks}")
print(f"Источники: {pattern.sources}")
print(f"Санитайзеры: {pattern.sanitizers}")
Поддерживаемые CWE (частичный список)¶
| CWE ID | Название | Серьёзность | CVSS |
|---|---|---|---|
| CWE-120 | Копирование буфера без проверки размера | ВЫСОКАЯ | 8.0 |
| CWE-119 | Недостаточное ограничение операций | ВЫСОКАЯ | 8.0 |
| CWE-78 | Инъекция команд ОС | КРИТИЧЕСКАЯ | 9.8 |
| CWE-89 | SQL-инъекция | КРИТИЧЕСКАЯ | 9.8 |
| CWE-200 | Раскрытие конфиденциальной информации | СРЕДНЯЯ | 5.3 |
| CWE-416 | Использование после освобождения | ВЫСОКАЯ | 8.1 |
| CWE-190 | Переполнение целого числа | ВЫСОКАЯ | 7.5 |
Python API¶
Полный пример¶
from src.security.hypothesis import (
HypothesisGenerator,
MultiCriteriaScorer,
QuerySynthesizer,
HypothesisExecutor,
HypothesisValidator,
CodebaseStats
)
import duckdb
# 1. Подключение к CPG {#1-connect-to-cpg}
conn = duckdb.connect("cpg.duckdb")
# 2. Сбор статистики по кодовой базе {#2-gather-codebase-statistics}
stats = CodebaseStats(
total_methods=conn.execute("SELECT COUNT(*) FROM nodes_method").fetchone()[0],
total_calls=conn.execute("SELECT COUNT(*) FROM nodes_call").fetchone()[0]
)
# 3. Генерация гипотез {#3-generate-hypotheses}
generator = HypothesisGenerator()
hypotheses = generator.generate(language="C", max_hypotheses=100)
# 4. Оценка и приоритизация {#4-score-and-prioritize}
scorer = MultiCriteriaScorer()
scored = scorer.score_batch(hypotheses, stats)
# 5. Генерация SQL-запросов {#5-synthesize-sql-queries}
synthesizer = QuerySynthesizer()
for h in scored:
h.sql_query = synthesizer.synthesize_query(h)
# 6. Выполнение запросов к CPG {#6-execute-against-cpg}
executor = HypothesisExecutor(conn)
for h in scored[:20]: # Топ-20
evidence = executor.execute(h)
h.evidence.extend(evidence)
# 7. Проверка и отчёт {#7-validate-and-report}
validator = HypothesisValidator()
results = validator.validate_batch(scored)
print(f"Частота обнаружения: {results.detection_rate:.1%}")
print(f"Точность: {results.precision:.1%}")
print(f"Полнота: {results.recall:.1%}")
print(f"F1-мера: {results.f1_score:.2f}")
Производительность¶
Результаты тестирования¶
| Метрика | Значение |
|---|---|
| Уровень обнаружения уязвимостей CVE | 100% (3 из 3 целевых CVE) |
| Уровень подтверждения гипотез | 55% |
| Среднее время запроса | 2–3 мс |
| Время генерации (100 гипотез) | <1 с |
| Время выполнения (20 гипотез) | <30 с |
Подтверждённые уязвимости CVE (PostgreSQL 17)¶
| CVE | Тип | Метод обнаружения |
|---|---|---|
| CVE-2025-8713 | Раскрытие статистики | Гипотеза + метод |
| CVE-2025-8714 | Инъекция в pg_dump | На основе метода |
| CVE-2025-8715 | Инъекция символа новой строки | На основе метода |
См. также¶
- Руководство по экспорту CPG — экспорт CPG для анализа
- Кулинарная книга SQL-запросов — примеры запросов
- Модули анализа — документация по расширенному анализу
- База данных CWE
- База данных CAPEC