Descripción general
Un Credentials Feed entrega las credenciales expuestas (inicios de sesión filtrados de empleados o clientes) que detecta la Plataforma Axur. Un pequeño script en ServiceNow convierte cada credencial en un registro de Incidente, para que su equipo pueda restablecer la contraseña y dar seguimiento a la respuesta.
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 las credenciales a un endpoint que usted crea en ServiceNow. 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.
¿Ya usa la guía del Tickets Feed?
Esta guía sigue la misma estructura, con sus propios nombres de script (AxurCredentialFeedMapper, axur.credentials_feed.url). Ambas integraciones pueden funcionar en paralelo en la misma instancia y pueden compartir la misma propiedad de API Key.
Requisitos previos
Una instancia de ServiceNow y un usuario admin (o
web_service_adminpara Push). Para probar primero, use una Personal Developer Instance (PDI) gratuita de developer.servicenow.com. Su URL tiene el formatohttps://dev123456.service-now.com.Un usuario con perfil manager en la Plataforma Axur para crear el feed.
Una API Key de la Plataforma Axur (solo Pull). Consulte el paso Obtener la API Key.
UI clásica vs. Next Experience
Los menús de ServiceNow se ven diferentes en la interfaz clásica (UI16) y en Next Experience (menú All). Algunos atajos, como escribir sys_properties.list en el filtro, no funcionan en todas las versiones. Cada paso a continuación también incluye una URL directa que funciona en ambas interfaces. Reemplace <instance> por el nombre de su instancia, por ejemplo dev123456.
URLs directas usadas en esta guía
Qué | URL directa |
Nueva propiedad del sistema |
|
Lista de propiedades del sistema |
|
Nuevo Script Include |
|
Nueva Scheduled Script Execution |
|
Nueva Scripted REST API |
|
Incidentes creados por el feed |
|
Logs del sistema |
|
Obtener el feed y la API Key en la Plataforma Axur
Haga este paso primero. Pull necesita la URL del feed y la API Key antes de crear cualquier cosa en ServiceNow.
Crear el feed
Vaya a one.axur.com/api-integrations → sección Feeds → Add feed. Puede elegir la plantilla Employee credentials o User credentials, o hacer clic en Skip templates.
Elija el tipo Credentials.
Elija el modo de entrega: Pull o Push. Para Push, ingrese la URL del endpoint que creará en el paso 6.
El campo Event date viene precargado con la fecha de creación (
created). Cada credencial llega una sola vez, cuando la Plataforma Axur la detecta por primera vez.En Feed parameters, elija qué credenciales recibir. Combine filtros con
&:Recomendado: agregue también el parámetro
fieldsque se muestra abajo. Así el feed devuelve solo lo que usa el script, y las contraseñas nunca salen de la Plataforma Axur:fields=id,created,detectionDate,customer,assets,status,credential.types,user,user.type,access.url,source.name
Ejemplo combinado con un filtro:
credential.types=employee&fields=id,created,…Defina un título, por ejemplo “ServiceNow – Credenciales expuestas”, y guarde.
Copie la URL del feed que aparece para el feed en la lista. Tiene el formato
https://api.axur.com/gateway/1.0/api/integration-feed/feeds/feed/<ID>.Figura 2: Configuración sugerida del feed (ilustración; la pantalla real puede verse diferente).
Obtener la API Key (solo Pull)
En la Plataforma Axur, abra My Preferences → pestaña API KEY.
Cree una nueva clave y cópiela de inmediato. Guárdela en un gestor de contraseñas hasta crear la propiedad en ServiceNow en el paso Guardar la URL y la API Key.
La clave pertenece al usuario que la creó
La clave solo ve lo que ese usuario puede ver en la Plataforma Axur. Si el usuario se desactiva, se bloquea o se elimina, la clave se revoca y el job empieza a fallar con 401 Unauthorized. Cree la clave con un usuario que tenga acceso a las credenciales y que no vaya a ser desactivado, como un usuario de integración dedicado. Nunca comparta la clave ni la escriba en scripts.
Mapeo de campos
Cada elemento de collectionData.detections[] se convierte en un registro de la tabla Incident. Los colores indican de dónde proviene cada dato:
Tabla de mapeo
Campo de ServiceNow | Origen en el JSON | Notas |
|
| Se define solo al crear. Las actualizaciones no reabren el incidente. |
|
| Se usa para evitar duplicados. |
|
|
|
| Data Leakage - Tipo - | Limitado a 160 caracteres: solo se acorta la parte de usuario/URL (con |
| Plantilla de la Figura 3b | Enlace: |
Etiquetas de tipo de credencial
| Etiqueta en el Incidente |
| Employee credential exposed |
| User credential exposed |
ambos | Employee and User credential exposed |
La contraseña nunca se escribe en ServiceNow
El script no copia la contraseña al Incidente, aunque el feed la envíe. Los incidentes son visibles para muchas personas y se conservan por mucho tiempo, por lo que guardar allí contraseñas expuestas generaría una nueva filtración. Su equipo puede ver la detección completa en la Plataforma Axur mediante el enlace de la descripción.
Cuidado con las claves con punto
Campos como access.url y credential.types tienen un punto en el nombre. En JavaScript, use corchetes: d['access.url'], no d.access.url.
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.
Abra
https://<instance>.service-now.com/sys_script_include.do?sys_id=-1. Desde el menú, la ruta es System Definition › Script Includes → New.Name:
AxurCredentialFeedMapper(debe ser exactamente este nombre).Pegue el código de abajo en el campo Script y guarde.
var AxurCredentialFeedMapper = {
TABLE: 'incident',
CREDENTIALS_URL: 'https://one.axur.com/data-leakage/credentials',
SHORT_DESCRIPTION_LIMIT: 160,
WORKSPACE: 'Data Leakage',
TYPE_LABELS: {
'employee': 'Employee',
'user': 'User'
},
buildFields: function (item) {
var id = item.id;
var customer = item.customer || '';
var user = item.user || '';
var accessUrl = item['access.url'] || '';
var typeLabel = this.typeLabel(item['credential.types'] || []);
var prefix = this.WORKSPACE + ' - ' + typeLabel + ' credential exposed - ' + customer + ' - ';
var target = accessUrl ? user + ' @ ' + accessUrl : user;
var shortDescription = prefix + this.fit(target, prefix.length);
var link = this.CREDENTIALS_URL + '?customerId=' + encodeURIComponent(customer)
+ '&text=' + encodeURIComponent(id);
var description = [
'Axur - one.axur.com',
'',
'New credential exposure detected (' + link + ')',
'',
'Detection ID: ' + id,
this.assetsLine(item.assets || []),
'Credential Type: ' + typeLabel,
'User: ' + user + (item['user.type'] ? ' (' + item['user.type'] + ')' : ''),
'Access URL: ' + accessUrl,
'Source: ' + (item['source.name'] || ''),
'Status: ' + (item.status || ''),
'Detection Date: ' + this.formatDate(item.detectionDate || item.created)
].join('\n');
return { id: id, shortDescription: shortDescription, description: description };
},
typeLabel: function (types) {
var labels = [];
for (var i = 0; i < types.length; i++) {
labels.push(this.TYPE_LABELS[types[i]] || types[i]);
}
return labels.length ? labels.join(' and ') : 'Unknown';
},
fit: function (text, usedLength) {
var available = this.SHORT_DESCRIPTION_LIMIT - usedLength;
if (text.length <= available) return text;
return text.substring(0, Math.max(available - 3, 0)) + '...';
},
assetsLine: function (assets) {
if (assets.length === 0) return 'Asset: -';
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.id) return;
var gr = new GlideRecord(this.TABLE);
gr.addQuery('correlation_id', f.id);
gr.query();
var exists = gr.next();
if (!exists) {
gr.initialize();
gr.state = 1;
}
gr.correlation_id = f.id;
gr.correlation_display = f.id;
gr.short_description = f.shortDescription;
gr.description = f.description;
if (exists) { gr.update(); } else { gr.insert(); }
},
processPayload: function (payload) {
var detections = (payload && payload.collectionData && payload.collectionData.detections) || [];
for (var i = 0; i < detections.length; i++) {
this.upsert(detections[i]);
}
return detections.length;
}
};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
Antes de empezar: tenga a mano la URL del feed y la API Key.
Abra directamente el formulario de nueva propiedad:
https://<instance>.service-now.com/sys_properties.do?sys_id=-1. También puede abrirsys_properties_list.doy hacer clic en New.Cree la propiedad de la URL del feed:
Si
axur.feed.api_keytodavía no existe (se comparte con la integración del Tickets Feed), abra el formulario de nuevo y créela:
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 propiedad del sistema.
Crear la programación
Abra
https://<instance>.service-now.com/sysauto_script.do?sys_id=-1. Desde el menú, la ruta es System Definition › Scheduled Jobs → New → Automatically run a script of your choosing.Name:
Axur Credentials Feed → Incident. Run: Periodically. Repeat interval:00:05:00(5 min).Pegue el script de abajo y guarde.
Figura 4: Scheduled Job que se ejecuta cada 5 minutos (ilustración).
var FEED_URL = gs.getProperty('axur.credentials_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 credentials feed: HTTP ' + response.getStatusCode() + ' - ' + response.getBody());
break;
}
var processed = AxurCredentialFeedMapper.processPayload(JSON.parse(response.getBody()));
if (processed === 0 || FEED_URL.indexOf('dry-run=true') > -1) break;
}
Cada llamada al feed avanza el puntero y devuelve el siguiente lote. El bucle continúa hasta que un lote llega vacío, con un límite de 20 llamadas por ejecución para que el job nunca se quede colgado. En modo dry-run el puntero no avanza, así que el job hace una sola llamada por ejecución.
Opción B: Push con una Scripted REST API
Elija esta opción para recibir credenciales casi en tiempo real. Su instancia debe aceptar llamadas entrantes de la Plataforma Axur.
Abra
https://<instance>.service-now.com/sys_ws_definition.do?sys_id=-1. Desde el menú, la ruta es System Web Services › Scripted Web Services › Scripted REST APIs → New.Name:
Axur Credentials Feed, API ID:axur_credentials_feed. Guarde.En la pestaña Resources → New: Name
credentials, HTTP methodPOST, Relative path/credentials.Pegue el script de abajo en el resource y guarde.
Copie el Resource path (por ejemplo
https://<instance>.service-now.com/api/<scope>/axur_credentials_feed/credentials) e ingréselo como endpoint del feed Push en la Plataforma Axur.
(function process(request, response) {
var processed = AxurCredentialFeedMapper.processPayload(request.body.data);
response.setStatus(200);
response.setBody({ processed: processed });
})(request, response);
Autenticación del endpoint
De forma predeterminada, el resource exige autenticación de ServiceNow (Requires authentication). No la desactive. En su lugar, haga que la Plataforma Axur se autentique en cada llamada:
En ServiceNow, cree un usuario de integración dedicado (por ejemplo
axur.integration) solo con los roles necesarios para crear y actualizar incidentes.Al configurar el feed Push en la Plataforma Axur, agregue un header personalizado con las credenciales de ese usuario:
Authorization: Basic <base64 de usuario:contraseña>. La Plataforma Axur envía sus headers personalizados en cada solicitud.
Opcional: verificar la firma
Cada solicitud Push también incluye un header X-Push-Signature: un HMAC-SHA256 del cuerpo sin procesar de la solicitud, codificado en hexadecimal y calculado con la clave secreta del feed Push. Valídelo en el resource si su equipo de seguridad exige comprobar que la llamada proviene de la Plataforma Axur.
Prueba de conexión
Cuando guarda o prueba el feed Push, la Plataforma Axur envía un cuerpo vacío ({}). El script responde 200 con processed: 0 y no crea nada.
Probar y validar
Active el dry-run temporalmente: abra la propiedad
axur.credentials_feed.url(sys_properties_list.do, busque por nombre) y agregue?dry-run=trueal final de su Value, por ejemplohttps://api.axur.com/gateway/1.0/api/integration-feed/feeds/feed/<ID>?dry-run=true. Guarde. Ahora el feed devuelve las mismas credenciales en cada llamada y su puntero no avanza, así que no se pierde nada mientras prueba.Ejecute el job manualmente: abra el Scheduled Job → Execute Now.
Revise los incidentes en
incident_list.do?sysparm_query=correlation_idISNOTEMPTY. Confirme que ninguna contraseña aparece en el Incidente.Ejecútelo de nuevo. Gracias al upsert, la cantidad de incidentes no debería aumentar.
Busque errores en
syslog_list.doo en System Logs › Errors (mensajes que empiezan conAxur credentials feed:).¿Todo bien? Edite de nuevo
axur.credentials_feed.urly quite?dry-run=truede su valor, para que el puntero empiece a avanzar.
Consejo
Valide en una instancia de preproducción o de desarrollo antes de activarlo en producción. Un feed sin filtros puede traer muchas credenciales en la primera ejecución; empiece con un filtro (por ejemplo credential.types=employee) si espera un volumen grande.
Notas de seguridad y checklist
Tema | Recomendación |
Contraseñas | Nunca se guardan en ServiceNow. Use el parámetro |
Quién ve los incidentes | Las credenciales expuestas son datos personales. Asigne los incidentes a un grupo restringido (por ejemplo, con una regla de Assignment group) en lugar de la cola general. |
API Key | Guardada como |
Checklist de puesta en producción
Credentials Feed creado en la Plataforma Axur con los filtros correctos y el parámetro
fieldsScript Include
AxurCredentialFeedMappercreadoPull: propiedades
axur.credentials_feed.urlyaxur.feed.api_keycreadasPull: Scheduled Job activo · Push: endpoint registrado en el feed
Probado con
?dry-run=trueenaxur.credentials_feed.url, sin duplicados y sin contraseñas en el Incidente?dry-run=trueeliminado deaxur.credentials_feed.url







