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:
+29
-13
@@ -474,33 +474,49 @@ def compare_company_values(old_data, new_data):
|
||||
return diffs
|
||||
|
||||
|
||||
def suggest_threats_ai(security_data, api_key, model='deepseek-chat', base_url=None):
|
||||
def suggest_threats_ai(security_data, api_key, model='deepseek-chat', base_url=None,
|
||||
threats=None):
|
||||
"""ИИ предлагает актуальные угрозы БИ для объекта КИИ по его характеристикам.
|
||||
|
||||
security_data — dict: name, description, object_type, sphere, architecture,
|
||||
attacker_category, has_internet (True/False), etc.
|
||||
threats — актуальный перечень угроз БДУ ФСТЭК (список строк «УБИ.xxx …»).
|
||||
Передаётся в промт целиком, чтобы ИИ выбирал из свежего списка,
|
||||
а не из своего устаревшего.
|
||||
|
||||
Возвращает (список_угроз, ошибка).
|
||||
"""
|
||||
if not api_key:
|
||||
return None, "Не задан API-ключ ИИ (Файл → Настройки → API)"
|
||||
internet = 'да' if security_data.get('has_internet', True) else 'нет'
|
||||
|
||||
if threats:
|
||||
threat_list_text = "\n".join(f"{i+1}. {t}" for i, t in enumerate(threats))
|
||||
else:
|
||||
threat_list_text = "(перечень не предоставлен — используй знания об актуальном перечне БДУ ФСТЭК)"
|
||||
|
||||
system = (
|
||||
"Ты — эксперт ФСТЭК по безопасности критической информационной инфраструктуры "
|
||||
"(187-ФЗ, приказ ФСТЭК № 236). На основе характеристик объекта КИИ составь "
|
||||
"перечень АКТУАЛЬНЫХ угроз безопасности информации из БДУ ФСТЭК "
|
||||
"(перечень угроз УБИ.xxx). Верни ТОЛЬКО JSON: "
|
||||
'{"threats": ["УБИ.xxx Название угрозы", ...]} — от 8 до 15 угроз, '
|
||||
"без пояснений и комментариев."
|
||||
"(187-ФЗ, приказ ФСТЭК № 236). На основе характеристик объекта КИИ выбери из "
|
||||
"предоставленного перечня АКТУАЛЬНЫЕ угрозы безопасности информации и верни "
|
||||
"ТОЛЬКО JSON: "
|
||||
'{"threats": ["УБИ.xxx Название угрозы", ...]} — от 10 до 40 угроз, '
|
||||
"без пояснений и комментариев. Не выдумывай угрозы, которых нет в перечне; "
|
||||
"используй полные строки из перечня (код + название) как они есть."
|
||||
)
|
||||
user = (
|
||||
"Характеристики объекта КИИ:\n"
|
||||
f"{json.dumps(security_data, ensure_ascii=False)}\n\n"
|
||||
"Актуальный перечень угроз БДУ ФСТЭК:\n"
|
||||
f"{threat_list_text}"
|
||||
)
|
||||
user = json.dumps(security_data, ensure_ascii=False)
|
||||
js, err = _ai_json(api_key, model, base_url, system, user)
|
||||
if err:
|
||||
return None, err
|
||||
threats = js.get('threats') or []
|
||||
if isinstance(threats, str):
|
||||
threats = [threats]
|
||||
threats = [str(t).strip() for t in threats if str(t).strip()]
|
||||
return threats, None
|
||||
threats_out = js.get('threats') or []
|
||||
if isinstance(threats_out, str):
|
||||
threats_out = [threats_out]
|
||||
threats_out = [str(t).strip() for t in threats_out if str(t).strip()]
|
||||
return threats_out, None
|
||||
|
||||
|
||||
def check_security_ai(security_data, api_key, model='deepseek-chat', base_url=None):
|
||||
|
||||
Reference in New Issue
Block a user