Тех. меры: только при присвоенной категории и по факту СЗИ (без СЗИ нет «Регистрации и мониторинга»/«Антивируса»); промт СЗИ: при «без категории» — базовый минимум + провести категорирование, переданы характеристики объекта (интернет/ПО/архитектура); показатель 10 и 10.1–10.7: авторасчёт по методичке ФСТЭК (операции за год / дни) и порогам ПП-127
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"system": "Ты — эксперт по безопасности критической информационной инфраструктуры (187-ФЗ, приказ ФСТЭК России № 239 и № 236). По категории значимости объекта КИИ, актуальным угрозам и уже выбранным средствам защиты информации (СЗИ) определи, каких средств не хватает, и дай рекомендации. Учитывай требования по категориям: для I категории — максимальный набор (антивирус, СКЗИ, SIEM, межсетевые экраны, средства анти-APT и т.д.), для II — расширенный набор, для III — базовый набор. Выбирай СЗИ ТОЛЬКО из реально существующих классов средств защиты (антивирусная защита, СКЗИ, межсетевой экран, SIEM, DLP, IDS/IPS, средства доверенной загрузки, контроля целостности, управления доступом и т.п.).",
|
||||
"system": "Ты — эксперт по безопасности критической информационной инфраструктуры (187-ФЗ, приказ ФСТЭК России № 239 и № 236). По категории значимости объекта КИИ, характеристикам объекта, актуальным угрозам и уже выбранным средствам защиты информации (СЗИ) определи, каких средств не хватает, и дай рекомендации. Обязательно учитывай следующее:\n1) КАТЕГОРИЯ ЗНАЧИМОСТИ: если категория «без категории», «—», пусто или не присвоена — объект НЕ является значимым объектом КИИ, полный набор СЗИ по приказу № 239 для него НЕ требуется. В этом случае рекомендую только минимальный базовый набор (антивирусная защита, резервное копирование, управление доступом) и главный совет — провести категорирование объекта. НЕ перечисляй средства для I категории (СКЗИ, SIEM, анти-APT, доверенная загрузка и т.п.), если категория не присвоена. Для I категории — максимальный набор, для II — расширенный, для III — базовый набор по приказу № 239.\n2) ХАРАКТЕРИСТИКИ ОБЪЕКТА: внимательно читай переданные характеристики (наличие интернета, архитектура, ПО, тип объекта). НЕ рекомендуй СЗИ для технологий, которых нет у объекта: нет интернета/внешних сетей → не рекомендуй DDoS-защиту, VPN, веб-защиту, защиту от удалённых атак из интернета; нет виртуализации/контейнеров → не рекомендуй защиту виртуальной инфраструктуры и контейнеров; нет мобильных устройств → не рекомендуй защиту мобильных; объект не АСУ ТП → не рекомендуй защиту АСУ ТП; нет гостайны → не рекомендуй средства для гостайны. Отмечай только реально применимые классы СЗИ.\n3) ОБЪЁМ: максимум 5–7 рекомендаций, только самые важные для данной категории и объекта. Если текущий набор СЗИ достаточен — верни пустой список рекомендаций и «достаточно»: true.\nВыбирай СЗИ ТОЛЬКО из реально существующих классов средств защиты (антивирусная защита, СКЗИ, межсетевой экран, SIEM, DLP, IDS/IPS, средства доверенной загрузки, контроля целостности, управления доступом и т.п.).",
|
||||
"response_format": "Верни ТОЛЬКО JSON: {\"рекомендации\": [{\"сзи\": \"название класса/средства\", \"зачем\": \"для чего нужно\"}], \"общие_советы\": [\"...\"], \"достаточно\": true|false}. Поле «достаточно» — true, если текущий набор СЗИ покрывает требования категории. Не придумывай конкретные торговые марки, если их нет в списке — указывай класс средства."
|
||||
}
|
||||
|
||||
@@ -144,6 +144,11 @@ class Company:
|
||||
vso: str = "" # Снижение выплат сторонним организациям ΔВСО (руб.)
|
||||
ns: str = "" # Снижение сборов ΔНС (руб.)
|
||||
|
||||
# Показатель 10 (прекращение финансовых операций): операции за год (млн ед.)
|
||||
ops_count: str = "" # Количество операций за прошедший год (млн ед.)
|
||||
calendar_days: str = "" # Количество календарных дней в году (по умолчанию 365)
|
||||
criterion10_value: str = "" # Значение показателя 10.1–10.7 (в своих единицах)
|
||||
|
||||
# Списки
|
||||
commission: List[CommissionMember] = field(default_factory=list)
|
||||
information_systems: List[InformationSystem] = field(default_factory=list)
|
||||
|
||||
+35
-13
@@ -298,19 +298,18 @@ BASE_ORG_MEASURES = [
|
||||
'Утверждение перечня лиц, имеющих доступ к объекту',
|
||||
]
|
||||
|
||||
# Базовый набор тех. мер
|
||||
# Базовый набор тех. мер — только универсальные, не требующие конкретных СЗИ.
|
||||
# Меры, зависящие от средств защиты (антивирус, СЗИ от НСД, регистрация событий
|
||||
# и т.п.), добавляются отдельно по факту наличия СЗИ (DEFENSE_TOOL_MEASURES).
|
||||
BASE_TECH_MEASURES = [
|
||||
'Идентификация и аутентификация пользователей',
|
||||
'Управление доступом',
|
||||
'Ограничение программной среды',
|
||||
'Антивирусная защита',
|
||||
'Защита информации от несанкционированного доступа (СЗИ от НСД)',
|
||||
'Регистрация и мониторинг событий безопасности',
|
||||
'Резервное копирование и восстановление',
|
||||
'Защита технических средств и линий связи',
|
||||
]
|
||||
|
||||
# Средства защиты → доп. тех. меры
|
||||
# Средства защиты → доп. тех. меры (по факту наличия СЗИ у объекта)
|
||||
DEFENSE_TOOL_MEASURES = [
|
||||
('межсетев', 'Межсетевое экранирование'),
|
||||
('firewall', 'Межсетевое экранирование'),
|
||||
@@ -324,6 +323,23 @@ DEFENSE_TOOL_MEASURES = [
|
||||
('виртуализ', 'Защита среды виртуализации'),
|
||||
('vmware', 'Защита среды виртуализации'),
|
||||
('hyper-v', 'Защита среды виртуализации'),
|
||||
('антивирус', 'Антивирусная защита'),
|
||||
('kaspersky', 'Антивирусная защита'),
|
||||
('eset', 'Антивирусная защита'),
|
||||
('dr.web', 'Антивирусная защита'),
|
||||
('аваст', 'Антивирусная защита'),
|
||||
('avast', 'Антивирусная защита'),
|
||||
('сзи', 'Защита информации от несанкционированного доступа (СЗИ от НСД)'),
|
||||
('от нсд', 'Защита информации от несанкционированного доступа (СЗИ от НСД)'),
|
||||
('dallas', 'Защита информации от несанкционированного доступа (СЗИ от НСД)'),
|
||||
('secret net', 'Защита информации от несанкционированного доступа (СЗИ от НСД)'),
|
||||
('аккорд', 'Защита информации от несанкционированного доступа (СЗИ от НСД)'),
|
||||
('siem', 'Регистрация и мониторинг событий безопасности'),
|
||||
('dlp', 'Регистрация и мониторинг событий безопасности'),
|
||||
('мониторинг', 'Регистрация и мониторинг событий безопасности'),
|
||||
('регистрац', 'Регистрация и мониторинг событий безопасности'),
|
||||
('доверенная загрузка', 'Контроль (доверенная) загрузки'),
|
||||
('резервн', 'Резервное копирование и восстановление'),
|
||||
]
|
||||
|
||||
|
||||
@@ -395,15 +411,21 @@ def auto_fill_security(isys, threats=None):
|
||||
if not (getattr(isys, 'org_measures', '') or '').strip():
|
||||
res['org_measures'] = '\n'.join(BASE_ORG_MEASURES)
|
||||
|
||||
# 7. Тех. меры — базовые + по СЗИ объекта
|
||||
# 7. Тех. меры — базовые + по СЗИ объекта.
|
||||
# Только если объекту присвоена категория значимости (1/2/3):
|
||||
# для незначимого объекта технические меры не требуются.
|
||||
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)
|
||||
cat = (getattr(isys, 'category', '') or '').strip()
|
||||
has_category = cat in ('1', '2', '3')
|
||||
if has_category:
|
||||
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)
|
||||
# else: категория не присвоена — технические меры не заполняем
|
||||
|
||||
return res
|
||||
|
||||
|
||||
+91
-4
@@ -2241,7 +2241,52 @@ class DokoGenApp:
|
||||
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
|
||||
if num == '9':
|
||||
if num == '10' or str(num).startswith('10.'):
|
||||
# Показатель 10 — прекращение финансовых операций (банковская сфера)
|
||||
is_base = str(num) == '10'
|
||||
if is_base:
|
||||
ttk.Label(frm, text="Показатель 10 — прекращение (нарушение) проведения клиентами операций "
|
||||
"по переводу денежных средств",
|
||||
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
|
||||
ttk.Label(frm, text="Применим для: системно значимых кредитных организаций, операторов услуг "
|
||||
"платёжной инфраструктуры значимых платёжных систем, операторов платформы "
|
||||
"цифрового рубля и др.\n"
|
||||
"Формула: №10 = операции за год (млн ед.) / календарные дни в году "
|
||||
"(среднедневное количество операций).\n"
|
||||
"Пороги: ≤ 70 млн/день → III; > 70 и ≤ 120 → II; > 120 → I.",
|
||||
foreground='gray', wraplength=760, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
|
||||
else:
|
||||
ttk.Label(frm, text=f"Показатель {num} — прекращение (нарушение) проведения операций "
|
||||
"(подпоказатель 10.x)",
|
||||
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
|
||||
ttk.Label(frm, text="Значение показателя вводится в единицах, установленных ПП-127 "
|
||||
"(трлн руб., тыс. шт., млрд руб., количество договоров, млн ед.); "
|
||||
"категория определяется по порогам ПП-127.",
|
||||
foreground='gray', wraplength=760, justify=tk.LEFT).pack(anchor=tk.W, pady=(2, 6))
|
||||
|
||||
def _row(label, key, default=''):
|
||||
ttk.Label(frm, text=label, wraplength=900, justify=tk.LEFT).pack(anchor=tk.W, pady=(4, 0))
|
||||
e = ttk.Entry(frm, width=80)
|
||||
e.insert(0, str(default or ''))
|
||||
e.pack(fill=tk.X)
|
||||
return e
|
||||
|
||||
_ops = getattr(self.model, 'ops_count', '') or ''
|
||||
_days = getattr(self.model, 'calendar_days', '') or '365'
|
||||
_v10 = getattr(self.model, 'criterion10_value', '') or ''
|
||||
if is_base:
|
||||
e_ops = _row("Количество операций за прошедший год (млн ед.):", 'ops', _ops)
|
||||
e_days = _row("Количество календарных дней в году (по умолчанию 365):", 'days', _days)
|
||||
else:
|
||||
e_val10 = _row("Значение показателя (в единицах ПП-127):", 'val10', _v10)
|
||||
result_frame = ttk.Frame(frm)
|
||||
result_frame.pack(fill=tk.BOTH, expand=True, pady=(8, 0))
|
||||
result = tk.Text(result_frame, height=12, wrap=tk.WORD, state=tk.NORMAL)
|
||||
result_scroll = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=result.yview)
|
||||
result.configure(yscrollcommand=result_scroll.set)
|
||||
result.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
result_scroll.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
elif num == '9':
|
||||
ttk.Label(frm, text="Показатель 9 — ущерб бюджетам РФ (применим ко всем субъектам КИИ)",
|
||||
font=('Arial', 10, 'bold')).pack(anchor=tk.W)
|
||||
ttk.Label(frm, text="Формула: №9 = ΔБ / Бусредн × 100%, где ΔБ = ΔНП + ΔНДПИ + ΔДИВ + ΔВСО + ΔНС\n"
|
||||
@@ -2353,7 +2398,34 @@ class DokoGenApp:
|
||||
|
||||
def _calc():
|
||||
lines = []
|
||||
if num == '8':
|
||||
if num == '10' or str(num).startswith('10.'):
|
||||
from .variables import _criterion_10_cat
|
||||
if str(num) == '10':
|
||||
ops = _num(e_ops.get())
|
||||
days = _num(e_days.get())
|
||||
if days is None or days <= 0:
|
||||
days = 365
|
||||
if ops is None:
|
||||
result.delete('1.0', tk.END)
|
||||
result.insert('1.0', "Заполните количество операций за год (млн ед.).")
|
||||
return
|
||||
val = ops / days
|
||||
lines.append(f"Количество операций за прошедший год: {ops:,.0f} млн ед.")
|
||||
lines.append(f"Количество календарных дней в году: {days:.0f}")
|
||||
lines.append(f"№10 = операции / дни = {ops:,.0f} / {days:.0f} = {val:.6f} млн ед./день")
|
||||
else:
|
||||
val = _num(e_val10.get())
|
||||
if val is None:
|
||||
result.delete('1.0', tk.END)
|
||||
result.insert('1.0', "Заполните значение показателя.")
|
||||
return
|
||||
lines.append(f"Значение показателя {num}: {val:,.6f}")
|
||||
cat = _criterion_10_cat(num, val)
|
||||
if cat:
|
||||
lines.append(f"Категория значимости: {cat} (по порогам ПП-127)")
|
||||
else:
|
||||
lines.append("Категория значимости: — (значение ниже порога III)")
|
||||
elif num == '8':
|
||||
d = _num(e_dincome.get())
|
||||
b = _num(e_budget.get())
|
||||
if d is None or b is None or b <= 0:
|
||||
@@ -2505,8 +2577,9 @@ class DokoGenApp:
|
||||
combo.pack(side=tk.RIGHT, padx=6)
|
||||
_combos[num] = combo
|
||||
|
||||
# Кнопка «🧮» — авторасчёт показателя (п. 8 «ущерб субъекту КИИ» и п. 9 «ущерб бюджетам»)
|
||||
if grp_num in ('8', '9'):
|
||||
# Кнопка «🧮» — авторасчёт показателя (п. 8 «ущерб субъекту КИИ»,
|
||||
# п. 9 «ущерб бюджетам», п. 10 «прекращение финансовых операций»)
|
||||
if grp_num in ('8', '9', '10'):
|
||||
ttk.Button(row, text='🧮', width=3,
|
||||
command=lambda n=num, nm=name, v=var, c=combo:
|
||||
_open_calc_dialog(n, nm, v, c)
|
||||
@@ -3773,6 +3846,13 @@ class DokoGenApp:
|
||||
'category': isys.category or '',
|
||||
'sphere': isys.sphere or '',
|
||||
'object_type': isys.object_type or '',
|
||||
'description': isys.description or '',
|
||||
'architecture': isys.architecture or '',
|
||||
'hw_sw': isys.hw_sw or '',
|
||||
'os_sw': isys.os_sw or '',
|
||||
'app_sw': isys.app_sw or '',
|
||||
'net_category': isys.net_category or '',
|
||||
'is_internet': bool(getattr(isys, 'is_internet', False)),
|
||||
'threats': isys.threats or '',
|
||||
'attacker_category': isys.attacker_category or '',
|
||||
'defense_tools': list(self.defense_tools_listbox.get(0, tk.END)) or [],
|
||||
@@ -3838,6 +3918,13 @@ class DokoGenApp:
|
||||
'category': isys.category or '',
|
||||
'sphere': isys.sphere or '',
|
||||
'object_type': isys.object_type or '',
|
||||
'description': isys.description or '',
|
||||
'architecture': isys.architecture or '',
|
||||
'hw_sw': isys.hw_sw or '',
|
||||
'os_sw': isys.os_sw or '',
|
||||
'app_sw': isys.app_sw or '',
|
||||
'net_category': isys.net_category or '',
|
||||
'is_internet': bool(getattr(isys, 'is_internet', False)),
|
||||
'threats': isys.threats or '',
|
||||
'attacker_category': isys.attacker_category or '',
|
||||
'defense_tools': list(self.defense_tools_listbox.get(0, tk.END)) or [],
|
||||
|
||||
@@ -518,6 +518,84 @@ def _calc_criterion_8_9(company, isys, num):
|
||||
return text, cat
|
||||
|
||||
|
||||
# Пороги показателя 10 и подпоказателей 10.1–10.7 (ПП-127, «Значение показателя»)
|
||||
CRITERION_10_THRESHOLDS = {
|
||||
# num: (категория → (нижняя граница, верхняя граница)), границы «включительно»
|
||||
# Показатель 10 — среднедневное количество операций (млн ед.):
|
||||
# III — менее или равно 70, II — более 70 но менее или равно 120, I — более 120.
|
||||
'10': {'I': (120, None), 'II': (70, 120), 'III': (None, 70)},
|
||||
'10.1': {'I': (10, None), 'II': (1, 10), 'III': (None, 1)}, # трлн руб.
|
||||
'10.2': {'I': (25, None), 'II': (10, 25), 'III': (None, 10)}, # тыс. шт.
|
||||
'10.3': {'I': (2000, None), 'II': (1000, 2000), 'III': (50, 1000)}, # млрд руб.
|
||||
'10.4': {'I': (5000, None), 'II': (1500, 5000), 'III': (100, 1500)}, # млрд руб.
|
||||
'10.5': {'I': (150, None), 'II': (100, 150), 'III': (25, 100)}, # договоров
|
||||
'10.6': {'I': (5000, None), 'II': (1000, 5000), 'III': (100, 1000)}, # млрд руб.
|
||||
'10.7': {'I': (500, None), 'II': (200, 500), 'III': (30, 200)}, # млн ед.
|
||||
}
|
||||
|
||||
|
||||
def _criterion_10_cat(num, value):
|
||||
"""Категория значимости по показателю 10 / 10.x (ПП-127).
|
||||
|
||||
value — численное значение показателя. Возвращает 'I'/'II'/'III' или None.
|
||||
"""
|
||||
thr = CRITERION_10_THRESHOLDS.get(str(num))
|
||||
if not thr or value is None:
|
||||
return None
|
||||
for cat in ('I', 'II', 'III'):
|
||||
lo, hi = thr[cat]
|
||||
if lo is not None and value < lo:
|
||||
continue
|
||||
if hi is not None and value > hi:
|
||||
continue
|
||||
return cat
|
||||
return None
|
||||
|
||||
|
||||
def _calc_criterion_10(company, isys, num):
|
||||
"""Расчёт показателя 10 (прекращение финансовых операций) и подпоказателей 10.1–10.7.
|
||||
|
||||
Показатель 10: среднедневное количество операций = операции за год (млн ед.) / дни.
|
||||
Подпоказатели 10.x: значение показателя (в своих единицах) сравнивается с порогами.
|
||||
Возвращает (текст_обоснования, категория или None).
|
||||
"""
|
||||
num = str(num)
|
||||
if num not in CRITERION_10_THRESHOLDS:
|
||||
return None, None
|
||||
if num == '10':
|
||||
ops = _num(getattr(company, 'ops_count', '') or '')
|
||||
days = _num(getattr(company, 'calendar_days', '') or '')
|
||||
if days is None or days <= 0:
|
||||
days = 365
|
||||
if ops is None:
|
||||
return ("Показатель применим. Для расчёта заполните данные организации: "
|
||||
"«Количество операций за прошедший год (млн ед.)».", None)
|
||||
val = ops / days
|
||||
cat = _criterion_10_cat('10', val)
|
||||
text = (f"Показатель прекращения финансовых операций оценивается среднедневным количеством "
|
||||
f"операций, проведенных клиентами по банковским счетам и (или) без открытия банковского "
|
||||
f"счета. Количество операций за прошедший год: {ops:,.2f} млн ед. Количество календарных "
|
||||
f"дней в году: {days:.0f}. Среднедневное количество операций: {ops:,.2f} / {days:.0f} "
|
||||
f"= {val:.6f} млн ед./день.")
|
||||
else:
|
||||
value = _num(getattr(company, 'criterion10_value', '') or '')
|
||||
if value is None:
|
||||
return (f"Показатель применим. Для расчёта заполните значение показателя "
|
||||
f"«{num}» в данных организации.", None)
|
||||
val = value
|
||||
cat = _criterion_10_cat(num, val)
|
||||
text = (f"Показатель {num} оценивается значением показателя: {val:,.6f} "
|
||||
f"(в единицах, установленных ПП-127).")
|
||||
if cat:
|
||||
text += (f" Согласно Постановлению № 127 полученное значение соответствует "
|
||||
f"{cat}-й категории значимости, по данному показателю объекту присваивается "
|
||||
f"{cat}-я категория значимости.")
|
||||
else:
|
||||
text += (" Значение не достигает порога III категории — по данному показателю "
|
||||
"категория значимости не присваивается.")
|
||||
return text, cat
|
||||
|
||||
|
||||
def _build_org_measures_text(company, isys=None):
|
||||
"""Формирует текст организационных мер из словаря org_measures.json
|
||||
с учётом ответов раздела «Физическая безопасность» опросника.
|
||||
@@ -617,6 +695,14 @@ def _build_categorization_indicators(company, is_list):
|
||||
category = f"{cat}-я категория"
|
||||
else:
|
||||
category = '—'
|
||||
elif grp_num == '10':
|
||||
text, cat = _calc_criterion_10(company, isys, num)
|
||||
if text:
|
||||
value = text
|
||||
if cat:
|
||||
category = f"{cat}-я категория"
|
||||
else:
|
||||
category = '—'
|
||||
else:
|
||||
# Применимый показатель без авторасчёта — оператор заполняет значение
|
||||
value = '—'
|
||||
|
||||
Reference in New Issue
Block a user