Інтеграція 1С-Бітрікс з антифрод-системою

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Інтеграція 1С-Бітрікс з антифрод-системою
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Інтеграція 1С-Бітрікс з антифрод-системою

Шахрайські замовлення в інтернет-магазинах — це не лише фінансові втрати через чарджбеки. Це ресурси операторів, кинутий товар на складі, зіпсовані відносини з платіжними системами при високому рівні суперечок. Вбудовані інструменти 1С-Бітрікс вирішують частину проблем (OTP-верифікація телефону, ліміти замовлень), але не замінюють спеціалізований антифрод. Потрібна інтеграція із зовнішньою системою оцінки ризиків.

Архітектура інтеграції

Антифрод-перевірка вбудовується в процес оформлення замовлення. Є два моменти для виклику:

Before order save — до запису в базу. Якщо антифрод блокує, замовлення не створюється. Плюс: чисто. Мінус: синхронний виклик додає затримку до оформлення замовлення (200–500 мс на API-виклик).

After order save — замовлення створюється зі статусом «На перевірці», антифрод перевіряє асинхронно. Результат оновлює статус. Плюс: немає затримки. Мінус: потрібна обробка черги.

Для більшості магазинів — синхронна перевірка перед збереженням замовлення з тайм-аутом 2–3 секунди.

Провайдери антифроду

Seon — REST API, виконує device fingerprinting, email/phone scoring, IP reputation. Популярний в e-commerce.

IPQS (IPQualityScore) — комплексна перевірка IP, email, phone, device. Бюджетний варіант.

Kount / Forter / Signifyd — enterprise-рішення з ML-моделями, що навчаються на даних конкретного магазину.

Власна модель на базі правил — якщо обсяг менше 200 замовлень/день, складні зовнішні системи надлишкові. Набір перевірок на PHP достатній.

Обробник перевірки замовлення

// /local/lib/Fraud/FraudCheckHandler.php
namespace Local\Fraud;

AddEventHandler('sale', 'OnBeforeOrderFinalAction', [FraudCheckHandler::class, 'check']);

class FraudCheckHandler
{
    public static function check(\Bitrix\Sale\Order $order): \Bitrix\Main\EventResult
    {
        if ($order->getId() > 0) {
            // Вже існуюче замовлення, оновлення — пропускаємо
            return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);
        }

        try {
            $checker = new FraudChecker();
            $result  = $checker->evaluate($order);

            if ($result->isBlocked()) {
                return new \Bitrix\Main\EventResult(
                    \Bitrix\Main\EventResult::ERROR,
                    new \Bitrix\Main\Error($result->getBlockReason())
                );
            }

            if ($result->requiresReview()) {
                // Позначаємо замовлення для ручної перевірки
                $order->setField('COMMENTS', '[FRAUD_REVIEW] Score: ' . $result->getScore());
            }

        } catch (\Throwable $e) {
            // Помилка антифроду не повинна блокувати замовлення
            \Bitrix\Main\Diag\Debug::writeToFile(
                ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()],
                'Fraud check error',
                '/local/logs/fraud.log'
            );
        }

        return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);
    }
}

Клас оцінки ризиків

namespace Local\Fraud;

class FraudChecker
{
    private const BLOCK_THRESHOLD  = 80;
    private const REVIEW_THRESHOLD = 50;

    public function evaluate(\Bitrix\Sale\Order $order): FraudResult
    {
        $score   = 0;
        $reasons = [];
        $props   = $order->getPropertyCollection();

        $ip    = $_SERVER['REMOTE_ADDR'];
        $email = $props->getItemByOrderPropertyCode('EMAIL')?->getValue() ?? '';
        $phone = $props->getItemByOrderPropertyCode('PHONE')?->getValue() ?? '';

        // Перевірки по IP
        $ipScore = $this->checkIp($ip);
        $score  += $ipScore['score'];
        if ($ipScore['score'] > 20) $reasons[] = $ipScore['reason'];

        // Перевірки по email
        $emailScore = $this->checkEmail($email);
        $score     += $emailScore['score'];
        if ($emailScore['score'] > 10) $reasons[] = $emailScore['reason'];

        // Частота замовлень
        $freqScore = $this->checkOrderFrequency($ip, $email, $phone);
        $score    += $freqScore['score'];
        if ($freqScore['score'] > 15) $reasons[] = $freqScore['reason'];

        // Сума замовлення
        $amountScore = $this->checkOrderAmount($order);
        $score      += $amountScore['score'];

        // Перевірка через зовнішній API (якщо налаштований)
        if (defined('FRAUD_API_KEY') && FRAUD_API_KEY) {
            $apiScore = $this->checkExternalApi($ip, $email, $phone, $order);
            $score   += $apiScore['score'];
            if ($apiScore['score'] > 20) $reasons[] = $apiScore['reason'];
        }

        $this->log($order->getId() ?: 0, $ip, $email, $score, $reasons);

        return new FraudResult($score, $reasons, self::BLOCK_THRESHOLD, self::REVIEW_THRESHOLD);
    }

    private function checkIp(string $ip): array
    {
        // VPN / Tor / datacenter IP — високий ризик
        $conn = \Bitrix\Main\Application::getConnection();

        // IP у стоп-листі 1С-Бітрікс
        $inStopList = $conn->query(
            "SELECT ID FROM b_stop_list WHERE IP_ADDR = '{$ip}' AND ACTIVE = 'Y' LIMIT 1"
        )->fetch();

        if ($inStopList) return ['score' => 60, 'reason' => 'IP in stop list'];

        // Кількість замовлень з цього IP за останні 24 години
        $orderCount = (int)$conn->query(
            "SELECT COUNT(*) cnt FROM b_sale_order
             WHERE CREATED_BY_IP = '{$ip}'
               AND DATE_INSERT   > DATE_SUB(NOW(), INTERVAL 24 HOUR)"
        )->fetch()['cnt'];

        if ($orderCount > 5)  return ['score' => 40, 'reason' => "IP: {$orderCount} orders/24h"];
        if ($orderCount > 2)  return ['score' => 15, 'reason' => "IP: {$orderCount} orders/24h"];

        return ['score' => 0, 'reason' => ''];
    }

    private function checkEmail(string $email): array
    {
        if (empty($email)) return ['score' => 20, 'reason' => 'No email'];

        // Одноразові домени
        $tempDomains = ['guerrillamail.com', 'mailinator.com', 'tempmail.com', 'throwam.com', 'yopmail.com'];
        $domain      = strtolower(substr(strrchr($email, '@'), 1));

        if (in_array($domain, $tempDomains)) return ['score' => 40, 'reason' => 'Disposable email'];

        // Кількість замовлень з цього email
        $conn = \Bitrix\Main\Application::getConnection();
        $emailSafe = $conn->getSqlHelper()->forSql($email);

        $orderCount = (int)$conn->query(
            "SELECT COUNT(*) cnt
             FROM b_sale_order_props_value pv
             JOIN b_sale_order_props p ON p.ID = pv.ORDER_PROPS_ID
             JOIN b_sale_order o       ON o.ID = pv.ORDER_ID
             WHERE p.CODE = 'EMAIL'
               AND pv.VALUE = '{$emailSafe}'
               AND o.DATE_INSERT > DATE_SUB(NOW(), INTERVAL 7 DAY)"
        )->fetch()['cnt'];

        if ($orderCount > 3) return ['score' => 25, 'reason' => "Email: {$orderCount} orders/week"];

        return ['score' => 0, 'reason' => ''];
    }

    private function checkOrderAmount(\Bitrix\Sale\Order $order): array
    {
        $price = (float)$order->getPrice();

        // Дуже велике замовлення від нового покупця — ризик
        $userId = (int)$order->getUserId();
        if ($price > 100000 && $userId > 0) {
            $conn        = \Bitrix\Main\Application::getConnection();
            $prevOrders  = (int)$conn->query(
                "SELECT COUNT(*) cnt FROM b_sale_order WHERE USER_ID = {$userId} AND STATUS_ID NOT IN ('C')"
            )->fetch()['cnt'];

            if ($prevOrders === 0) {
                return ['score' => 30, 'reason' => 'High amount + new customer'];
            }
        }

        return ['score' => 0, 'reason' => ''];
    }

    private function checkExternalApi(string $ip, string $email, string $phone, \Bitrix\Sale\Order $order): array
    {
        $http = new \Bitrix\Main\Web\HttpClient();
        $http->setHeader('Authorization', 'Bearer ' . FRAUD_API_KEY);
        $http->setTimeout(2); // жорсткий тайм-аут

        $response = $http->post('https://api.fraudprovider.com/v1/check', json_encode([
            'ip'     => $ip,
            'email'  => $email,
            'phone'  => $phone,
            'amount' => $order->getPrice(),
        ]));

        if ($http->getStatus() !== 200) return ['score' => 0, 'reason' => ''];

        $data = json_decode($response, true);
        $risk = (int)($data['risk_score'] ?? 0);

        return [
            'score'  => (int)($risk * 0.5), // нормалізуємо до нашої шкали
            'reason' => $risk > 70 ? "External API risk: {$risk}" : '',
        ];
    }

    private function log(int $orderId, string $ip, string $email, int $score, array $reasons): void
    {
        \Bitrix\Main\Diag\Debug::writeToFile(
            compact('orderId', 'ip', 'email', 'score', 'reasons'),
            'Fraud check',
            '/local/logs/fraud.log'
        );
    }
}

Адміністративний інтерфейс

В адміністративній частині — розділ «Антифрод» із:

  • Таблицею підозрілих замовлень (статус «На перевірці»)
  • Кнопками «Підтвердити» / «Відхилити»
  • Історією заблокованих спроб із IP та причинами
  • Можливістю додати IP або email до білого/чорного списку

Терміни реалізації

Конфігурація Термін
Базовий антифрод (IP, email, частота) 4–5 днів
+ інтеграція із зовнішнім API (Seon/IPQS) +2–3 дні
+ адміністративний інтерфейс, білі/чорні списки +2–3 дні
+ ML-скоринг на власних даних +2–4 тижні