收集 Fastly WAF 日志
支持的平台:
Google SecOps
SIEM
概览
此解析器会从 Fastly WAF JSON 日志中提取字段,对其进行转换和重命名,并将其映射到 UDM。它会处理各种数据类型、转换严重程度级别,并根据可用的 IP 和主机名信息对事件进行分类。它还会处理潜在的解析失败情况,并丢弃格式有误的日志条目。
准备工作
- 确保您拥有 Google SecOps 实例。
- 具有配置 WAF 设置权限的 Fastly 账号。
在 Google SecOps 中配置 Feed 以注入 Fastly WAF 日志
- 依次前往 SIEM 设置 > Feed。
- 点击新增。
- 在 Feed 名称字段中,输入 Feed 的名称(例如 Fastly WAF 日志)。
- 选择Webhook 作为来源类型。
- 选择 Fastly WAF 作为日志类型。
- 点击下一步。
- 可选:为以下输入参数指定值:
- 分隔符:用于分隔日志行(例如
\n
)的分隔符。 - 资源命名空间:资源命名空间。
- 提取标签:应用于此 Feed 中的事件的标签。
- 分隔符:用于分隔日志行(例如
- 点击下一步。
- 在最终确定界面中查看 Feed 配置,然后点击提交。
- 点击生成 Secret 密钥,生成用于对此 Feed 进行身份验证的 Secret 密钥。
- 复制并存储密钥。您将无法再查看此密钥。如有必要,您可以重新生成新的 Secret 密钥,但此操作会使之前的 Secret 密钥过时。
- 在详情标签页中,从端点信息字段复制 Feed 端点网址。您需要在客户端应用中指定此端点网址。
- 点击完成。
为该网站钩子 Feed 创建 API 密钥
依次前往 Google Cloud 控制台 > 凭据。
点击创建凭据,然后选择 API 密钥。
限制 API 密钥对 Google Security Operations API 的访问权限。
指定端点网址
- 在客户端应用中,指定 webhook Feed 中提供的 HTTPS 端点网址。
通过在自定义标头中指定 API 密钥和密钥(格式如下)来启用身份验证:
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
建议:将 API 密钥作为标头指定,而不是在网址中指定。
如果您的 webhook 客户端不支持自定义标头,您可以使用以下格式的查询参数指定 API 密钥和密钥:
ENDPOINT_URL?key=API_KEY&secret=SECRET
替换以下内容:
ENDPOINT_URL
:Feed 端点网址。API_KEY
:用于对 Google Security Operations 进行身份验证的 API 密钥。SECRET
:您为对 Feed 进行身份验证而生成的密钥。
在 Fastly 中配置 Webhook
- 登录 Fastly。
- 可选:在网站菜单中选择一个网站(如果您有多个网站)。
- 依次选择管理 > 网站集成。
- 点击添加网站集成。
- 选择通用 Webhook。
- Webhook 网址:依次输入 Google SecOps 的 ENDPOINT_网址、API_KEY 和 SECRET。
- 提醒展示位置:选择所有活动或特定活动。
- 可选:如果您选择了特定活动,请前往“活动”菜单,然后选择要让该 Webhook 发送的活动类型。
- 点击创建网站集成。
UDM 映射表
日志字段 | UDM 映射 | 逻辑 |
---|---|---|
anomaly_score |
security_result.detection_fields[].key :“anomaly”security_result.detection_fields[].value :anomaly_score |
如果 waf.score.anomaly 为 0 或空,且 anomaly_score 不为空或不为 0,则 anomaly_score 值用于填充 security_result.detection_fields 数组,其中键为“anomaly”,值为 anomaly_score 字段的值。 |
cache_status |
additional.fields[].key :“cache_status”additional.fields[].value.string_value :cache_status |
cache_status 值用于向 additional.fields 数组填充键“cache_status”和 cache_status 字段的值。 |
client_ip |
principal.ip :client_ip |
client_ip 字段映射到 principal.ip 。 |
connection.fastly_is_edge |
additional.fields[].key :“fastly_is_edge”additional.fields[].value.bool_value :connection.fastly_is_edge |
connection.fastly_is_edge 值用于向 additional.fields 数组填充键为“fastly_is_edge”且值为 connection.fastly_is_edge 字段的值。 |
connection.fastly_is_shield |
additional.fields[].key :“fastly_is_shield”additional.fields[].value.bool_value :connection.fastly_is_shield |
connection.fastly_is_shield 值用于向 additional.fields 数组填充键为“fastly_is_shield”且值为 connection.fastly_is_shield 字段的值。 |
connection.request_tls_version |
network.tls.version :connection.request_tls_version |
connection.request_tls_version 字段已映射到 network.tls.version 。 |
fastly.server |
target.hostname :fastly.server |
fastly.server 字段映射到 target.hostname 。 |
fastly.service_id |
additional.fields[].key :“service_id”additional.fields[].value.string_value :fastly.service_id |
fastly.service_id 值用于使用键“service_id”和 fastly.service_id 字段的值填充 additional.fields 数组。 |
geo.city |
principal.location.city :geo.city |
geo.city 字段已映射到 principal.location.city 。 |
geo.country |
principal.location.country_or_region :geo.country |
geo.country 字段映射到 principal.location.country_or_region 。 |
geo.location |
principal.location.region_latitude :从 geo.location 中提取principal.location.region_longitude :从 geo.location 中提取 |
系统会使用正则表达式从 geo.location 字段中提取经纬度,并分别映射到 principal.location.region_latitude 和 principal.location.region_longitude 。 |
geo.region |
principal.location.state :geo.region |
geo.region 字段映射到 principal.location.state 。 |
host |
principal.hostname :host |
host 字段已映射到 principal.hostname 。 |
request_headers.accept_charset |
additional.fields[].key :"accept_charset"additional.fields[].value.string_value :request_headers.accept_charset |
request_headers.accept_charset 值用于向 additional.fields 数组填充键“accept_charset”和 request_headers.accept_charset 字段的值。 |
request_headers.accept_language |
additional.fields[].key :“accept_language”additional.fields[].value.string_value :request_headers.accept_language |
request_headers.accept_language 值用于向 additional.fields 数组填充键为“accept_language”且值为 request_headers.accept_language 字段的值。 |
request_headers.referer |
network.http.referral_url :request_headers.referer |
request_headers.referer 字段已映射到 network.http.referral_url 。 |
request_headers.user_agent |
network.http.user_agent :request_headers.user_agent |
request_headers.user_agent 字段映射到 network.http.user_agent 。 |
request_id |
metadata.product_log_id :request_id |
request_id 字段映射到 metadata.product_log_id 。 |
request_method |
network.http.method :request_method |
request_method 字段映射到 network.http.method 。 |
response_headers.cache_control |
additional.fields[].key :“cache_control”additional.fields[].value.string_value :response_headers.cache_control |
response_headers.cache_control 值用于向 additional.fields 数组填充键为“cache_control”且值为 response_headers.cache_control 字段的值。 |
response_headers.content_type |
additional.fields[].key :“content_type”additional.fields[].value.string_value :response_headers.content_type |
response_headers.content_type 值用于向 additional.fields 数组填充键为“content_type”且值为 response_headers.content_type 字段的值。 |
response_state |
additional.fields[].key :“response_state”additional.fields[].value.string_value :response_state |
response_state 值用于向 additional.fields 数组填充键为“response_state”且值为 response_state 字段的值。 |
response_status |
network.http.response_code :response_status |
如果 status 字段为空,则 response_status 字段会映射到 network.http.response_code 。 |
rule_id |
security_result.rule_id :rule_id |
如果 waf.rule_id 为空,则使用 rule_id 值填充 security_result.rule_id 。 |
severity |
waf.severity :severity |
severity 字段值会复制到 waf.severity 。 |
size_bytes.request_header |
network.sent_bytes :size_bytes.request_header |
size_bytes.request_header 字段映射到 network.sent_bytes 。 |
size_bytes.response_header |
network.received_bytes :size_bytes.response_header |
size_bytes.response_header 字段映射到 network.received_bytes 。 |
status |
network.http.response_code :status |
status 字段映射到 network.http.response_code 。 |
timestamp |
metadata.event_timestamp :timestamp |
系统会解析 timestamp 字段并将其映射到 metadata.event_timestamp 。 |
url |
target.url :url |
url 字段映射到 target.url 。 |
waf.blocked |
security_result.action :派生 |
如果 waf.blocked 为 false,则 security_result.action 会设置为“允许”。如果 waf.blocked 为 true,则 security_result.action 会设置为“BLOCK”。 |
waf.executed |
security_result.detection_fields[].key :“已执行”security_result.detection_fields[].value :waf.executed |
waf.executed 值用于向 security_result.detection_fields 数组填充键为“executed”且值为 waf.executed 字段的值。 |
waf.failures |
security_result.detection_fields[].key :“failures”security_result.detection_fields[].value :waf.failures |
waf.failures 值用于向 security_result.detection_fields 数组填充键为“failures”且值为 waf.failures 字段的值。 |
waf.logged |
security_result.detection_fields[].key :“已记录”security_result.detection_fields[].value :waf.logged |
waf.logged 值用于向 security_result.detection_fields 数组填充键为“logged”且值为 waf.logged 字段的值。 |
waf.message |
metadata.description :waf.message |
如果 waf.message 不为空,则会映射到 metadata.description 。 |
waf.rule_id |
security_result.rule_id :waf.rule_id |
如果 waf.rule_id 不为空,则会映射到 security_result.rule_id 。 |
waf.score.anomaly |
security_result.detection_fields[].key :“anomaly”security_result.detection_fields[].value :waf.score.anomaly |
如果 waf.score.anomaly 不为 0 且不为空,则该值会用于使用键“anomaly”和 waf.score.anomaly 字段的值填充 security_result.detection_fields 数组。 |
waf.score.http_violation |
security_result.detection_fields[].key :“http_violation”security_result.detection_fields[].value :waf.score.http_violation |
如果 waf.score.http_violation 不为 0 且不为空,则该值会用于填充 security_result.detection_fields 数组。 |
waf.score.lfi |
security_result.detection_fields[].key :“lfi”security_result.detection_fields[].value :waf.score.lfi |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.php_injection |
security_result.detection_fields[].key :“php_injection”security_result.detection_fields[].value :waf.score.php_injection |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.rce |
security_result.detection_fields[].key :“rce”security_result.detection_fields[].value :waf.score.rce |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.rfi |
security_result.detection_fields[].key :“rfi”security_result.detection_fields[].value :waf.score.rfi |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.session_fixation |
security_result.detection_fields[].key :“session_fixation”security_result.detection_fields[].value :waf.score.session_fixation |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.sql_injection |
security_result.detection_fields[].key : "sql_injection"security_result.detection_fields[].value : waf.score.sql_injection |
与 waf.score.http_violation 类似的逻辑。 |
waf.score.xss |
security_result.detection_fields[].key :“xss”security_result.detection_fields[].value :waf.score.xss |
与 waf.score.http_violation 类似的逻辑。 |
waf.severity |
security_result.severity :派生security_result.severity_details :waf.severity |
如果 waf.severity 不为空,则会根据范围(<=3:严重、>3 且 <=6:中等、>6 且 <=8:轻微,否则:UNKNOWN_SEVERITY)确定 security_result.severity 的值。原始 waf.severity 值也会映射到 security_result.severity_details 。 |
waf_message |
metadata.description :waf_message |
如果 waf.message 为空且 waf_message 不为空,则会映射到 metadata.description 。如果 client_ip 或 host 和 fastly.server 不为空,则 metadata.event_type 会设置为“NETWORK_HTTP”。否则,如果 client_ip 或 host 不为空,则 metadata.event_type 会设置为“STATUS_UPDATE”。否则,将其设置为“GENERIC_EVENT”。硬编码的值。硬编码的值。硬编码的值。 |
变化
2022-06-06
- 新创建的解析器。