🏗 Фаза 1-4: Архитектура, ядро, проверки, API, генератор отчетов
- scanner/engine.py — Playwright-движок сканирования - scanner/models.py — Pydantic модели - scanner/checks/ — 5 проверок (cookie, privacy, forms, server, external) - api/server.py — FastAPI REST API - reports/generator.py — PDF через WeasyPrint + Jinja2 - main.py — CLI + сервер Проверки: ✅ cookie_banner — поиск cookie-баннера ✅ privacy_link — проверка ссылки на политику ✅ form_checkbox — проверка чекбоксов согласия ✅ server_location — геолокация сервера (RФ или нет) ✅ external_scripts — внешние скрипты аналитики
This commit is contained in:
commit
de18090304
20 files changed
+1665
No files matched your search
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
Проверка внешних скриптов, собирающих данные пользователей.
|
||||
Google Analytics, Facebook Pixel, Яндекс.Метрика и другие —
|
||||
отправляют данные на сервера за пределами РФ.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from playwright.async_api import Page
|
||||
|
||||
from scanner.checks.base import BaseCheck
|
||||
from scanner.models import CheckResult, RiskLevel
|
||||
|
||||
|
||||
class ExternalScriptsCheck(BaseCheck):
|
||||
"""Проверяет наличие внешних скриптов, передающих данные за пределы РФ."""
|
||||
|
||||
name = "external_scripts"
|
||||
title = "Внешние скрипты аналитики"
|
||||
description = "Ищет скрипты Google Analytics, Facebook Pixel и другие иностранные сервисы"
|
||||
risk_on_fail = RiskLevel.HIGH
|
||||
default_weight = 15
|
||||
|
||||
EXTERNAL_PATTERNS = [
|
||||
r"google-analytics\.com",
|
||||
r"googletagmanager\.com",
|
||||
r"googlesyndication\.com",
|
||||
r"googleadservices\.com",
|
||||
r"googleapis\.com",
|
||||
r"google\.com/recaptcha",
|
||||
r"facebook\.com/tr",
|
||||
r"fbcdn\.net",
|
||||
r"connect\.facebook\.net",
|
||||
r"mc\.yandex\.ru",
|
||||
r"monitoring\.yandex\.ru",
|
||||
r"top\.mail\.ru",
|
||||
r"clarity\.microsoft\.com",
|
||||
r"hotjar\.com",
|
||||
r"mixpanel\.com",
|
||||
r"segment\.com",
|
||||
r"amplitude\.com",
|
||||
r"zendesk\.com",
|
||||
r"intercom\.io",
|
||||
r"chatra\.com",
|
||||
r"tilda\.cdn",
|
||||
r"wix\.com",
|
||||
r"wordpress\.com",
|
||||
r"shopify\.com",
|
||||
]
|
||||
|
||||
async def check(self, page: Page, url: str) -> CheckResult:
|
||||
try:
|
||||
html = await page.evaluate("() => document.documentElement.outerHTML")
|
||||
|
||||
found_scripts = []
|
||||
for pattern in self.EXTERNAL_PATTERNS:
|
||||
matches = re.findall(pattern, html, re.IGNORECASE)
|
||||
if matches:
|
||||
found_scripts.append({
|
||||
"pattern": pattern,
|
||||
"matches": len(matches),
|
||||
})
|
||||
|
||||
if not found_scripts:
|
||||
return self._pass_result(
|
||||
message="Внешние скрипты аналитики не найдены.",
|
||||
)
|
||||
|
||||
critical_services = [
|
||||
"google-analytics",
|
||||
"googletagmanager",
|
||||
"facebook",
|
||||
"clarity",
|
||||
"segment",
|
||||
"amplitude",
|
||||
]
|
||||
|
||||
has_critical = False
|
||||
for script in found_scripts:
|
||||
if any(re.search(c, script["pattern"]) for c in critical_services):
|
||||
has_critical = True
|
||||
break
|
||||
|
||||
if has_critical:
|
||||
return self._fail_result(
|
||||
message=(
|
||||
f"Найдены внешние скрипты передачи данных: "
|
||||
f"{', '.join(s['pattern'] for s in found_scripts)}. "
|
||||
f"Они передают персональные данные за пределы РФ."
|
||||
),
|
||||
details={
|
||||
"scripts_found": found_scripts,
|
||||
"has_critical": True,
|
||||
},
|
||||
)
|
||||
|
||||
return self._fail_result(
|
||||
message=(
|
||||
f"Найдены внешние скрипты: "
|
||||
f"{', '.join(s['pattern'] for s in found_scripts)}. "
|
||||
f"Требуется согласие пользователя."
|
||||
),
|
||||
details={
|
||||
"scripts_found": found_scripts,
|
||||
"has_critical": False,
|
||||
},
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return self._error_result(message=f"Ошибка: {str(e)}")
|
||||
Reference in new issue
Block a user