概要
ネイティブ連携では、detection.opened イベントが ServiceNow のテーブルに直接送信されていました。Feeds を使うと、配信するチケットを自分で選択でき、ServiceNow 側の小さなスクリプトが各チケットを Incident レコードに変換します。
図 1:2 つの配信モード。どちらも同じ JSON と同じマッピングスクリプトを使用します。
Push (Webhook 2.0): ほぼリアルタイム
Axur プラットフォームが、ServiceNow に作成したエンドポイントへチケットを送信します。ネイティブ連携に最も近い方式ですが、インスタンスがインバウンド通信を受け付ける必要があります。
Pull (polling): 承認を得やすい
ServiceNow が X 分ごとにフィードを照会します。通信はアウトバウンドのみで、遅延はスケジュール間隔と同じになります。
前提条件
ServiceNow の admin ユーザー(Push の場合は web_service_admin)、フィード作成用の Axur プラットフォームの manager ユーザー、および Axur プラットフォームの API Key(Pull の場合)が必要です。
Axur プラットフォームでフィードを作成
one.axur.com/api-integrations を開き、Feeds セクション → Add feed → Skip templates の順に進みます。
タイプとして Tickets を選択します。
配信モードとして Pull または Push を選択します。Push の場合は、手順 6 で作成するエンドポイントの URL を入力します。
Event date で First detection(
ticket.creation.date) を選択します。ネイティブ連携のdetection.openedと同様に、各チケットは 1 回だけ届きます。Feed parameters は、すべて受信する場合は空欄のままにします。絞り込む場合は、例:
type=phishing,fake-social-media-profileのように指定します。タイトル(例:“ServiceNow – Incidents”)を設定して保存します。フィードの ID/URL を控えておいてください。
図 2:推奨フィード設定(イメージ図。実際の画面とは異なる場合があります)。
再検出も受信したい場合
Any detection(open.date) を使用してください。以下のスクリプトは ticketKey(correlation_id)で既存のインシデントを更新するため、インシデントが重複することはありません。
フィールドマッピング
collectionData.tickets[] の各項目が Incident テーブルの 1 レコードになります。色は各情報の取得元を示しています:
マッピング表
ServiceNow のフィールド | JSON 内の取得元 | 備考 |
| 固定値 | 作成時のみ設定されます。更新時にインシデントが再オープンされることはありません。 |
|
| 重複を防ぐために使用します。 |
|
| ネイティブ連携と同じです。 |
| ワークスペース - タイプ - | ネイティブ連携と同じ形式です。上限は 160 文字で、URL のみが( |
| ネイティブのテンプレート(図 3b) | リンク: |
ドットを含むキーに注意
open.date や creation.date などのフィールドは、名前にドットが含まれています。JavaScript では d.open.date ではなく、角括弧を使って d['open.date'] と記述してください。
Script Include:マッパー
このスクリプトはフィールドを組み立て、インシデントを作成または更新します。作成は 1 回だけ で、Push と Pull の両方で使用されます。
ServiceNow で System Definition › Script Includes → New を開きます。
Name:
AxurFeedMapper(必ずこの名前にしてください)。以下のコードを Script フィールドに貼り付けて保存します。
図 4:Script Include の作成(イメージ図)。
TYPE_LABELS と WORKSPACES には Axur プラットフォームで使われている公式ラベルが含まれているため、テキストがネイティブ連携と一致します。リストにないタイプは Axur Surface と元のスラッグが使われるため、処理が失敗することはありません。
var AxurFeedMapper = {
TABLE: 'incident',
TICKET_URL: 'https://one.axur.com/brand-protection/tickets/',
SHORT_DESCRIPTION_LIMIT: 160,
DEFAULT_WORKSPACE: 'Axur Surface',
WORKSPACES: {
'digital-fraud': 'Digital Fraud',
'online-piracy': 'Online Piracy',
'data-leakage': 'Data Leakage',
'deep-dark-web': 'Deep & Dark Web',
'executives-vips': 'Executives & VIPs'
},
TYPE_LABELS: {
'phishing': { workspace: 'digital-fraud', name: 'Phishing' },
'paid-search': { workspace: 'digital-fraud', name: 'Brand use in paid search' },
'malware': { workspace: 'digital-fraud', name: 'Malware' },
'fake-social-media-profile': { workspace: 'digital-fraud', name: 'Fake social media profile' },
'similar-domain-name': { workspace: 'digital-fraud', name: 'Similar domain name' },
'fake-mobile-app': { workspace: 'digital-fraud', name: 'Fake mobile app' },
'fraudulent-brand-use': { workspace: 'digital-fraud', name: 'Fraudulent brand use' },
'unauthorized-sale': { workspace: 'online-piracy', name: 'Counterfeit or irregular sale' },
'unauthorized-distribution': { workspace: 'online-piracy', name: 'Content piracy' },
'corporate-credential-leak': { workspace: 'data-leakage', name: 'Corporate credential leak' },
'code-secret-leak': { workspace: 'data-leakage', name: 'Code secret leak' },
'database-exposure': { workspace: 'data-leakage', name: 'Database exposure' },
'document-leak': { workspace: 'data-leakage', name: 'Document leak' },
'other-sensitive-data': { workspace: 'data-leakage', name: 'Other sensitive data' },
'infostealer-credential': { workspace: 'data-leakage', name: 'Infostealer credentials' },
'dw-activity': { workspace: 'deep-dark-web', name: 'Deep & Dark Web activity' },
'data-exposure-website': { workspace: 'deep-dark-web', name: 'Data exposure in website' },
'data-sale-website': { workspace: 'deep-dark-web', name: 'Data sale in website' },
'fraud-tool-scheme-website': { workspace: 'deep-dark-web', name: 'Fraud tool or scheme in website' },
'suspicious-activity-website': { workspace: 'deep-dark-web', name: 'Suspicious activity in website' },
'data-exposure-message': { workspace: 'deep-dark-web', name: 'Data exposure in messaging app' },
'data-sale-message': { workspace: 'deep-dark-web', name: 'Data sale in messaging app' },
'fraud-tool-scheme-message': { workspace: 'deep-dark-web', name: 'Fraud tool or scheme in messaging app' },
'suspicious-activity-message': { workspace: 'deep-dark-web', name: 'Suspicious activity in messaging app' },
'infrastructure-exposure': { workspace: 'deep-dark-web', name: 'Infrastructure exposure' },
'ransomware-attack': { workspace: 'deep-dark-web', name: 'Ransomware attack alert' },
'executive-fake-social-media-profile': { workspace: 'executives-vips', name: 'Fake social media profile' },
'executive-personalinfo-leak': { workspace: 'executives-vips', name: 'Personal information leak' },
'executive-credential-leak': { workspace: 'executives-vips', name: 'Credential leak' },
'executive-mobile-phone': { workspace: 'executives-vips', name: 'Phone number leak' },
'executive-card-leak': { workspace: 'executives-vips', name: 'Credit card leak' }
},
buildFields: function (item) {
var t = item.ticket || {};
var d = item.detection || {};
var ticketKey = t.ticketKey;
var type = d.type || '';
var label = this.TYPE_LABELS[type] || { workspace: '', name: type };
var workspace = this.WORKSPACES[label.workspace] || this.DEFAULT_WORKSPACE;
var threatUrl = t.reference || '';
var prefix = workspace + ' - ' + label.name + ' - ' + t.customerKey + ' - ';
var suffix = ' (' + ticketKey + ')';
var shortDescription = prefix + this.fitReference(threatUrl, prefix.length + suffix.length) + suffix;
var description = [
'Axur - one.axur.com',
'',
'New threat detected (' + this.TICKET_URL + ticketKey + ')',
'',
'Ticket Key: ' + ticketKey,
this.assetsLine(d.assets || []),
'Ticket Type: ' + label.name + ' (' + type + ')',
'Threat URL: ' + threatUrl,
'Detection Date: ' + this.formatDate(d['open.date'] || t['creation.date'])
].join('\n');
return { ticketKey: ticketKey, shortDescription: shortDescription, description: description };
},
fitReference: function (reference, usedLength) {
var available = this.SHORT_DESCRIPTION_LIMIT - usedLength;
if (reference.length <= available) return reference;
return reference.substring(0, Math.max(available - 3, 0)) + '...';
},
assetsLine: function (assets) {
return assets.length === 1 ? 'Asset: ' + assets[0] : 'Assets: (' + assets.join(', ') + ')';
},
formatDate: function (iso) {
if (!iso) return '';
return iso.substring(8, 10) + '/' + iso.substring(5, 7) + '/' + iso.substring(0, 4);
},
upsert: function (item) {
var f = this.buildFields(item);
if (!f.ticketKey) return;
var gr = new GlideRecord(this.TABLE);
gr.addQuery('correlation_id', f.ticketKey);
gr.query();
var exists = gr.next();
if (!exists) {
gr.initialize();
gr.state = 1;
}
gr.correlation_id = f.ticketKey;
gr.correlation_display = f.ticketKey;
gr.short_description = f.shortDescription;
gr.description = f.description;
if (exists) { gr.update(); } else { gr.insert(); }
},
processPayload: function (payload) {
var tickets = (payload && payload.collectionData && payload.collectionData.tickets) || [];
for (var i = 0; i < tickets.length; i++) {
this.upsert(tickets[i]);
}
return tickets.length;
}
};別のテーブルを使う場合
レコードの格納先を incident 以外にする場合は、TABLE の値を変更してください。対象テーブルには correlation_id、short_description、description フィールドが必要です。
オプション A:Scheduled Job による Pull
インスタンスが外部からの通信を 受け付けられない 場合は、このオプションを選択してください。
URL と API Key を保存する
sys_properties.list(ナビゲーションフィルターに入力)→ New を開きます。
axur.feed.urlを作成し、フィードの URL を設定します。例:https://api.axur.com/gateway/1.0/api/integration-feed/feeds/feed/<ID>.axur.feed.api_keyを作成して Axur プラットフォームの API Key を設定し、Read roles をadminに制限します。
セキュリティ
API Key をスクリプトに直接記述しないでください。セキュリティチームの方針に応じて、system property の代わりに Connection & Credential Aliases を使用することもできます。
スケジュールを作成する
System Definition › Scheduled Jobs → New → Automatically run a script of your choosing を開きます。
Name:
Axur Feed → Incident、Run:Periodically、Repeat interval:00:05:00(5 分)。以下のスクリプトを貼り付けて保存します。
図 5:5 分ごとに実行される Scheduled Job(イメージ図)。
var FEED_URL = gs.getProperty('axur.feed.url');
var API_KEY = gs.getProperty('axur.feed.api_key');
var MAX_PAGES = 20;
for (var page = 0; page < MAX_PAGES; page++) {
var request = new sn_ws.RESTMessageV2();
request.setEndpoint(FEED_URL);
request.setHttpMethod('GET');
request.setRequestHeader('Authorization', 'Bearer ' + API_KEY);
request.setRequestHeader('Accept', 'application/json');
var response = request.execute();
if (response.getStatusCode() != 200) {
gs.error('Axur feed: HTTP ' + response.getStatusCode() + ' - ' + response.getBody());
break;
}
var processed = AxurFeedMapper.processPayload(JSON.parse(response.getBody()));
if (processed === 0) break;
}
フィードを呼び出すたびにポインターが進み、次のページが返されます。ループは空のページが返るまで続きますが、ジョブが止まらないよう 1 回の実行につき最大 20 ページに制限しています。認証ヘッダーの形式については API ドキュメント を参照してください。
オプション B:Scripted REST API による Push
チケットを ほぼリアルタイム で受信したい場合は、このオプションを選択してください。インスタンスが Axur プラットフォームからのインバウンド通信を受け付ける必要があります。
System Web Services › Scripted Web Services › Scripted REST APIs → New を開きます。
Name:
Axur Feed、API ID:axur_feedを入力して保存します。Resources タブ → New で、Name に
tickets、HTTP method にPOST、Relative path に/ticketsを設定します。以下のスクリプトをリソースに貼り付けて保存します。
Resource path(例:
https://<instance>.service-now.com/api/<scope>/axur_feed/tickets)をコピーし、Axur プラットフォームの Push フィードのエンドポイントとして入力します。
図 6:Webhook 2.0 を受信する POST リソース(イメージ図)。
(function process(request, response) {
var processed = AxurFeedMapper.processPayload(request.body.data);
response.setStatus(200);
response.setBody({ processed: processed });
})(request, response);エンドポイントの認証
デフォルトでは、このリソースには ServiceNow の認証(Requires authentication)が必要です。Axur プラットフォームの Push フィードで利用できる認証方式に合わせて設定してください(例:Incident テーブルへの書き込み権限のみを持つ専用の連携ユーザー)。認証は無効にしないでください。
テストと検証
ポインターを進めずにテスト:Pull の場合は、
axur.feed.urlの末尾に?dry-run=trueを追加します。毎回同じチケットが返され、データが失われることはありません。ジョブを手動で実行します:Scheduled Job を開き → Execute Now。
Incident › All で、Correlation ID が空でないもので絞り込んでインシデントを確認します。
もう一度実行します。upsert により、インシデントの件数は 増えないはず です。
System Logs › Errors でエラーを確認します(
Axur feed:で始まるメッセージ)。問題がなければ、ポインターが進むように
?dry-run=trueを削除 します。
ヒント本番環境で有効にする前に、サブ本番環境または開発環境のインスタンスで検証してください。
制限事項とチェックリスト
ネイティブ連携 | Feeds の場合 |
| ✅ 対応(イベント日付 First detection または Any detection) |
| ✅ 同じ形式(スクリプトで生成) |
新規検出のみ | ✅ さらに:タイプ、インシデント、テイクダウン、あらゆる更新などでのフィルタリングが可能… |
本番稼働前チェックリスト
正しいイベント日付とフィルターで Axur プラットフォームにフィードを作成済み
AxurFeedMapperScript Include を作成済み使用するタイプで
TYPE_LABELSテーブルを更新済みPull:
axur.feed.urlとaxur.feed.api_keyのプロパティを作成済み(読み取り制限あり)Pull:Scheduled Job が有効 · Push:フィードにエンドポイントを登録済み
?dry-run=trueでテスト済み、重複なし?dry-run=trueを削除済み






