feat: ⚡ автозаполнение вкладки «Безопасность» по данным объекта
Новая кнопка «⚡ Автозаполнить» в панели действий — заполняет пустые поля
логически, без выдумок:
- категория нарушителя: есть интернет → внешний, нет → внутренний
- уровень возможностей: Н1 (внутренний) / Н2 (внешний)
- виды нарушителей: по категории из словаря attacker_types.json
- угрозы: подбор программой (скоринг по характеристикам объекта)
- инциденты: выводятся из подобранных угроз по ключевым словам
- орг. меры: базовый набор (контролируемая зона, доступ, документы,
ответственные, обучение, инциденты, перечень лиц)
- тех. меры: базовые + доп. по средствам защиты объекта (СЗИ:
межсетевой экран → МЭ, антивирус, СОВ, СКЗИ, виртуализация)
Незаполненное пользователем не перезаписывает.
This commit is contained in:
@@ -205,3 +205,140 @@ def suggest_threats_program(isys, threats=None, limit=None):
|
|||||||
if limit and len(result) > limit:
|
if limit and len(result) > limit:
|
||||||
result = result[:limit]
|
result = result[:limit]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# Автозаполнение вкладки «Безопасность» по данным объекта (логическое)
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
|
# Ключевые слова: угроза → тип инцидента (словарь incidents.json)
|
||||||
|
INCIDENT_RULES = [
|
||||||
|
('отказ в обслуживании', 'отказ в обслуживании'),
|
||||||
|
('несанкционированн', 'несанкционированный доступ'),
|
||||||
|
('утечк', 'утечка данных (нарушение конфиденциальности)'),
|
||||||
|
('модификац', 'модификация (подмена) данных'),
|
||||||
|
('подмен', 'модификация (подмена) данных'),
|
||||||
|
('функционирован', 'нарушение функционирования технических средств'),
|
||||||
|
('техническ', 'нарушение функционирования технических средств'),
|
||||||
|
('использован', 'несанкционированное использование вычислительных ресурсов объекта'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Базовый набор орг. мер (всегда актуальны для значимого объекта)
|
||||||
|
BASE_ORG_MEASURES = [
|
||||||
|
'Установление контролируемой зоны',
|
||||||
|
'Контроль физического доступа к объекту',
|
||||||
|
'Разработка документов (регламентов, инструкций, руководств) по обеспечению безопасности объекта',
|
||||||
|
'Назначение ответственных за обеспечение безопасности объекта',
|
||||||
|
'Обучение и инструктаж персонала',
|
||||||
|
'Регламентация действий при компьютерных инцидентах',
|
||||||
|
'Утверждение перечня лиц, имеющих доступ к объекту',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Базовый набор тех. мер
|
||||||
|
BASE_TECH_MEASURES = [
|
||||||
|
'Идентификация и аутентификация пользователей',
|
||||||
|
'Управление доступом',
|
||||||
|
'Ограничение программной среды',
|
||||||
|
'Антивирусная защита',
|
||||||
|
'Защита информации от несанкционированного доступа (СЗИ от НСД)',
|
||||||
|
'Регистрация и мониторинг событий безопасности',
|
||||||
|
'Резервное копирование и восстановление',
|
||||||
|
'Защита технических средств и линий связи',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Средства защиты → доп. тех. меры
|
||||||
|
DEFENSE_TOOL_MEASURES = [
|
||||||
|
('межсетев', 'Межсетевое экранирование'),
|
||||||
|
('firewall', 'Межсетевое экранирование'),
|
||||||
|
('сетев', 'Межсетевое экранирование'),
|
||||||
|
('обнаруж', 'Обнаружение вторжений (СОВ)'),
|
||||||
|
('ids', 'Обнаружение вторжений (СОВ)'),
|
||||||
|
('ips', 'Обнаружение вторжений (СОВ)'),
|
||||||
|
('криптограф', 'Криптографическая защита информации (СКЗИ)'),
|
||||||
|
('vipnet', 'Криптографическая защита информации (СКЗИ)'),
|
||||||
|
('континент', 'Криптографическая защита информации (СКЗИ)'),
|
||||||
|
('виртуализ', 'Защита среды виртуализации'),
|
||||||
|
('vmware', 'Защита среды виртуализации'),
|
||||||
|
('hyper-v', 'Защита среды виртуализации'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def auto_fill_security(isys, threats=None):
|
||||||
|
"""Логическое автозаполнение вкладки «Безопасность» по данным объекта КИИ.
|
||||||
|
|
||||||
|
Заполняет (только если поле пустое):
|
||||||
|
attacker_category — по наличию интернета (внешний/внутренний нарушитель);
|
||||||
|
attacker_level — Н1/Н2 (внутренний — базовые, внешний — базовые повышенные);
|
||||||
|
attacker_types — виды нарушителей по категории/интернету;
|
||||||
|
threats — подбор программой (скоринг по характеристикам);
|
||||||
|
incidents — типы инцидентов, выводимые из подобранных угроз;
|
||||||
|
org_measures / tech_measures — базовый набор + по СЗИ объекта.
|
||||||
|
|
||||||
|
Возвращает dict {поле: новое_значение} только для пустых полей.
|
||||||
|
"""
|
||||||
|
from .models import InformationSystem
|
||||||
|
res = {}
|
||||||
|
|
||||||
|
has_internet = _has_internet(isys)
|
||||||
|
|
||||||
|
# 1. Категория нарушителя
|
||||||
|
if not (getattr(isys, 'attacker_category', '') or '').strip():
|
||||||
|
res['attacker_category'] = 'Внешний нарушитель' if has_internet else 'Внутренний нарушитель'
|
||||||
|
|
||||||
|
# 2. Уровень возможностей
|
||||||
|
if not (getattr(isys, 'attacker_level', '') or '').strip():
|
||||||
|
res['attacker_level'] = 'Н2 — Базовые повышенные возможности' if has_internet else 'Н1 — Базовые возможности'
|
||||||
|
|
||||||
|
# 3. Виды нарушителей
|
||||||
|
if not (getattr(isys, 'attacker_types', '') or '').strip():
|
||||||
|
if has_internet:
|
||||||
|
types = [
|
||||||
|
'Отдельные физические лица (хакеры)',
|
||||||
|
'Преступные группы (криминальные структуры)',
|
||||||
|
'Конкурирующие организации',
|
||||||
|
'Авторизованные пользователи систем и сетей',
|
||||||
|
'Системные администраторы и администраторы безопасности',
|
||||||
|
'Бывшие (уволенные) работники (пользователи)',
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
types = [
|
||||||
|
'Авторизованные пользователи систем и сетей',
|
||||||
|
'Системные администраторы и администраторы безопасности',
|
||||||
|
'Бывшие (уволенные) работники (пользователи)',
|
||||||
|
'Лица, обеспечивающие функционирование систем и сетей или обеспечивающих систем оператора (администрация, охрана, уборщики и др.)',
|
||||||
|
]
|
||||||
|
res['attacker_types'] = '\n'.join(types)
|
||||||
|
|
||||||
|
# 4. Угрозы — подбор программой
|
||||||
|
if not (getattr(isys, 'threats', '') or '').strip():
|
||||||
|
prog = suggest_threats_program(isys, threats=threats)
|
||||||
|
if prog:
|
||||||
|
res['threats'] = '\n'.join(prog)
|
||||||
|
|
||||||
|
# 5. Инциденты — из подобранных угроз
|
||||||
|
if not (getattr(isys, 'incidents', '') or '').strip():
|
||||||
|
threats_text = res.get('threats') or (getattr(isys, 'threats', '') or '')
|
||||||
|
if threats_text:
|
||||||
|
incidents = []
|
||||||
|
low = threats_text.lower()
|
||||||
|
for kw, incident in INCIDENT_RULES:
|
||||||
|
if kw in low and incident not in incidents:
|
||||||
|
incidents.append(incident)
|
||||||
|
if incidents:
|
||||||
|
res['incidents'] = '\n'.join(incidents)
|
||||||
|
|
||||||
|
# 6. Орг. меры — базовый набор
|
||||||
|
if not (getattr(isys, 'org_measures', '') or '').strip():
|
||||||
|
res['org_measures'] = '\n'.join(BASE_ORG_MEASURES)
|
||||||
|
|
||||||
|
# 7. Тех. меры — базовые + по СЗИ объекта
|
||||||
|
if not (getattr(isys, 'tech_measures', '') or '').strip():
|
||||||
|
tech = list(BASE_TECH_MEASURES)
|
||||||
|
defense = ' '.join(getattr(isys, 'defense_tools_list', []) or [])
|
||||||
|
dlow = defense.lower()
|
||||||
|
for kw, measure in DEFENSE_TOOL_MEASURES:
|
||||||
|
if kw in dlow and measure not in tech:
|
||||||
|
tech.append(measure)
|
||||||
|
res['tech_measures'] = '\n'.join(tech)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|||||||
@@ -980,6 +980,8 @@ class DokoGenApp:
|
|||||||
# --- Панель действий (сверху, всегда видна) ---
|
# --- Панель действий (сверху, всегда видна) ---
|
||||||
sec_actions = ttk.Frame(sec_frame)
|
sec_actions = ttk.Frame(sec_frame)
|
||||||
sec_actions.pack(fill=tk.X, pady=(0, 6))
|
sec_actions.pack(fill=tk.X, pady=(0, 6))
|
||||||
|
ttk.Button(sec_actions, text="⚡ Автозаполнить",
|
||||||
|
command=self._auto_fill_security_click).pack(side=tk.LEFT, padx=2)
|
||||||
ttk.Button(sec_actions, text="⬇️ Загрузить угрозы ФСТЭК",
|
ttk.Button(sec_actions, text="⬇️ Загрузить угрозы ФСТЭК",
|
||||||
command=self._download_fstec_threats).pack(side=tk.LEFT, padx=2)
|
command=self._download_fstec_threats).pack(side=tk.LEFT, padx=2)
|
||||||
ttk.Button(sec_actions, text="⚙️ Подобрать угрозы (программа)",
|
ttk.Button(sec_actions, text="⚙️ Подобрать угрозы (программа)",
|
||||||
@@ -2047,6 +2049,63 @@ class DokoGenApp:
|
|||||||
text="⚠ Список угроз ещё не скачан — нажмите «⬇️ Загрузить угрозы ФСТЭК»",
|
text="⚠ Список угроз ещё не скачан — нажмите «⬇️ Загрузить угрозы ФСТЭК»",
|
||||||
foreground='#c62828')
|
foreground='#c62828')
|
||||||
|
|
||||||
|
def _auto_fill_security_click(self):
|
||||||
|
"""⚡ Автозаполнение вкладки «Безопасность» по данным объекта (логическое).
|
||||||
|
|
||||||
|
Заполняет только пустые поля:
|
||||||
|
категория/уровень/виды нарушителя — по интернету и типу объекта;
|
||||||
|
угрозы — подбор программой (скоринг);
|
||||||
|
инциденты — из подобранных угроз;
|
||||||
|
орг./тех. меры — базовый набор + по средствам защиты объекта.
|
||||||
|
"""
|
||||||
|
if self._current_is_idx is None:
|
||||||
|
messagebox.showinfo("Автозаполнение", "Сначала выберите объект КИИ в списке слева")
|
||||||
|
return
|
||||||
|
self._collect_is()
|
||||||
|
isys = self.model.information_systems[self._current_is_idx]
|
||||||
|
try:
|
||||||
|
from .threat_rules import auto_fill_security, load_threats
|
||||||
|
threats_full = load_threats()
|
||||||
|
fill = auto_fill_security(isys, threats=threats_full)
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("Ошибка", str(e))
|
||||||
|
return
|
||||||
|
if not fill:
|
||||||
|
messagebox.showinfo("Автозаполнение", "Все поля безопасности уже заполнены.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Применяем к виджетам
|
||||||
|
if 'attacker_category' in fill and hasattr(self, 'is_attacker_category_combo'):
|
||||||
|
self.is_attacker_category_combo.set(fill['attacker_category'])
|
||||||
|
if 'attacker_level' in fill and hasattr(self, 'is_attacker_level_combo'):
|
||||||
|
self.is_attacker_level_combo.set(fill['attacker_level'])
|
||||||
|
for key, attr in [('attacker_types', 'is_attacker_types_listbox'),
|
||||||
|
('threats', 'is_threats_listbox'),
|
||||||
|
('incidents', 'is_incidents_listbox'),
|
||||||
|
('org_measures', 'is_org_measures_listbox'),
|
||||||
|
('tech_measures', 'is_tech_measures_listbox')]:
|
||||||
|
if key in fill and hasattr(self, attr):
|
||||||
|
lb = getattr(self, attr)
|
||||||
|
lb.delete(0, tk.END)
|
||||||
|
for line in fill[key].split('\n'):
|
||||||
|
if line.strip():
|
||||||
|
lb.insert(tk.END, line.strip())
|
||||||
|
|
||||||
|
self._collect_is() # сохранить в модель
|
||||||
|
filled = ', '.join({
|
||||||
|
'attacker_category': 'нарушитель',
|
||||||
|
'attacker_level': 'уровень',
|
||||||
|
'attacker_types': 'виды нарушителя',
|
||||||
|
'threats': 'угрозы',
|
||||||
|
'incidents': 'инциденты',
|
||||||
|
'org_measures': 'орг. меры',
|
||||||
|
'tech_measures': 'тех. меры',
|
||||||
|
}.get(k, k) for k in fill)
|
||||||
|
self.log(f"⚡ Автозаполнение выполнено: {filled}")
|
||||||
|
messagebox.showinfo("Автозаполнение",
|
||||||
|
f"Заполнено: {filled}.\n\nНезаполненные поля (если есть) требуют ручного ввода "
|
||||||
|
f"или данных из опросника.")
|
||||||
|
|
||||||
def _suggest_threats_program_click(self):
|
def _suggest_threats_program_click(self):
|
||||||
"""Подобрать угрозы логикой программы по характеристикам объекта."""
|
"""Подобрать угрозы логикой программы по характеристикам объекта."""
|
||||||
if self._current_is_idx is None:
|
if self._current_is_idx is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user