feat: подбор угроз — инвертированная логика (все угрозы минус неактуальные)
- threat_rules: по умолчанию актуальны ВСЕ угрозы БДУ ФСТЭК, исключаются заведомо неактуальные: нет интернета → убраны удалённый доступ/веб/почта/ беспроводные/DDoS/облачные/грид; АСУ → убраны BIOS/грид/виртуализация/браузер (теперь 170-200 угроз на объект вместо 15 «самых похожих») - _has_internet уточнён: «Отсутствует» у оператора / «изолирован» / «не требуется» → внешней сети нет; сеть общего пользования или реальный оператор → есть - verify.suggest_threats_ai: свежий перечень ФСТЭК (227 угроз) передаётся в промт, ИИ выбирает из него, а не из устаревших знаний; + человекочитаемая сводка объекта - ui: кнопки программа/ИИ без лимита 20; после подбора угрозы сохраняются в модель (_collect_is) — при открытии словаря галочки выбранных угроз стоят - models.from_dict: фильтрация неизвестных полей вложенных объектов — старые файлы с удалёнными полями (attacker_characteristics) больше не падают
This commit is contained in:
+54
-37
@@ -95,16 +95,30 @@ def _has_internet(isys) -> bool:
|
||||
"""Есть ли подключение к сети Интернет / внешним сетям."""
|
||||
if getattr(isys, 'is_internet', False):
|
||||
return True
|
||||
# По описанию / сетям: «отсутствует подключение к сети Интернет» → нет
|
||||
desc = ((getattr(isys, 'description', '') or '') + ' ' +
|
||||
(getattr(isys, 'net_operator', '') or '')).lower()
|
||||
desc = ((getattr(isys, 'description', '') or '') + ' ').lower()
|
||||
operator = (getattr(isys, 'net_operator', '') or '').lower()
|
||||
net_category = (getattr(isys, 'net_category', '') or '').lower()
|
||||
|
||||
# Явные признаки ОТСУТСТВИЯ внешней сети
|
||||
if 'отсутств' in operator: # оператор «Отсутствует»
|
||||
return False
|
||||
if 'отсутств' in desc and ('интернет' in desc or 'подключ' in desc):
|
||||
return False
|
||||
net_category = (getattr(isys, 'net_category', '') or '').lower()
|
||||
if net_category:
|
||||
if 'не требуется' in desc and ('доменн' in desc or 'интернет' in desc):
|
||||
return False
|
||||
if 'изолирован' in desc:
|
||||
return False
|
||||
|
||||
# Сеть общего пользования — это и есть внешняя сеть (Интернет)
|
||||
if 'общего пользован' in net_category:
|
||||
return True
|
||||
# По умолчанию считаем, что сеть есть (осторожная оценка)
|
||||
return True
|
||||
|
||||
# Указан реальный оператор/провайдер — внешняя связь есть
|
||||
if operator and operator not in ('нет', 'отсутствует', 'не требуется', '-'):
|
||||
return True
|
||||
|
||||
# Консервативно: без явных признаков внешней сети считаем, что её нет
|
||||
return False
|
||||
|
||||
|
||||
def _is_insider(isys) -> bool:
|
||||
@@ -117,8 +131,16 @@ def _score(threat_lower, keywords):
|
||||
return sum(1 for kw in keywords if kw in threat_lower)
|
||||
|
||||
|
||||
def suggest_threats_program(isys, threats=None, limit=15):
|
||||
"""Подбор угроз по характеристикам объекта КИИ.
|
||||
def suggest_threats_program(isys, threats=None, limit=None):
|
||||
"""Подбор угроз по характеристикам объекта КИИ (инвертированная логика).
|
||||
|
||||
По умолчанию актуальны ВСЕ угрозы из перечня (БДУ ФСТЭК).
|
||||
Исключаются только заведомо неактуальные для данного объекта:
|
||||
- нет сети Интернет → убираем угрозы удалённого доступа, веб, почты,
|
||||
беспроводных сетей, DDoS, облачных и т.п.;
|
||||
- объект типа АСУ → убираем угрозы BIOS, грид-систем, виртуализации
|
||||
(у технологического оборудования их, как правило, нет).
|
||||
Такой подход даёт полный список, а не «15 самых похожих».
|
||||
|
||||
Возвращает список строк (с кодами УБИ, если они есть в перечне).
|
||||
"""
|
||||
@@ -130,39 +152,34 @@ def suggest_threats_program(isys, threats=None, limit=15):
|
||||
has_internet = _has_internet(isys)
|
||||
is_asu = _is_asu(isys)
|
||||
is_network = _is_network(isys)
|
||||
insider = _is_insider(isys)
|
||||
|
||||
# Собираем активные наборы ключевых слов
|
||||
active = list(BASE_KEYWORDS)
|
||||
if has_internet:
|
||||
active += INTERNET_KEYWORDS
|
||||
else:
|
||||
active += ISOLATED_KEYWORDS
|
||||
# --- Слова-исключения (если встретились в названии угрозы — она неактуальна) ---
|
||||
exclude = []
|
||||
|
||||
if not has_internet:
|
||||
# Объект изолирован: угрозы, реализуемые только через внешние сети
|
||||
exclude += [
|
||||
'удалённ', 'удаленн', 'дистанционн', 'веб', 'электронн', 'почт',
|
||||
'фишинг', 'беспроводн', 'wi-fi', 'wifi', 'интернет', 'ddos', 'vpn',
|
||||
'облачн', 'грид', 'внешн',
|
||||
]
|
||||
|
||||
if is_asu:
|
||||
active += ASU_KEYWORDS
|
||||
if is_network:
|
||||
active += NETWORK_KEYWORDS
|
||||
if insider:
|
||||
active += INSIDER_KEYWORDS
|
||||
else:
|
||||
active += EXTERNAL_KEYWORDS
|
||||
# АСУ: нет BIOS/виртуализации/браузера в привычном понимании
|
||||
exclude += ['биос', 'грид', 'гипервизор', 'виртуальн', 'браузер']
|
||||
|
||||
scored = []
|
||||
if not is_network and not is_asu:
|
||||
# Обычная ИС: неактуальны чисто сетевые/телеком-угрозы без указания
|
||||
# — оставляем всё, кроме специфики каналов связи, если их нет
|
||||
pass
|
||||
|
||||
result = []
|
||||
for t in threats:
|
||||
tl = str(t).lower()
|
||||
s = _score(tl, active)
|
||||
if s > 0:
|
||||
scored.append((s, t))
|
||||
|
||||
# Сортировка: больше совпадений — выше; убираем дубликаты, сохраняя порядок
|
||||
scored.sort(key=lambda x: -x[0])
|
||||
result = []
|
||||
seen = set()
|
||||
for s, t in scored:
|
||||
if t in seen:
|
||||
if any(kw in tl for kw in exclude):
|
||||
continue
|
||||
seen.add(t)
|
||||
result.append(t)
|
||||
if len(result) >= limit:
|
||||
break
|
||||
|
||||
if limit and len(result) > limit:
|
||||
result = result[:limit]
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user