收集 ServiceNow Security 日志

支持的平台:

本文档介绍了如何使用 Webhook Feed 将 ServiceNow 安全事件发送到 Google Security Operations。ServiceNow Security 解析器专为 ServiceNow 实例安全中心安全事件而设计,例如登录失败、SNC 登录、管理员登录、模拟和安全权限提升(请参阅 ServiceNow 实例安全中心安全事件)。ServiceNow 集成会将每个事件以 JSON 格式发布到 Google SecOps webhook 端点,解析器会在该端点将其标准化为统一数据模型 (UDM)。

解析器可识别五个事件值:Failed LoginAdmin LoginSNC LoginImpersonationSecurity Elevation。每个值都对应于 sysevent 队列中已注册的 ServiceNow 事件。此文档创建了一个 webhook Feed、一个向该 Feed 执行 POST 操作的脚本包含,以及四个在匹配的 sysevent 记录上触发并调用该脚本包含的脚本操作。

完成此一次性设置后,ServiceNow 会自动将每个新的安全事件转发给 Google SecOps。管理员无需采取进一步行动。

准备工作

确保您满足以下前提条件:

  • Google SecOps 实例。
  • 一个 ServiceNow 实例,其中包含一个具有 admin 角色的用户账号,或者具有以下权限:系统定义 > 脚本包含系统属性系统政策 > 事件 > 脚本操作注册
  • 现有的 ServiceNow 实例安全中心激活。ISC 已停止销售,无法在新实例上激活。
  • 对 Google Google Cloud 控制台的特权访问权限(用于创建 API 密钥)。

在 Google SecOps 中创建 Webhook Feed

以下部分介绍了如何在 Google SecOps 中创建 Webhook Feed。

创建 Feed

  1. 依次前往 SIEM 设置 > Feed
  2. 点击添加新 Feed
  3. 在下一页上,点击配置单个 Feed
  4. Feed 名称字段中,输入 Feed 的名称(例如 ServiceNow Security Events)。
  5. 选择 Webhook 作为来源类型
  6. 选择 ServiceNow Security 作为日志类型
  7. 点击下一步
  8. 为以下输入参数指定值:

    • 拆分定界符:当集成每次请求发送多个 JSON 事件时,请输入 \n。如果每个请求都包含单个事件,请留空。
    • 资源命名空间资源命名空间
    • 注入标签:应用于此 Feed 中事件的标签。
  9. 点击下一步

  10. 最终确定界面中查看新的 Feed 配置,然后点击提交

生成并保存密钥

  1. 在 Feed 详情页面上,点击生成密钥
  2. 复制并保存密钥,将其保存在安全的位置。

获取 Feed 端点网址

  1. 前往相应 Feed 的详细信息标签页。
  2. 端点信息部分,复制 Feed 端点网址。网址格式为:

    https://malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    

    或者,对于区域级端点:

    https://<REGION>-malachiteingestion-pa.googleapis.com/v2/unstructuredlogentries:batchCreate
    
  3. 保存此网址,以供后续步骤使用。

  4. 点击完成

创建 Google Cloud API 密钥

  1. 前往 Google Google Cloud 控制台“凭据”页面
  2. 选择与您的 Google SecOps 实例关联的项目。
  3. 依次点击创建凭据> API 密钥
  4. 点击修改 API 密钥以限制密钥。
  5. 名称字段中,输入一个描述性名称(例如 ServiceNow Webhook API Key)。
  6. API 限制下:

    1. 选择限制密钥
    2. 选择 API 列表中,选择 Google SecOps API
  7. 点击保存

  8. 复制 API 密钥并将其保存在安全的位置。

在 ServiceNow 中存储 Google SecOps 凭据

将端点网址和凭据存储为 ServiceNow 系统属性,以便集成代码不包含任何密钥。

  1. 在 ServiceNow 中,依次前往系统属性 > sys_properties.list
  2. 点击新建,然后提供以下配置详细信息:

    • 名称x_chronicle.endpoint_url
    • :粘贴 Feed 端点网址。
    • 类型string
  3. 点击提交

  4. 点击新建,然后提供以下配置详细信息:

    • 名称x_chronicle.api_key
    • :粘贴 Google Cloud API 密钥。
    • 类型password2
  5. 点击提交

  6. 点击新建,然后提供以下配置详细信息:

    • 名称x_chronicle.secret_key
    • :粘贴 Google SecOps Feed 密钥。
    • 类型password2
  7. 点击提交

创建网络钩子实用工具 Script Include

此脚本包含使用 ServiceNow sn_ws.RESTMessageV2 范围 API 将 JSON 载荷发布到 Google SecOps Webhook 端点。API 密钥和 Secret 密钥会作为 HTTP 标头发送。

  1. 前往系统定义 > 脚本包含
  2. 点击 New(新建)。
  3. 提供以下配置详细信息:

    • 名称ChronicleWebhookUtil
    • API 名称ChronicleWebhookUtil
    • 客户端可调用:未选中
    • 有效:已选中
  4. 脚本字段中,输入以下代码:

    var ChronicleWebhookUtil = Class.create();
    ChronicleWebhookUtil.prototype = {
        initialize: function() {
            this.endpointURL = gs.getProperty('x_chronicle.endpoint_url');
            this.apiKey = gs.getProperty('x_chronicle.api_key');
            this.secretKey = gs.getProperty('x_chronicle.secret_key');
        },
    
        // payload: a plain object whose keys match the required JSON contract.
        sendEvent: function(payload) {
            try {
                if (!this.endpointURL || !this.apiKey || !this.secretKey) {
                    gs.error('[Chronicle] Missing configuration. Check System Properties: x_chronicle.*');
                    return false;
                }
    
                var request = new sn_ws.RESTMessageV2();
                request.setEndpoint(this.endpointURL);
                request.setHttpMethod('POST');
                request.setRequestHeader('Content-Type', 'application/json');
                request.setRequestHeader('X-goog-api-key', this.apiKey);
                request.setRequestHeader('X-Webhook-Access-Key', this.secretKey);
                request.setRequestBody(JSON.stringify(payload));
    
                var response = request.execute();
                var statusCode = response.getStatusCode();
    
                if (statusCode == 200 || statusCode == 201 || statusCode == 204) {
                    gs.info('[Chronicle] Event sent: ' + payload.event + ' | Status: ' + statusCode);
                    return true;
                }
    
                gs.error('[Chronicle] Failed to send event: ' + payload.event + ' | Status: ' + statusCode + ' | Response: ' + response.getBody());
                return false;
            } catch (ex) {
                gs.error('[Chronicle] Exception sending event: ' + ex.message);
                return false;
            }
        },
    
        type: 'ChronicleWebhookUtil'
    };
    
  5. 点击提交

验证事件注册

只有当脚本操作的事件名称存在于事件注册表sysevent_register 表)中时,脚本操作才会触发。ServiceNow 开箱即用,可提供此集成使用的五种事件,但最好还是确认一下,因为如果缺少条目,系统不会生成任何错误,并且脚本操作永远不会运行。

  1. 在 ServiceNow 中,依次前往系统政策 > 事件 > 注册 (sysevent_register.list)。
  2. 事件名称列过滤以下各项,并确认存在相应记录:

    • login
    • login.failed
    • impersonation.start
    • security.elevated_role.enabled
  3. 如果缺少某个条目,请点击新建,将事件名称字段设置为缺失的值,将表格设置为 Global [global],然后点击提交

创建脚本操作

每个脚本操作都订阅一个 ServiceNow 事件名称。当 ServiceNow 将匹配的记录插入 sysevent 队列时,脚本操作会运行,读取事件参数,并调用 ChronicleWebhookUtil 来 POST 载荷。

解析器会映射到以下 ServiceNow 事件:

解析器 event ServiceNow 事件名称 触发器
Failed Login login.failed 登录尝试失败(任何身份验证方法)。
Admin Login login 具有 admin 角色的用户成功登录。
SNC Login login 具有 snc_external 角色的用户成功登录。
Impersonation impersonation.start 管理员开始模拟其他用户。
Security Elevation security.elevated_role.enabled 用户提升为 security_admin 或其他高权限角色。

loginlogin.failedparm1 设置为用户名,将 parm2 设置为来源 IP。其他事件遵循相同的 parm1/parm2 惯例,但具体内容取决于您的 ServiceNow 版本。打开每个事件的注册表条目,并确认参数说明与稍后介绍的脚本一致。如果您的注册表不同,请调整 parm1parm2 引用。

创建“登录失败”脚本操作

  1. 依次前往系统政策 > 事件 > 脚本操作
  2. 点击 New(新建)。
  3. 提供以下配置详细信息:

    • 名称Chronicle - Failed Login
    • 事件名称login.failed
    • 有效:已选中
  4. 脚本字段中,输入以下代码:

    (function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) {
        new ChronicleWebhookUtil().sendEvent({
            event: 'Failed Login',
            event_created: event.sys_created_on.getValue(),
            user: event.parm1.toString(),
            ip_address: event.parm2.toString()
        });
    })(current, event);
    
  5. 点击提交

创建登录脚本操作

此脚本操作会在每次成功登录时触发,并且仅在登录用户拥有 adminsnc_external 角色时转发记录。系统会相应地设置 event 字段。

  1. 依次前往系统政策 > 事件 > 脚本操作
  2. 点击 New(新建)。
  3. 提供以下配置详细信息:

    • 名称Chronicle - Login
    • 事件名称login
    • 有效:已选中
  4. 脚本字段中,输入以下代码:

    (function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) {
        var userName = event.parm1.toString();
        var ipAddress = event.parm2.toString();
    
        var user = new GlideRecord('sys_user');
        if (!user.get('user_name', userName)) {
            return;
        }
    
        function hasRole(roleName) {
            var role = new GlideRecord('sys_user_has_role');
            role.addQuery('user', user.sys_id);
            role.addQuery('role.name', roleName);
            role.query();
            return role.next();
        }
    
        var eventValue;
        if (hasRole('snc_external')) {
            eventValue = 'SNC Login';
        } else if (hasRole('admin')) {
            eventValue = 'Admin Login';
        } else {
            return;
        }
    
        new ChronicleWebhookUtil().sendEvent({
            event: eventValue,
            event_created: event.sys_created_on.getValue(),
            user: userName,
            ip_address: ipAddress
        });
    })(current, event);
    
  5. 点击提交

创建模拟脚本操作

  1. 依次前往系统政策 > 事件 > 脚本操作
  2. 点击 New(新建)。
  3. 提供以下配置详细信息:

    • 名称Chronicle - Impersonation
    • 事件名称impersonation.start
    • 有效:已选中
  4. 脚本字段中,输入以下代码:

    (function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) {
        new ChronicleWebhookUtil().sendEvent({
            event: 'Impersonation',
            event_created: event.sys_created_on.getValue(),
            user: event.parm1.toString(),       // impersonator
            snc_user: event.parm2.toString()    // impersonated user
        });
    })(current, event);
    
  5. 点击提交

创建安全提升脚本操作

  1. 依次前往系统政策 > 事件 > 脚本操作
  2. 点击 New(新建)。
  3. 提供以下配置详细信息:

    • 名称Chronicle - Security Elevation
    • 事件名称security.elevated_role.enabled
    • 有效:已选中
  4. 脚本字段中,输入以下代码:

    (function runAction(/*GlideRecord*/ current, /*GlideRecord*/ event) {
        new ChronicleWebhookUtil().sendEvent({
            event: 'Security Elevation',
            event_created: event.sys_created_on.getValue(),
            user: event.parm1.toString()
        });
    })(current, event);
    
  5. 点击提交

验证集成

您可以采用以下任一方法。

使用合成事件进行验证

如需立即测试每个脚本操作,而不等待实际的安全事件,请执行以下操作,从后台脚本中将事件排入队列:

  1. 在 ServiceNow 中,依次前往系统定义 > 脚本 - 后台
  2. 运行脚本字段中,输入以下某一行,然后点击运行脚本

    gs.eventQueue('login.failed', null, 'test.user', '203.0.113.45');
    gs.eventQueue('login', null, 'admin', '203.0.113.45');
    gs.eventQueue('impersonation.start', null, 'admin', 'test.user');
    gs.eventQueue('security.elevated_role.enabled', null, 'admin', 'security_admin');
    
  3. 等待最多一分钟,让 Event Manager 作业处理队列。

使用真实事件进行验证

在 ServiceNow 中生成以下任一已映射的安全性事件,以验证集成:

  • 登录失败:在无痕式浏览器窗口中打开 /login.do,然后提交无效密码。
  • 管理员登录:使用具有 admin 角色的用户从与您通常使用的 IP 地址不同的 IP 地址登录。
  • 模拟:从管理员账号模拟其他用户。
  • 安全权限提升:从具有 admin 角色的用户提升到 security_admin 角色。

确认转发

  1. 在 ServiceNow 中,依次前往系统政策 > 事件 > 事件日志 (sysevent.list),并确认是否显示了具有相应事件名称的记录。
  2. 在 ServiceNow 中,依次前往系统日志 > 系统日志 > 全部,然后确认是否显示状态为 200、201 或 204 的 [Chronicle] Event sent: ... 信息消息。[Chronicle] Failed to send event[Chronicle] Exception sending event 消息表示存在凭据或连接问题。
  3. 在 Google SecOps 中,针对 metadata.vendor_name = "SERVICENOW"metadata.product_name = "SERVICENOW_SECURITY" 运行 UDM 搜索。
  4. 确认该事件显示时,metadata.event_type 设置为 USER_LOGINUSER_CHANGE_PERMISSIONS,并且 principal.user.userid 已填充。

身份验证方法参考

Google SecOps webhook Feed 接受 API 密钥和密钥作为 HTTP 标头或网址查询参数。本指南使用标头方法,因为 sn_ws.RESTMessageV2 支持自定义标头,这样可避免凭据出现在网址和服务器访问日志中。

本指南中使用的标题:

  • X-goog-api-key:Google SecOps API 的 Google Cloud API 密钥。
  • X-Webhook-Access-Key:由 Google SecOps 生成的 Feed 密钥。

如果集成无法发送自定义标头,请改为将凭据附加到端点网址:

<ENDPOINT_URL>?key=<API_KEY>&secret=<SECRET_KEY>

Webhook 限制和最佳实践

限制
最大请求大小 4 MB
最大 QPS(每秒查询次数) 15000
请求超时 30 秒
重试行为 自动(使用指数退避算法)

为了控制数据量,请仅发送检测所需的安全事件,并在来源以突发方式生成事件时,使用 \n 分隔符按请求批量发送多个事件。

如需详细了解 Google SecOps Feed,请参阅 Google SecOps Feed 文档。如需了解每种 Feed 类型的要求,请参阅按类型划分的 Feed 配置

如果您在创建 Feed 时遇到问题,请与 Google SecOps 支持团队联系

UDM 映射表

日志字段 UDM 映射 逻辑
event extensions.auth.type 已映射:"Failed Login", "SNC Login", "Admin Login", "Impersonation"MACHINE
event_created metadata.event_timestamp 解析为 yyyy-MM-dd HH:mm:ss
event_type metadata.event_type 已重命名/已映射
event metadata.product_event_type event != `` 时进行映射
ip_address principal.ip 已合并
user principal.user.userid user != `` 时进行映射
created_by target.user.userid created_by != `` 时进行映射
snc_user target.user.userid snc_user != `` 时进行映射
timestamp event1.idm.read_only_udm.metadata.event_timestamp 从变更日志映射
data.sys_id event1.idm.read_only_udm.metadata.product_log_id 从变更日志映射
data.message_data event1.idm.read_only_udm.metadata.description 从变更日志映射
data.source event1.idm.read_only_udm.principal.resource.name 从变更日志映射
source event1.idm.read_only_udm.additional.fields 从变更日志映射
data.sys_created_on event1.idm.read_only_udm.metadata.collected_timestamp 从变更日志映射
data.sys_created_by event1.idm.read_only_udm.principal.user.userid 从变更日志映射
data.user event1.idm.read_only_udm.principal.user.userid 从变更日志映射
source_instance event1.idm.read_only_udm.principal.namespace 从变更日志映射
data.role event1.idm.read_only_udm.target.resource.attribute.roles 从变更日志映射
data.granted_by event1.idm.read_only_udm.target.user.userid 从变更日志映射
data.level event1.idm.read_only_udm.security_result.severity 从变更日志映射
data.state event1.idm.read_only_udm.security_result.action_details 从变更日志映射

更新日志

查看相应解析器的更改日志

需要更多帮助?获得社区成员和 Google SecOps 专业人士的解答。