Реализация проверки подлинности документов (Anti-Fraud Detection)
Проверка подлинности документов — задача обнаружения подделок: цифровых фальсификаций (Photoshop, copy-paste), физических подделок (ламинат, чернила), и «живых» манипуляций (прикрытие части документа, подмена фото). Это security-critical система, которая должна работать против мотивированного злоумышленника с доступом к современным инструментам редактирования.
Многоуровневая архитектура анти-фрод проверки
class AntifraudDocumentChecker:
def __init__(self):
self.manipulation_detector = ManipulationDetector()
self.metadata_analyzer = MetadataAnalyzer()
self.security_feature_detector = SecurityFeatureDetector()
self.consistency_checker = ConsistencyChecker()
def analyze(self, image_path: str,
doc_type: str) -> FraudAnalysisResult:
result = FraudAnalysisResult()
# 1. Анализ метаданных изображения
result.metadata_issues = self.metadata_analyzer.check(image_path)
# 2. Обнаружение следов цифровой манипуляции
result.manipulation_score = self.manipulation_detector.score(image_path)
# 3. Проверка защитных элементов документа
result.security_features = self.security_feature_detector.check(
image_path, doc_type
)
# 4. Консистентность данных внутри документа
result.consistency_score = self.consistency_checker.check(
image_path, doc_type
)
# 5. Итоговый риск-скор
result.fraud_score = self._compute_fraud_score(result)
result.verdict = 'suspicious' if result.fraud_score > 0.7 else 'clear'
return result
Обнаружение цифровых манипуляций
Error Level Analysis (ELA) — классический метод: области, изменённые в JPEG, имеют другой уровень ошибок сжатия:
import cv2
import numpy as np
from PIL import Image
import io
def error_level_analysis(image_path: str, quality: int = 95) -> np.ndarray:
"""ELA для обнаружения JPEG-манипуляций"""
original = Image.open(image_path)
# Пере-сжимаем с заданным качеством
buffer = io.BytesIO()
original.save(buffer, format='JPEG', quality=quality)
buffer.seek(0)
recompressed = Image.open(buffer)
# Разница
ela_image = np.array(original, dtype=np.float32) - \
np.array(recompressed, dtype=np.float32)
# Усиливаем для визуализации
ela_image = np.abs(ela_image) * 10
ela_image = np.clip(ela_image, 0, 255).astype(np.uint8)
return ela_image
CNN-based Manipulation Detection — нейросетевой детектор обнаруживает манипуляции более точно:
from transformers import AutoModelForImageClassification
class ManipulationDetector:
def __init__(self):
# Модель обученная на реальных/поддельных документах
self.model = AutoModelForImageClassification.from_pretrained(
'path/to/manipulation_detector'
)
self.model.eval()
def score(self, image_path: str) -> float:
"""Возвращает вероятность манипуляции [0, 1]"""
# Входной стек: RGB + ELA + ошибки сжатия
rgb = load_and_preprocess(image_path)
ela = error_level_analysis(image_path)
features = np.stack([rgb, ela], axis=0)
with torch.no_grad():
output = self.model(tensor_from(features))
return float(torch.sigmoid(output.logits[:, 1]))
Проверка защитных элементов
Защитные элементы документов: водяные знаки, голографические наклейки, микропечать, гильоши (волнистые узоры). Для каждого типа документа описываем ожидаемые визуальные признаки:
def check_watermark(image: np.ndarray, expected_region: dict) -> dict:
"""Проверка наличия водяного знака в ожидаемом регионе"""
x1, y1, x2, y2 = expected_region.values()
roi = image[y1:y2, x1:x2]
# FFT-анализ для выявления регулярных паттернов (гильош)
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
f_transform = np.fft.fft2(gray)
f_shift = np.fft.fftshift(f_transform)
magnitude = 20 * np.log(np.abs(f_shift) + 1)
# Наличие характерных частот в гильоше
expected_freq_present = analyze_frequency_pattern(magnitude)
return {
'watermark_detected': expected_freq_present,
'confidence': compute_pattern_confidence(magnitude)
}
Анализ консистентности шрифта
Подмена цифр или букв в документе часто выдаётся по несоответствию шрифта: другая толщина штриха, другая кегль, другой интерлиньяж.
def check_font_consistency(ocr_words: list[dict]) -> dict:
"""Проверка консистентности шрифтовых признаков"""
# Кластеризация по высоте символов
heights = [word['height'] for word in ocr_words]
# Если есть группа слов с сильно отличающейся высотой — подозрительно
mean_height = np.mean(heights)
std_height = np.std(heights)
outliers = [w for w in ocr_words
if abs(w['height'] - mean_height) > 3 * std_height]
return {
'consistent': len(outliers) == 0,
'suspicious_words': [w['text'] for w in outliers],
'anomaly_score': len(outliers) / max(len(ocr_words), 1)
}
| Тип мошенничества | Метод детекции | Эффективность |
|---|---|---|
| Photoshop (клон, вставка) | ELA + CNN | 89–94% |
| Изменение цифр в документе | Font consistency | 82–88% |
| Поддельные защитные элементы | FFT + CV | 76–84% |
| Скриншот документа (не оригинал) | EXIF + Moire detection | 91–96% |
| Масштаб системы | Срок |
|---|---|
| Базовая проверка (ELA + метаданные) | 3–4 недели |
| Полная антифрод-система | 8–12 недель |
| Integration в KYC с мониторингом | 12–18 недель |







