INTEGRITY Документация

Аномалии BGP

Чтобы получить доступ к результатам BGP Anomaly Detection в Cloudflare Radar, сначала нужно создать API-токен, который включает Account:Radar разрешение. Все следующие примеры должны работать с бесплатным аккаунтом Cloudflare.

Поиск событий перехвата BGP

В следующем примере мы отправим запрос к API событий угонов BGP о последних случаях перехвата источника BGP, инициированных или затронувших AS64512 (пример ASN).

curl "https://api.cloudflare.com/client/v4/radar/bgp/hijacks/events?invlovedAsn=64512&format=json&per_page=10" \
--header "Authorization: Bearer <API_TOKEN>"

Результат показывает 10 самых недавних случаев перехвата BGP-маршрутов, затрагивающих AS64512.

{
  "success": true,
  "errors": [],
  "result": {
    "asn_info": [
      {
        "asn": 64512,
        "org_name": "XXXXX",
        "country_code": "XX"
      },
      ...
    ],
    "events": [
      {
        "duration": 0,
        "event_type": 0,
        "hijack_msgs_count": 1,
        "hijacker_asn": 64512,
        "id": 1234,
        "is_stale": false,
        "max_hijack_ts": "2023-04-27T14:01:55.952",
        "max_msg_ts": "2023-04-27T14:01:55.952",
        "min_hijack_ts": "2023-04-27T14:01:55.952",
        "on_going_count": 1,
        "peer_asns": [
          8455
        ],
        "peer_ip_count": 1,
        "prefixes": [
          "192.0.2.0/24"
        ],
        "tags": [
          {
            "name": "irr_new_origin_invalid",
            "score": 4
          },
          {
            "name": "irr_old_origin_valid",
            "score": 0
          },
          ...
        ],
        "victim_asns": [
          64513
        ],
        "confidence_score": 4
      },
    ],
    "total_monitors": 163
  },
  ...
}

Из ответа мы можем получить следующую информацию о каждом событии:

Пользователи могут дополнительно отфильтровать события с низким уровнем достоверности, добавив minConfidence=8 параметр, который вернет только события с confidence_score 8 или выше.

curl "https://api.cloudflare.com/client/v4/radar/bgp/hijacks/events?invlovedAsn=64512&format=json&per_page=10&minConfidence=8" \
--header "Authorization: Bearer <API_TOKEN>"

Поиск событий утечки маршрутов BGP

Утечка маршрутов BGP представляет собой еще один тип аномалий BGP, которые обнаруживает Cloudflare Radar. Сейчас мы уделяем особое внимание обнаружению конкретно provider-customer-provider тип утечки маршрута. Подробнее о нашем подходе и методологии можно узнать в наша запись в блоге ↗.

В следующем примере мы отправим запрос к API событий утечек маршрутов BGP о последних случаях утечки маршрутов BGP, затронувших AS64512.

curl "https://api.cloudflare.com/client/v4/radar/bgp/leaks/events?invlovedAsn=64512&format=json&per_page=10" \
--header "Authorization: Bearer <API_TOKEN>"

Результат показывает 10 самых недавних случаев утечки BGP-маршрутов, затрагивающих AS64512.

{
  "success": true,
  "errors": [],
  "result": {
    "asn_info": [
      {
        "asn": 64512,
        "org_name": "XXXXXXX",
        "country_code": "XX"
      },
      ...
    ],
    "events": [
      {
        "detected_ts": "2023-04-21T23:10:06",
        "finished": false,
        "id": 1234,
        "leak_asn": 64512,
        "leak_count": 14,
        "leak_seg": [
          64514,
          64512,
          64513
        ],
        "leak_type": 1,
        "max_ts": "2023-04-21T23:10:56",
        "min_ts": "2023-04-21T23:09:46",
        "origin_count": 1,
        "peer_count": 13,
        "prefix_count": 1
      },
      ...
    ]
  },
  ...
}

Из ответа мы можем получить следующую информацию о каждом событии:

Отправка оповещений о перехватах BGP

В этом примере мы покажем, как создать приложение на Cloudflare Workers, которое отправляет оповещения о перехватах BGP для заданного ASN через вебхуки (подходит для Google Hangouts, Discord, Telegram и других сервисов) или по электронной почте.

В качестве платформы будем использовать Cloudflare Workers, а для периодической проверки новых оповещений применим Cron Triggers.

От приложения нам нужно следующее:

Настройка приложения Worker

Начнем с настройки приложения Cloudflare Worker.

Сначала создайте новое приложение Workers в локальном каталоге:

npm create cloudflare@latest -- hijack-alerts

Для настройки выберите следующие параметры:

Чтобы начать разработку Worker, cd в каталог вашего нового проекта:

cd hijack-alerts

В файле Wrangler измените частоту проверки по умолчанию (раз в час) на нужное вам значение. Ниже приведён пример настройки worker для запуска скрипта каждые пять минут.

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "hijack-alerts",
	"main": "src/index.js",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"triggers": {
		"crons": [
			"*/5 * * * *"
		]
	}
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "hijack-alerts"
main = "src/index.js"
# Set this to today's date
compatibility_date = "2026-08-28"

[triggers]
crons = [ "*/5 * * * *" ]

В этом примере нам также понадобится Cloudflare KV, чтобы сохранять идентификаторы последних проверенных событий и таким образом определять, какие события новые. После того как вы создадите хранилище KV, вернитесь к wrangler.jsonc файл и добавьте следующие разделы:

{
	"kv_namespaces": [
		{
			"binding": "HIJACKS_KV",
			"id": "KV_ID_FOR_PRODUCTION",
			"preview_id": "TEMPORARY_KV_FOR_DEV_ENVIRONMENT"
		}
	]
}
[[kv_namespaces]]
binding = "HIJACKS_KV"
id = "KV_ID_FOR_PRODUCTION"
preview_id = "TEMPORARY_KV_FOR_DEV_ENVIRONMENT"

Получение данных о недавно обнаруженных перехватах BGP

Начните с функции получения данных через API.

Следующие apiFetch(env, paramsStr) отвечает за прием строки параметров запроса, формирование корректных заголовков и обращение к конечной точке Cloudflare API для перехватов BGP.

async function apiFetch(env, paramsStr) {
	const config = {
		headers: {
			Authorization: `Bearer ${env.CF_API_TOKEN}`,
		},
	};
	const res = await fetch(
		`https://api.cloudflare.com/client/v4/radar/bgp/hijacks/events?${paramsStr}`,
		config,
	);

	if (!res.ok) {
		console.log(JSON.stringify(res));
		return null;
	}
	return await res.json();
}

env параметр передается вызывающей стороной, и нам не нужно заботиться о его формировании. paramsStr это строковая переменная, которая хранит параметры запроса в URL запроса.

Теперь в нашей основной функции cron trigger нам нужно сформировать параметры запроса и вызвать функцию обращения к API. Сценарий worker'а с cron trigger по умолчанию выглядит так:


export default {
    async scheduled(controller, env, ctx) {
    ...
    }
}

В нашем примере используется env переменные, чтобы получить переменные времени выполнения, такие как TOKEN и интересующий ASN, а также привязки Cloudflare KV. Мы не используем controller и ctx переменные в этом примере.

Сначала нужно разобраться, что такое новые события. Мы определяем новые события как события, которые приложение ещё не обработало. Мы используем хранилище Cloudflare KV, созданное и определённое ранее (HIJACKS_KV) для сохранения и получения идентификатора последнего обработанного события.

let kv_latest_id = parseInt(await env.HIJACKS_KV.get("latest_id"));
const first_batch = isNaN(kv_latest_id);

Основной цикл, проверяющий последние события, выглядит следующим образом (часть кода проверки опущена):

let new_events = [];
let page = 1;
while (true) {
	// query for events
	const query_params = `per_page=10&page=${page}&involvedAsn=${env.TARGET_ASN}&sortBy=ID&sortOrder=DESC`;
	const data = await apiFetch(env, query_params);

	// first batch, save KV value only
	if (first_batch) {
		await env.HIJACKS_KV.put("latest_id", events[0].id.toString());
		return;
	}

	// some validation skipped
	// ...

	let reached_last = false;
	for (const event of data.result.events) {
		if (event.id <= kv_latest_id) {
			// reached the latest events
			reached_last = true;
			break;
		}
		new_events.push(event);
	}
	if (reached_last) {
		break;
	}
	page += 1;
}

Теперь, когда все новые обнаруженные события сохранены в new_events переменную, после чего можно отправлять оповещения:

// sort events by increasing ID order
new_events.sort((a, b) => a.id - b.id);
const kv_latest_id = new_events[new_events.length - 1].id;
// push new events
for (const event of new_events) {
	await send_alert(env, event);
}
// update latest_id KV value
await env.HIJACKS_KV.put("latest_id", kv_latest_id.toString());

Отправка оповещений через webhook

Функция send_alert отвечает за формирование сообщения оповещения и отправку оповещений через webhook. Здесь показан пример текстового шаблона сообщения для webhook Google Hangouts. Пользователи могут настраивать сообщение и использование webhook в зависимости от своей выбранной платформы и потребностей.

async function send_hangout_alert(env, event) {
	const webhook_url = `${env.WEBHOOK_URL}&threadKey=bgp-hijacks-event-${event.id}`;

	const data = JSON.stringify({
		text: `Detected BGP hijack event (${event.id}):
Detected time: *${event.min_hijack_ts} UTC*
Detected ASN: *${event.hijacker_asn}*
Expected ASN(s): *${event.victim_asns.join(" ")}*
Prefixes: *${event.prefixes.join(" ")}*
Tags: *${event.tags.map((tag) => tag.name).join(" ")}*
Peer Count: *${event.peer_ip_count}*
`,
	});
	await fetch(webhook_url, {
		method: "POST",
		headers: {
			"Content-Type": "application/json; charset=UTF-8",
		},
		body: data,
	});
}

Обратите внимание, что вебхук считается секретным значением и должен передаваться в окружение через wrangler secret put WEBHOOK_URL команда.

Последний шаг: развернуть приложение с помощью команды npx wrangler deploy и приложение должно быть запущено и работать в вашем аккаунте Cloudflare, выполняясь каждые пять минут.

Отправка email-оповещений из Workers

Если у вас есть Email Routing включено для вашего домена, вы также можете отправлять email-оповещения прямо из Workers. См. Отправка писем из Workers чтобы узнать больше.

Чтобы это оповещение работало, необходимо настроить соответствующие email-привязки в конфигурационный файл Wrangler.

{
	"send_email": [
		{
			"type": "send_email",
			"name": "SEND_EMAIL_BINDING",
			"destination_address": "<YOUR_EMAIL>@example.com"
		}
	]
}
[[send_email]]
type = "send_email"
name = "SEND_EMAIL_BINDING"
destination_address = "<YOUR_EMAIL>@example.com"

После этого можно создать функцию отправки писем, которая будет направлять оповещения на указанный вами адрес назначения:

async function send_email_alert(hijacker, prefixes, victims) {
	const msg = createMimeMessage();
	msg.setSender({
		name: "BGP Hijack Alerter",
		addr: "<YOUR_APP>@<YOUR_APP_DOMAIN>",
	});
	msg.setRecipient("<YOUR_EMAIL>@example.com");
	msg.setSubject("BGP hijack alert");
	msg.addMessage({
		contentType: "text/plain",
		data: `BGP hijack detected:
    Detected origin: ${hijacker}
    Expected origins: ${victims.join(" ")}
    Prefixes: ${prefixes.join(" ")}
    `,
	});

	var message = new EmailMessage(
		"<YOUR_APP>@<YOUR_APP_DOMAIN>",
		"<YOUR_EMAIL>@example.com",
		msg.asRaw(),
	);
	try {
		await env.SEND_EMAIL_BINDING.send(message);
	} catch (e) {
		return new Response(e.message);
	}
}

Следующие шаги

См. нашу документацию по API, чтобы узнать о Утечки маршрутов BGP и Угоны BGP для получения дополнительной информации по этим темам.