BGP異常
ベータCloudflare RadarのBGP異常検出結果にアクセスするには、まずUser:User Details権限を含むAPIトークンを作成する必要があります。以下のすべての例は、無料プランのCloudflareアカウントで動作するはずです。
以下の例では、BGPハイジャックイベントAPIをクエリして、AS64512(例のASN)によって発生した、または影響を受けた最新のBGPオリジンハイジャックを取得します。
curl "https://api.cloudflare.com/client/v4/radar/bgp/hijacks/events?invlovedAsn=64512&format=json&per_page=10" \--header "Authorization: Bearer <API_TOKEN>"結果は、AS64512に影響を与える最新の10件のBGPハイジャックイベントを示します。
{ "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 }, ...}レスポンスから、各イベントに関する以下の情報を知ることができます:
hijack_msg_count: すべてのピアから観測された潜在的なBGPハイジャックメッセージの数。peer_asns: ハイジャックメッセージを観測したルートコレクターピアのAS番号。prefixes: 影響を受けたプレフィックス。hijacker_asnおよびvictim_asns: 潜在的なハイジャッカーASNおよび被害者ASN。confidence_score: このイベントがハイジャックであることに対するシステムの信頼度を示す定量的スコア:- 1-3: 低信頼度。
- 4-7: 中信頼度。
- 8以上: 高信頼度。
tags: イベントに対して収集された証拠。各tagは全体の信頼度スコアに影響を与えるスコアに関連付けられています:- 正のスコアは、そのイベントがハイジャックである可能性が_高い_ことを示します。
- 負のスコアは、そのイベントがハイジャックである可能性が_低い_ことを示します。
ユーザーは、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ルートリークは、Cloudflare Radarが検出する別のタイプのBGP異常です。現在、特にprovider-customer-providerタイプのルートリークの検出に焦点を当てています。私たちの設計と方法論については、私たちのブログ記事 ↗で詳しく学ぶことができます。
以下の例では、BGPルートリークイベントAPIをクエリして、AS64512に影響を与える最新のBGPルートリークイベントを取得します。
curl "https://api.cloudflare.com/client/v4/radar/bgp/leaks/events?invlovedAsn=64512&format=json&per_page=10" \--header "Authorization: Bearer <API_TOKEN>"結果は、AS64512に影響を与える最新の10件のBGPルートリークイベントを示します。
{ "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 }, ... ] }, ...}レスポンスから、各イベントに関する以下の情報を知ることができます:
leak_asn: リークを引き起こした可能性のあるAS。leak_seg: 観測され、リークであると考えられるASパスセグメント。min_tsおよびmax_ts: リークアナウンスの最も早いおよび最新のタイムスタンプ。leak_count: 観測されたBGPルートリークアナウンスの総数。peer_count: リークを観測したルートコレクターピアの数。prefix_countおよびorigin_count: リークの影響を受けたプレフィックスとオリジンASの数。
この例では、特定のASNに関連するBGPハイジャックのアラートをWebhook(Google Hangouts、Discord、Telegramなどで動作)またはメールを使用して送信するCloudflare Workersアプリを構築する方法を示します。
Cloudflare Workersをプラットフォームとして使用し、Cronトリガーを利用して定期的に新しいアラートをチェックします。
アプリには以下の機能を持たせたいと思います:
- 指定されたAPIトークンを使用してCloudflare APIからデータを取得。
- Cloudflare KVをチェックして、新しいイベントを把握。
- 新しいハイジャックのメッセージを構築し、Webhookトリガーを介してアラートを送信。
まず、ローカルディレクトリに新しいWorkersアプリを作成します:
npm create cloudflare@latest -- hijack-alertsyarn create cloudflare@latest hijack-alertspnpm create cloudflare@latest hijack-alertsFor setup, select the following options:
- For What would you like to start with?, choose
デモアプリケーション. - For Which template would you like to use?, choose
スケジュールされたWorker (Cron Trigger). - For Which language do you want to use?, choose
JavaScript. - For Do you want to use git for version control?, choose
Yes. - For Do you want to deploy your application?, choose
No(we will be making some changes before deploying).
Workerの開発を開始するには、新しいプロジェクトディレクトリにcdします:
cd hijack-alertswrangler.tomlファイルで、デフォルトのチェック頻度(1時間ごと)をお好みに変更します。以下は、スクリプトを5分ごとに実行するように設定する例です。
name = "hijack-alerts"main = "src/index.js"compatibility_date = "2023-04-27"
[triggers]crons = [ "*/5 * * * *" ]この例では、最新のチェックイベントIDを保存するためにCloudflare KVを使用する必要があります。KVを作成したら、wranglers.tomlファイルに以下のセクションを追加します:
[[kv_namespaces]]binding = "HIJACKS_KV"id = "KV_ID_FOR_PRODUCTION"preview_id = "TEMPORARY_KV_FOR_DEV_ENVIRONMENT"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トリガー関数内で、クエリパラメータを構築し、API取得関数を呼び出す必要があります。デフォルトのCronトリガーWorkerスクリプトは以下のように定義されています:
export default { async scheduled(controller, env, ctx) { ... }}この例では、env変数を使用して、TOKENや関心のあるASN、Cloudflare KVバインディングなどのランタイム変数を取得します。controllerおよびctx変数はこの例では使用しません。
まず、新しいイベントが何であるかを把握する必要があります。新しいイベントは、アプリがまだ処理していないイベントとして定義します。以前に作成し定義したCloudflare KVバケット(HIJACKS_KV)を使用して、最新の処理済みイベントIDを保存および取得します。
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) { // イベントをクエリ const query_params = `per_page=10&page=${page}&involvedAsn=${env.TARGET_ASN}&sortBy=ID&sortOrder=DESC`; const data = await apiFetch(env, query_params);
// 最初のバッチ、KV値のみ保存 if (first_batch) { await env.HIJACKS_KV.put("latest_id", events[0].id.toString()); return; }
// 一部の検証は省略 // ...
let reached_last = false; for (const event of data.result.events) { if (event.id <= kv_latest_id) { // 最新のイベントに到達 reached_last = true; break; } new_events.push(event); } if (reached_last) { break; } page += 1;}新しく検出されたイベントがnew_events変数に保存されたので、アラートを送信できます:
// イベントをIDの昇順でソートnew_events.sort((a, b) => a.id - b.id);const kv_latest_id = new_events[new_events.length - 1].id;// 新しいイベントをプッシュfor (const event of new_events) { await send_alert(env, event);}// 最新のID KV値を更新await env.HIJACKS_KV.put("latest_id", kv_latest_id.toString());send_alert関数は、アラートメッセージを構築し、Webhookを使用してアラートを送信します。ここでは、Google Hangouts Webhookを使用したプレーンテキストメッセージテンプレートの例を示します。ユーザーは、メッセージや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: `検出されたBGPハイジャックイベント (${event.id}):検出時間: *${event.min_hijack_ts} UTC*検出ASN: *${event.hijacker_asn}*期待されるASN(s): *${event.victim_asns.join(" ")}*プレフィックス: *${event.prefixes.join(" ")}*タグ: *${event.tags.map((tag) => tag.name).join(" ")}*ピア数: *${event.peer_ip_count}*`, }); await fetch(webhook_url, { method: "POST", headers: { "Content-Type": "application/json; charset=UTF-8", }, body: data, });}Webhookは秘密と見なされ、wrangler secret put WEBHOOK_URLコマンドを介して環境に設定する必要があります。
最後のステップは、npx wrangler deployコマンドでアプリケーションをデプロイすることで、アプリがCloudflareアカウントで稼働し、5分ごとに実行されるようにトリガーされます。
ドメインにEmail Routingが有効になっている場合、Workersから直接メールアラートを送信することもできます。詳細については、Workersからのメール送信を参照してください。
このアラートが機能するためには、wrangler.tomlファイルに適切なメールバインディングを設定する必要があります。
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ハイジャックアラート", addr: "<YOUR_APP>@<YOUR_APP_DOMAIN>", }); msg.setRecipient("<YOUR_EMAIL>@example.com"); msg.setSubject("BGPハイジャックアラート"); msg.addMessage({ contentType: "text/plain", data: `BGPハイジャックが検出されました: 検出されたオリジン: ${hijacker} 期待されるオリジン: ${victims.join(" ")} プレフィックス: ${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); }}BGPルートリークやBGPハイジャックに関する詳細情報については、APIドキュメントを参照してください。