Update app.py
Browse files
app.py
CHANGED
|
@@ -10,7 +10,7 @@ def analyze_email(headers, body):
|
|
| 10 |
score = 0
|
| 11 |
findings = []
|
| 12 |
|
| 13 |
-
#
|
| 14 |
if re.search(r"SPF.*FAIL", headers, re.IGNORECASE):
|
| 15 |
score += 10
|
| 16 |
findings.append("<li>SPF FAIL: Сервер не разрешен для этого домена (+10)</li>")
|
|
@@ -30,73 +30,73 @@ def analyze_email(headers, body):
|
|
| 30 |
score += 5
|
| 31 |
findings.append(f"<li>Отправитель ({from_email}) не совпадает с Return-Path ({return_email}) (+5)</li>")
|
| 32 |
|
| 33 |
-
#
|
| 34 |
|
| 35 |
-
#
|
| 36 |
keywords_urgency = [
|
| 37 |
"заблокирован", "срочно", "удаление", "ограничен", "suspension", "urgent", "immediate",
|
| 38 |
"остановлен", "удален", "удалён", "удалена", "остановлена", "ограничена", "заморожена",
|
| 39 |
"заморожен", "suspended",
|
| 40 |
-
#
|
| 41 |
"немедленно", "аккаунт будет заблокирован", "блокировка счета", "блокировка аккаунта",
|
| 42 |
"служба безопасности"
|
| 43 |
]
|
| 44 |
|
| 45 |
-
#
|
| 46 |
keywords_action = [
|
| 47 |
"verify", "update", "login", "вход", "пароль", "password", "аутентификация",
|
| 48 |
"authentication", "войдите", "требуется", "confirm", "confirmation",
|
| 49 |
-
#
|
| 50 |
"подтвердите", "подтвердить", "данные карты", "конфиденциальная информация",
|
| 51 |
"подтвердите личность", "перевод средств", "поддержка банка"
|
| 52 |
]
|
| 53 |
|
| 54 |
-
#
|
| 55 |
keywords_greed = [
|
| 56 |
"freespin", "фриспин", "casino", "казино", "lottery", "1xbet", "лотерея", "бонус",
|
| 57 |
"распродажа", "бесплатно", "раздача", "подарок", "гифт", "giveaway", "выигрыш",
|
| 58 |
"скидка", "prize", "gift", "win", "победитель", "winner", "поздравляем", "congratulations",
|
| 59 |
-
# Добавлено из
|
| 60 |
"вы выиграли", "приз", "выбран случайным образом"
|
| 61 |
]
|
| 62 |
|
| 63 |
body_lower = body.lower()
|
| 64 |
|
| 65 |
-
#
|
| 66 |
found_urgency = False
|
| 67 |
for word in keywords_urgency:
|
| 68 |
if word in body_lower:
|
| 69 |
-
#
|
| 70 |
-
# но в рамках задания суммируем
|
| 71 |
score += 2
|
| 72 |
findings.append(f"<li>Психологическое давление: '{word}' (+2)</li>")
|
| 73 |
|
| 74 |
-
#
|
| 75 |
for word in keywords_action:
|
| 76 |
if word in body_lower:
|
| 77 |
score += 1
|
| 78 |
findings.append(f"<li>Запрос данных/действий: '{word}' (+1)</li>")
|
| 79 |
|
| 80 |
-
#
|
| 81 |
for word in keywords_greed:
|
| 82 |
if word in body_lower:
|
| 83 |
score += 2
|
| 84 |
findings.append(f"<li>Приманка/Выигрыш: '{word}' (+2)</li>")
|
| 85 |
|
| 86 |
-
#
|
| 87 |
ip_links = re.findall(r'https?://(?:[0-9]{1,3}\.){3}[0-9]{1,3}', body)
|
| 88 |
if ip_links:
|
| 89 |
score += 5
|
| 90 |
findings.append(f"<li>IP в ссылке: ({ip_links[0]}) (+5)</li>")
|
| 91 |
|
| 92 |
-
suspicious_tlds = [".xyz", ".top", ".info", ".club", ".shop", ".site"] #
|
| 93 |
for tld in suspicious_tlds:
|
| 94 |
if tld in body_lower:
|
| 95 |
if re.search(rf"\w{tld}/\w", body_lower) or re.search(rf"\w{tld}\b", body_lower):
|
| 96 |
score += 2
|
| 97 |
findings.append(f"<li>Подозрительный домен '{tld}' (+2)</li>")
|
| 98 |
|
| 99 |
-
#
|
| 100 |
if score == 0:
|
| 101 |
verdict_text = "🟢 Уровень угрозы: НИЗКИЙ. Явных признаков фишинга не обнаружено."
|
| 102 |
findings_html = "Угроз не найдено."
|
|
@@ -109,7 +109,7 @@ def analyze_email(headers, body):
|
|
| 109 |
|
| 110 |
return str(score), verdict_text, findings_html
|
| 111 |
|
| 112 |
-
#
|
| 113 |
headers_input = gr.Textbox(label="1. Служебные заголовки", lines=5, placeholder="Вставьте заголовки (SPF, DKIM, From...)")
|
| 114 |
body_input = gr.Textbox(label="2. Текст письма", lines=10, placeholder="Вставьте текст письма...")
|
| 115 |
|
|
@@ -117,17 +117,17 @@ score_output = gr.Textbox(label="Итоговый счет угрозы", type="
|
|
| 117 |
verdict_output = gr.Textbox(label="Финальный вердикт", type="text", max_lines=3)
|
| 118 |
findings_output = gr.HTML(label="Детализация обнаруженных угроз")
|
| 119 |
|
| 120 |
-
#
|
| 121 |
examples_list = [
|
| 122 |
-
#
|
| 123 |
["SPF: FAIL\nFrom: Bank <security@bank.com>\nReturn-Path: hacker@evil.ru",
|
| 124 |
"Ваш аккаунт будет заблокирован через 24 часа. Срочно подтвердите данные карты по ссылке: http://secure-login-update.ru"],
|
| 125 |
|
| 126 |
-
#
|
| 127 |
["SPF: PASS\nDKIM: PASS\nFrom: University <edu@uni.ru>\nReturn-Path: edu@uni.ru",
|
| 128 |
"Уважаемый студент, напоминаем о необходимости оплатить обучение до 25 числа. Оплату можно произвести через личный кабинет университета."],
|
| 129 |
|
| 130 |
-
#
|
| 131 |
["SPF: PASS\nFrom: Promo <promo@shop.com>",
|
| 132 |
"Только сегодня! Вы выбраны среди 100 счастливчиков! Вы выиграли приз! Заберите свой приз на странице акции: https://promo-super-win.shop"]
|
| 133 |
]
|
|
@@ -136,7 +136,7 @@ gr.Interface(
|
|
| 136 |
fn=analyze_email,
|
| 137 |
inputs=[headers_input, body_input],
|
| 138 |
outputs=[score_output, verdict_output, findings_output],
|
| 139 |
-
title="Email Security Analyzer (Практика 3)",
|
| 140 |
-
description="Инструмент для оценки фишинга.
|
| 141 |
examples=examples_list
|
| 142 |
).launch()
|
|
|
|
| 10 |
score = 0
|
| 11 |
findings = []
|
| 12 |
|
| 13 |
+
# анализ самих заголовков
|
| 14 |
if re.search(r"SPF.*FAIL", headers, re.IGNORECASE):
|
| 15 |
score += 10
|
| 16 |
findings.append("<li>SPF FAIL: Сервер не разрешен для этого домена (+10)</li>")
|
|
|
|
| 30 |
score += 5
|
| 31 |
findings.append(f"<li>Отправитель ({from_email}) не совпадает с Return-Path ({return_email}) (+5)</li>")
|
| 32 |
|
| 33 |
+
# анализ самого текста
|
| 34 |
|
| 35 |
+
# словарь срочности и запугивания
|
| 36 |
keywords_urgency = [
|
| 37 |
"заблокирован", "срочно", "удаление", "ограничен", "suspension", "urgent", "immediate",
|
| 38 |
"остановлен", "удален", "удалён", "удалена", "остановлена", "ограничена", "заморожена",
|
| 39 |
"заморожен", "suspended",
|
| 40 |
+
# добавлено из тз учителя:
|
| 41 |
"немедленно", "аккаунт будет заблокирован", "блокировка счета", "блокировка аккаунта",
|
| 42 |
"служба безопасности"
|
| 43 |
]
|
| 44 |
|
| 45 |
+
# словарь требуемых действий
|
| 46 |
keywords_action = [
|
| 47 |
"verify", "update", "login", "вход", "пароль", "password", "аутентификация",
|
| 48 |
"authentication", "войдите", "требуется", "confirm", "confirmation",
|
| 49 |
+
# добавлено из тз учителя:
|
| 50 |
"подтвердите", "подтвердить", "данные карты", "конфиденциальная информация",
|
| 51 |
"подтвердите личность", "перевод средств", "поддержка банка"
|
| 52 |
]
|
| 53 |
|
| 54 |
+
# словарь жадности
|
| 55 |
keywords_greed = [
|
| 56 |
"freespin", "фриспин", "casino", "казино", "lottery", "1xbet", "лотерея", "бонус",
|
| 57 |
"распродажа", "бесплатно", "раздача", "подарок", "гифт", "giveaway", "выигрыш",
|
| 58 |
"скидка", "prize", "gift", "win", "победитель", "winner", "поздравляем", "congratulations",
|
| 59 |
+
# Добавлено из тз учителя:
|
| 60 |
"вы выиграли", "приз", "выбран случайным образом"
|
| 61 |
]
|
| 62 |
|
| 63 |
body_lower = body.lower()
|
| 64 |
|
| 65 |
+
# проверка на срочность
|
| 66 |
found_urgency = False
|
| 67 |
for word in keywords_urgency:
|
| 68 |
if word in body_lower:
|
| 69 |
+
# чтобы не начислять баллы за каждое слово много раз можно ограничить
|
| 70 |
+
# но в рамках задания суммируем
|
| 71 |
score += 2
|
| 72 |
findings.append(f"<li>Психологическое давление: '{word}' (+2)</li>")
|
| 73 |
|
| 74 |
+
# проверка на действия
|
| 75 |
for word in keywords_action:
|
| 76 |
if word in body_lower:
|
| 77 |
score += 1
|
| 78 |
findings.append(f"<li>Запрос данных/действий: '{word}' (+1)</li>")
|
| 79 |
|
| 80 |
+
# проверка на жадность
|
| 81 |
for word in keywords_greed:
|
| 82 |
if word in body_lower:
|
| 83 |
score += 2
|
| 84 |
findings.append(f"<li>Приманка/Выигрыш: '{word}' (+2)</li>")
|
| 85 |
|
| 86 |
+
# анализ самих ссылок
|
| 87 |
ip_links = re.findall(r'https?://(?:[0-9]{1,3}\.){3}[0-9]{1,3}', body)
|
| 88 |
if ip_links:
|
| 89 |
score += 5
|
| 90 |
findings.append(f"<li>IP в ссылке: ({ip_links[0]}) (+5)</li>")
|
| 91 |
|
| 92 |
+
suspicious_tlds = [".xyz", ".top", ".info", ".club", ".shop", ".site"] # добавил .shop из тз учителя
|
| 93 |
for tld in suspicious_tlds:
|
| 94 |
if tld in body_lower:
|
| 95 |
if re.search(rf"\w{tld}/\w", body_lower) or re.search(rf"\w{tld}\b", body_lower):
|
| 96 |
score += 2
|
| 97 |
findings.append(f"<li>Подозрительный домен '{tld}' (+2)</li>")
|
| 98 |
|
| 99 |
+
# вердикт
|
| 100 |
if score == 0:
|
| 101 |
verdict_text = "🟢 Уровень угрозы: НИЗКИЙ. Явных признаков фишинга не обнаружено."
|
| 102 |
findings_html = "Угроз не найдено."
|
|
|
|
| 109 |
|
| 110 |
return str(score), verdict_text, findings_html
|
| 111 |
|
| 112 |
+
# интерфейс
|
| 113 |
headers_input = gr.Textbox(label="1. Служебные заголовки", lines=5, placeholder="Вставьте заголовки (SPF, DKIM, From...)")
|
| 114 |
body_input = gr.Textbox(label="2. Текст письма", lines=10, placeholder="Вставьте текст письма...")
|
| 115 |
|
|
|
|
| 117 |
verdict_output = gr.Textbox(label="Финальный вердикт", type="text", max_lines=3)
|
| 118 |
findings_output = gr.HTML(label="Детализация обнаруженных угроз")
|
| 119 |
|
| 120 |
+
# примеры по тз учителя
|
| 121 |
examples_list = [
|
| 122 |
+
# фишинг
|
| 123 |
["SPF: FAIL\nFrom: Bank <security@bank.com>\nReturn-Path: hacker@evil.ru",
|
| 124 |
"Ваш аккаунт будет заблокирован через 24 часа. Срочно подтвердите данные карты по ссылке: http://secure-login-update.ru"],
|
| 125 |
|
| 126 |
+
# нормальное письмо
|
| 127 |
["SPF: PASS\nDKIM: PASS\nFrom: University <edu@uni.ru>\nReturn-Path: edu@uni.ru",
|
| 128 |
"Уважаемый студент, напоминаем о необходимости оплатить обучение до 25 числа. Оплату можно произвести через личный кабинет университета."],
|
| 129 |
|
| 130 |
+
# реклама
|
| 131 |
["SPF: PASS\nFrom: Promo <promo@shop.com>",
|
| 132 |
"Только сегодня! Вы выбраны среди 100 счастливчиков! Вы выиграли приз! Заберите свой приз на странице акции: https://promo-super-win.shop"]
|
| 133 |
]
|
|
|
|
| 136 |
fn=analyze_email,
|
| 137 |
inputs=[headers_input, body_input],
|
| 138 |
outputs=[score_output, verdict_output, findings_output],
|
| 139 |
+
title="Email Security Analyzer (Практика 3). Нуритдинов Марат (USE-26)",
|
| 140 |
+
description="Инструмент для оценки фишинга.",
|
| 141 |
examples=examples_list
|
| 142 |
).launch()
|