ОКВЭД: полный справочник ОКВЭД2 (2770 записей) в едином формате «код название», resolve_okved без дефиса, импорт доп. ОКВЭД без переносов; угрозы: умный подбор — исключение неиспользуемых технологий (виртуализация, облако, мобильные, АСУ ТП, грид, суперкомпьютер, большие данные, беспроводные сети, контейнеры, smart-карты, ИИ), базовые угрозы локальных сетей
This commit is contained in:
+2595
-92
File diff suppressed because it is too large
Load Diff
@@ -42,8 +42,26 @@ BASE_KEYWORDS = [
|
|||||||
'вредоносн', 'несанкционированн', 'утечк', 'перехват', 'модификац',
|
'вредоносн', 'несанкционированн', 'утечк', 'перехват', 'модификац',
|
||||||
'уничтожен', 'отказ в обслуживании', 'нсд', 'биос', 'пароль',
|
'уничтожен', 'отказ в обслуживании', 'нсд', 'биос', 'пароль',
|
||||||
'криптографическ', 'шифрован', 'аутентификац',
|
'криптографическ', 'шифрован', 'аутентификац',
|
||||||
|
# базовые угрозы локальных сетей / клиент-серверных архитектур
|
||||||
|
'доступ', 'данн', 'систем', 'конфигурац', 'целостност', 'информац',
|
||||||
|
'программн', 'пользовател', 'авторизац', 'сеанс', 'журнал', 'реестр',
|
||||||
|
'файл', 'память', 'буфер', 'ресурс', 'сервер', 'клиент', 'учётн',
|
||||||
|
'учетн', 'идентификац', 'привилег', 'средств', 'сетев', 'локальн',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Технологии, которые по умолчанию НЕ используются на объекте.
|
||||||
|
# Если в характеристиках объекта есть явные упоминания — группа возвращается.
|
||||||
|
TECH_GROUPS = {
|
||||||
|
'виртуализац': ['виртуал', 'гипервизор', 'контейнер'],
|
||||||
|
'облако': ['облачн', 'облак'],
|
||||||
|
'мобильн': ['мобильн', 'смартфон', 'планшет'],
|
||||||
|
'грид': ['грид', 'суперкомпьютер'],
|
||||||
|
'большие данные': ['больших данных', 'хранилищ'],
|
||||||
|
'беспроводн': ['беспроводн', 'wi-fi', 'wifi'],
|
||||||
|
'smart-карты': ['smart-карт', 'смарт-карт'],
|
||||||
|
'машинное обучение': ['машинного обучения', 'искусственного интеллекта', 'нейросет'],
|
||||||
|
}
|
||||||
|
|
||||||
# Объект имеет подключение к сети Интернет / сеть электросвязи
|
# Объект имеет подключение к сети Интернет / сеть электросвязи
|
||||||
INTERNET_KEYWORDS = [
|
INTERNET_KEYWORDS = [
|
||||||
'удалённ', 'удаленн', 'сетев', 'фишинг', 'ddos', 'отказ в обслуживании',
|
'удалённ', 'удаленн', 'сетев', 'фишинг', 'ddos', 'отказ в обслуживании',
|
||||||
@@ -153,6 +171,21 @@ def suggest_threats_program(isys, threats=None, limit=None):
|
|||||||
is_asu = _is_asu(isys)
|
is_asu = _is_asu(isys)
|
||||||
is_network = _is_network(isys)
|
is_network = _is_network(isys)
|
||||||
|
|
||||||
|
# --- Технологии, которые явно НЕ используются на объекте ---
|
||||||
|
# Если в характеристиках объекта (описание, архитектура, ПО, сфера) нет
|
||||||
|
# упоминаний технологии — угрозы этой группы исключаем.
|
||||||
|
tech_context = ' '.join([
|
||||||
|
str(getattr(isys, 'description', '') or ''),
|
||||||
|
str(getattr(isys, 'architecture', '') or ''),
|
||||||
|
str(getattr(isys, 'hw_sw', '') or ''),
|
||||||
|
str(getattr(isys, 'os_sw', '') or ''),
|
||||||
|
str(getattr(isys, 'app_sw', '') or ''),
|
||||||
|
str(getattr(isys, 'object_type', '') or ''),
|
||||||
|
str(getattr(isys, 'sphere', '') or ''),
|
||||||
|
str(getattr(isys, 'net_category', '') or ''),
|
||||||
|
str(getattr(isys, 'typical_object', '') or ''),
|
||||||
|
]).lower()
|
||||||
|
|
||||||
# --- Слова-исключения (если встретились в названии угрозы — она неактуальна) ---
|
# --- Слова-исключения (если встретились в названии угрозы — она неактуальна) ---
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
||||||
@@ -167,6 +200,19 @@ def suggest_threats_program(isys, threats=None, limit=None):
|
|||||||
if is_asu:
|
if is_asu:
|
||||||
# АСУ: нет BIOS/виртуализации/браузера в привычном понимании
|
# АСУ: нет BIOS/виртуализации/браузера в привычном понимании
|
||||||
exclude += ['биос', 'грид', 'гипервизор', 'виртуальн', 'браузер']
|
exclude += ['биос', 'грид', 'гипервизор', 'виртуальн', 'браузер']
|
||||||
|
else:
|
||||||
|
# Не АСУ — исключаем угрозы АСУ ТП / технологических процессов
|
||||||
|
exclude += ['технологическ', 'датчик', 'исполнительн', 'асутп', 'scada',
|
||||||
|
'промышленн', 'контроллер', 'числовым программным управлением',
|
||||||
|
'программируемых логических']
|
||||||
|
|
||||||
|
# Технологии, не упомянутые в характеристиках объекта → исключаем
|
||||||
|
for tech_name, kws in TECH_GROUPS.items():
|
||||||
|
if any(kw in tech_context for kw in kws):
|
||||||
|
continue # технология используется — угрозы оставляем
|
||||||
|
# Технология не упомянута — исключаем её угрозы
|
||||||
|
for kw in kws:
|
||||||
|
exclude.append(kw)
|
||||||
|
|
||||||
if not is_network and not is_asu:
|
if not is_network and not is_asu:
|
||||||
# Обычная ИС: неактуальны чисто сетевые/телеком-угрозы без указания
|
# Обычная ИС: неактуальны чисто сетевые/телеком-угрозы без указания
|
||||||
|
|||||||
+5
-1
@@ -4546,7 +4546,11 @@ class DokoGenApp:
|
|||||||
extra = data['okvedExtra']
|
extra = data['okvedExtra']
|
||||||
if isinstance(extra, str):
|
if isinstance(extra, str):
|
||||||
import re as _re
|
import re as _re
|
||||||
parts = [p.strip() for p in _re.split(r'[;,\n]+', extra) if p.strip()]
|
# Перенос строки внутри одной записи («27.32.2 Производство\nсиловых кабелей»)
|
||||||
|
# не должен создавать вторую запись — сначала склеиваем переносы в пробел,
|
||||||
|
# затем режем только по запятой / точке с запятой.
|
||||||
|
extra = _re.sub(r'\s*[\n\r]+\s*', ' ', extra)
|
||||||
|
parts = [p.strip() for p in _re.split(r'[;]+|\s*,\s*', extra) if p.strip()]
|
||||||
else:
|
else:
|
||||||
parts = [str(p).strip() for p in extra if str(p).strip()]
|
parts = [str(p).strip() for p in extra if str(p).strip()]
|
||||||
for p in parts:
|
for p in parts:
|
||||||
|
|||||||
+16
-10
@@ -161,15 +161,20 @@ def normalize_address(text):
|
|||||||
|
|
||||||
|
|
||||||
def resolve_okved(code, dadata_token=None):
|
def resolve_okved(code, dadata_token=None):
|
||||||
"""Код ОКВЭД → «код - название».
|
"""Код ОКВЭД → «код название» (без дефиса), например «27.32.2 Производство силовых кабелей».
|
||||||
|
|
||||||
|
Принимает и голый код («27.32.2»), и строку с названием
|
||||||
|
(«27.32.2 - Производство силовых кабелей» / «27.32.2 Производство силовых кабелей»).
|
||||||
1) Ищем в словаре dictionaries/okved.json (строки вида «27.32.2 Название»).
|
1) Ищем в словаре dictionaries/okved.json (строки вида «27.32.2 Название»).
|
||||||
2) Если не нашли — запрашиваем DaData suggest okved2 (если есть токен).
|
2) Если не нашли — запрашиваем DaData suggest okved2 (если есть токен).
|
||||||
3) Иначе возвращаем код как есть.
|
3) Иначе возвращаем нормализованную строку «код название» как есть.
|
||||||
"""
|
"""
|
||||||
code = (code or '').strip()
|
code = (code or '').strip()
|
||||||
if not code:
|
if not code:
|
||||||
return ''
|
return ''
|
||||||
|
# Извлекаем код из входной строки: «27.32.2 - Производство силовых кабелей» → «27.32.2»
|
||||||
|
m = re.match(r'^\s*(\d+(?:\.\d+)*)', code)
|
||||||
|
code_only = m.group(1) if m else code.split()[0].rstrip('.')
|
||||||
# 1) Словарь
|
# 1) Словарь
|
||||||
try:
|
try:
|
||||||
import os, json
|
import os, json
|
||||||
@@ -178,12 +183,8 @@ def resolve_okved(code, dadata_token=None):
|
|||||||
items = json.load(f)
|
items = json.load(f)
|
||||||
for item in items:
|
for item in items:
|
||||||
item = str(item).strip()
|
item = str(item).strip()
|
||||||
# совпадение по началу: «27.32.2» или «27.32.2 - ...» / «27.32.2 ...»
|
# совпадение по коду: «27.32.2» или «27.32.2 Название»
|
||||||
if item.split()[0].rstrip('.') == code.rstrip('.'):
|
if item.split()[0].rstrip('.') == code_only.rstrip('.'):
|
||||||
# нормализуем: «код - название»
|
|
||||||
rest = item[len(item.split()[0]):].strip().lstrip('- ').strip()
|
|
||||||
if rest:
|
|
||||||
return f"{code} - {rest}"
|
|
||||||
return item
|
return item
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -191,7 +192,7 @@ def resolve_okved(code, dadata_token=None):
|
|||||||
if dadata_token:
|
if dadata_token:
|
||||||
try:
|
try:
|
||||||
js, err = _http_json('https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/okved2',
|
js, err = _http_json('https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/okved2',
|
||||||
data={'query': code, 'count': 1},
|
data={'query': code_only, 'count': 1},
|
||||||
headers={'Content-Type': 'application/json',
|
headers={'Content-Type': 'application/json',
|
||||||
'Authorization': f'Token {dadata_token}'})
|
'Authorization': f'Token {dadata_token}'})
|
||||||
if not err and js:
|
if not err and js:
|
||||||
@@ -200,7 +201,12 @@ def resolve_okved(code, dadata_token=None):
|
|||||||
return sugg[0]['value']
|
return sugg[0]['value']
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return code
|
# 3) Нормализуем вход: «27.32.2 - Название» → «27.32.2 Название» (без дефиса)
|
||||||
|
rest = code[len(m.group(1)):].strip() if m else ''
|
||||||
|
rest = rest.lstrip('- ').strip()
|
||||||
|
if rest:
|
||||||
|
return f"{code_only} {rest}"
|
||||||
|
return code_only
|
||||||
|
|
||||||
|
|
||||||
def _fmt_date(value):
|
def _fmt_date(value):
|
||||||
|
|||||||
Reference in New Issue
Block a user