Descripción general
La integración nativa enviaba los eventos detection.opened directamente a una tabla de ServiceNow. Con los Feeds, usted elige qué tickets se entregan, y un pequeño script en ServiceNow convierte cada ticket en un registro de Incident.
Figura 1: Los dos modos de entrega. Ambos usan el mismo JSON y el mismo script de mapeo.
Push (Webhook 2.0): casi en tiempo real
La Plataforma Axur envía los tickets a un endpoint que usted crea en ServiceNow. Es la opción más parecida a la integración nativa, pero su instancia debe aceptar llamadas entrantes.
Pull (polling): más fácil de aprobar
ServiceNow consulta el feed cada X minutos. El tráfico es solo saliente, y la latencia es igual al intervalo de la programación.
Requisitos previos
Un usuario admin en ServiceNow (o web_service_admin para Push), un usuario manager en la Plataforma Axur para crear el feed y una API Key de la Plataforma Axur (para Pull).
Crear el feed en la Plataforma Axur
Vaya a one.axur.com/api-integrations → sección Feeds → Add feed → Skip templates.
Elija el tipo Tickets.
Elija el modo de entrega: Pull o Push. Para Push, ingrese la URL del endpoint que creará en el paso 6.
En Event date, seleccione First detection (
ticket.creation.date). Cada ticket llega una sola vez, igual que eldetection.openedde la integración nativa.En Feed parameters, déjelo en blanco para recibir todo o aplique un filtro, por ejemplo:
type=phishing,fake-social-media-profile.Defina un título, por ejemplo “ServiceNow – Incidents”, y guarde. Anote el ID/URL del feed.
Figura 2: Configuración sugerida del feed (ilustración; la pantalla real puede ser diferente).
¿También quiere recibir redetecciones?
Use Any detection (open.date). El script de abajo actualiza el incidente existente por ticketKey (correlation_id), así que ningún incidente se duplica.
Mapeo de campos
Cada elemento de collectionData.tickets[] se convierte en un registro de la tabla Incident. Los colores muestran de dónde viene cada dato:
Tabla de mapeo
Campo en ServiceNow | Origen en el JSON | Observaciones |
| fijo | Se define solo al crear. Las actualizaciones no reabren el incidente. |
|
| Se usa para evitar duplicados. |
|
| Igual que en la integración nativa. |
| Workspace - Tipo - | Mismo formato que la integración nativa. Limitado a 160 caracteres: solo se acorta la URL (con |
| Plantilla nativa (Figura 3b) | Link: |
Cuidado con las claves con punto
Campos como open.date y creation.date tienen un punto en el nombre. En JavaScript, use corchetes: d['open.date'], no d.open.date.
Script Include: el mapeador
Este script arma los campos y crea o actualiza el incidente. Se crea una sola vez y lo usan tanto Push como Pull.
En ServiceNow, vaya a System Definition › Script Includes → New.
Name:
AxurFeedMapper(debe ser exactamente este nombre).Pegue el código de abajo en el campo Script y guarde.
Figura 4: Creación del Script Include (ilustración).
TYPE_LABELS y WORKSPACES contienen las etiquetas oficiales que usa la Plataforma Axur, para que el texto coincida con el de la integración nativa. Los tipos que no están en la lista usan Axur Surface y el slug original por defecto, así que nada se rompe.
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;
}
};¿Otra tabla?
Si los registros no deben ir a incident, cambie el valor de TABLE. La tabla debe tener los campos correlation_id, short_description y description.
Opción A: Pull con un Scheduled Job
Elija esta opción si su instancia no puede recibir llamadas externas.
Guardar la URL y la API Key
Vaya a sys_properties.list (escríbalo en el filtro de navegación) → New.
Cree
axur.feed.urlcon la URL del feed, por ejemplo:https://api.axur.com/gateway/1.0/api/integration-feed/feeds/feed/<ID>.Cree
axur.feed.api_keycon la API Key de la Plataforma Axur y restrinja los Read roles aadmin.
Seguridad
Nunca escriba la API Key directamente en el script. Si su equipo de seguridad lo prefiere, use Connection & Credential Aliases en lugar de la system property.
Crear la programación
Vaya a System Definition › Scheduled Jobs → New → Automatically run a script of your choosing.
Name:
Axur Feed → Incident. Run: Periodically. Repeat interval:00:05:00(5 min).Pegue el script de abajo y guarde.
Figura 5: Scheduled Job que se ejecuta cada 5 minutos (ilustración).
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;
}
Cada llamada al feed avanza el puntero y devuelve la página siguiente. El loop continúa hasta que una página vuelve vacía, con un límite de 20 páginas por ejecución para que el job nunca se cuelgue. Consulte la documentación de la API para ver el formato del header de autenticación.
Opción B: Push con una Scripted REST API
Elija esta opción para recibir los tickets casi en tiempo real. Su instancia debe aceptar llamadas entrantes desde la Plataforma Axur.
Vaya a System Web Services › Scripted Web Services › Scripted REST APIs → New.
Name:
Axur Feed, API ID:axur_feed. Guarde.En la pestaña Resources → New: Name
tickets, HTTP methodPOST, Relative path/tickets.Pegue el script de abajo en el resource y guarde.
Copie el Resource path (por ejemplo:
https://<instance>.service-now.com/api/<scope>/axur_feed/tickets) e ingréselo como endpoint del feed Push en la Plataforma Axur.
Figura 6: Resource POST que recibe el Webhook 2.0 (ilustración).
(function process(request, response) {
var processed = AxurFeedMapper.processPayload(request.body.data);
response.setStatus(200);
response.setBody({ processed: processed });
})(request, response);Autenticación del endpoint
Por defecto, el resource exige autenticación de ServiceNow (Requires authentication). Configúrela según las opciones de autenticación disponibles en el feed Push de la Plataforma Axur (por ejemplo, un usuario de integración dedicado que solo pueda escribir en la tabla Incident). No desactive la autenticación.
Probar y validar
Pruebe sin avanzar el puntero: en Pull, agregue
?dry-run=trueal final deaxur.feed.url. Recibirá siempre los mismos tickets y no se pierde nada.Ejecute el job manualmente: abra el Scheduled Job → Execute Now.
Revise los incidentes en Incident › All, filtrando por Correlation ID no vacío.
Ejecútelo de nuevo. Gracias al upsert, la cantidad de incidentes no debería aumentar.
Busque errores en System Logs › Errors (mensajes que empiezan con
Axur feed:).¿Todo bien? Quite el
?dry-run=truepara que el puntero empiece a avanzar.
Consejo
Valide en una instancia de subproducción o de desarrollo antes de activarlo en producción.
Limitaciones y checklist
Integración nativa | Con Feeds |
| ✅ Cubierto (fecha del evento First detection o Any detection) |
Campos | ✅ Mismo formato, armado por el script |
Solo nuevas detecciones | ✅ Y más: filtros por tipo, incidente, takedown, cualquier actualización… |
Checklist de go-live
Feed creado en la Plataforma Axur con la fecha del evento y los filtros correctos
Script Include
AxurFeedMappercreadoTabla
TYPE_LABELSactualizada con los tipos que usaPull: properties
axur.feed.urlyaxur.feed.api_keycreadas (con lectura restringida)Pull: Scheduled Job activo · Push: endpoint registrado en el feed
Probado con
?dry-run=true, sin duplicados?dry-run=truequitado






