Files
152-fz-scanner/scanner/checks/external_scripts.py
T
neo de18090304 🏗 Фаза 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 — внешние скрипты аналитики
2026-06-09 21:10:21 +05:00

111 lines
3.9 KiB
Python

"""
Проверка внешних скриптов, собирающих данные пользователей.
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)}")