Skip to content

Commit 4a3964b

Browse files
authored
[proofpoint_tap] Set timestamp to max of {click,message}Time and threatTime (#9982)
Prevent new events from appearing in the past by using the time the event was triggered as the `@timestamp`. An event can be triggered when a click occurs, a message is delivered/blocked, or new threat is discovered. When a new threat is discovered the previous behavior made the event appear to have happened in the past because we used the clickTime or messageTime as the timestamp which might have occurred weeks ago. The API docs state, "the time an event is created is always after either of these two times: - the time that the message was sent or the time click occurred (messageTime or clickTime) - the time that the threat referenced by the message or click was recognized and condemned by Proofpoint (threatsInfoMap/threatTime)" I suspect this does not occur for `clicks_blocked` because click was already condemned, but in case they send an update if a new threat matches the previous click I'll include the same change there. Fixes #9967
1 parent a27f0db commit 4a3964b

File tree

13 files changed

+99
-15
lines changed

13 files changed

+99
-15
lines changed

packages/proofpoint_tap/changelog.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# newer versions go on top
2+
- version: "1.19.0"
3+
changes:
4+
- description: Set @timestamp based on the event trigger which is either the messageTime/clickTime or the threatTime.
5+
type: enhancement
6+
link: https://github.com/elastic/integrations/pull/9982
27
- version: "1.18.1"
38
changes:
49
- description: Prevent dropped events due to an insufficiently unique deduplication key. The document `_id` computation now uses a hash over the `event.original` value.

packages/proofpoint_tap/data_stream/clicks_blocked/_dev/test/pipeline/test-clicks-blocked.log-expected.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"clicks_blocked": {
5858
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
5959
"classification": "phish",
60+
"click_time": "2022-03-21T07:52:11.000Z",
6061
"threat": {
6162
"id": "3xx97xx852c66a7xx761450xxxxxx9f4ffaxxxxxxxxxxxxxxx7a76481xx",
6263
"status": "active",
@@ -156,6 +157,7 @@
156157
"clicks_blocked": {
157158
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
158159
"classification": "phish",
160+
"click_time": "2022-03-30T07:22:52.000Z",
159161
"threat": {
160162
"id": "fdxxxxxxxxxxxcc34aff1aefxbx3xx7xb7xfxcxx1xxxxxxxx98780b5xxxexbx5xc32c",
161163
"status": "active",
@@ -254,6 +256,7 @@
254256
"clicks_blocked": {
255257
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
256258
"classification": "spam",
259+
"click_time": "2022-03-30T07:10:19.000Z",
257260
"threat": {
258261
"id": "eaxxxxxxxxxxxx6376xxxxxxxxxxx1cba65xxx9x7xxxxxxxxxxfbbxx4x0",
259262
"status": "active",
@@ -353,6 +356,7 @@
353356
"clicks_blocked": {
354357
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
355358
"classification": "malware",
359+
"click_time": "2022-03-30T10:11:12.000Z",
356360
"threat": {
357361
"id": "502bxxxxxxxxxxx70513b6cxxxxxxxxxxxxebc7fc699xxxxxxxxxxxxxxxxd5f",
358362
"status": "active",
@@ -452,6 +456,7 @@
452456
"clicks_blocked": {
453457
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
454458
"classification": "spam",
459+
"click_time": "2022-03-30T10:01:01.000Z",
455460
"threat": {
456461
"id": "47580xdx0x2x5x2xfx8x3x3x7x7xxxxcx6x7x4x4x1xexcx5cx9x3xfxfxxx1",
457462
"status": "active",

packages/proofpoint_tap/data_stream/clicks_blocked/elasticsearch/ingest_pipeline/default.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,19 @@ processors:
5555
if: ctx.email?.to?.address instanceof String
5656
- date:
5757
field: json.clickTime
58+
target_field: proofpoint_tap.clicks_blocked.click_time
5859
if: ctx.json?.clickTime != null && ctx.json.clickTime != ''
5960
formats:
6061
- ISO8601
6162
on_failure:
6263
- append:
6364
field: error.message
6465
value: '{{{_ingest.on_failure_message}}}'
66+
- set:
67+
field: '@timestamp'
68+
copy_from: proofpoint_tap.clicks_blocked.click_time
69+
ignore_failure: true
70+
ignore_empty_value: true
6571
- rename:
6672
field: json.id
6773
target_field: event.id
@@ -126,6 +132,18 @@ processors:
126132
- append:
127133
field: error.message
128134
value: '{{{_ingest.on_failure_message}}}'
135+
- script:
136+
lang: painless
137+
description: Set the @timestamp to the maximum of clickTime and threatTime.
138+
tag: timestamp-is-maximum
139+
if: ctx.proofpoint_tap?.clicks_blocked?.threat?.time instanceof String
140+
ignore_failure: true
141+
source: |
142+
def ts = Instant.parse(ctx['@timestamp']);
143+
def threatTime = Instant.parse(ctx.proofpoint_tap.clicks_blocked.threat.time);
144+
if (threatTime.isAfter(ts)) {
145+
ctx['@timestamp'] = ctx.proofpoint_tap.clicks_blocked.threat.time;
146+
}
129147
- uri_parts:
130148
field: json.url
131149
keep_original: false

packages/proofpoint_tap/data_stream/clicks_blocked/fields/fields.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
- name: campaign_id
88
type: keyword
99
description: An identifier for the campaign of which the threat is a member, if available at the time of the query. Threats can be linked to campaigns even after these events are retrieved.
10+
- name: click_time
11+
type: date
12+
description: The time the user clicked on the URL.
1013
- name: classification
1114
type: keyword
1215
description: The threat category of the malicious URL.

packages/proofpoint_tap/data_stream/clicks_permitted/_dev/test/pipeline/test-clicks-permitted.log-expected.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"expected": [
33
{
4-
"@timestamp": "2016-06-24T19:17:44.000Z",
4+
"@timestamp": "2016-06-24T19:17:46.000Z",
55
"destination": {
66
"as": {
77
"number": 29518,
@@ -57,6 +57,7 @@
5757
"clicks_permitted": {
5858
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
5959
"classification": "MALWARE",
60+
"click_time": "2016-06-24T19:17:44.000Z",
6061
"threat": {
6162
"id": "61f7622xx1x6x7x1x4xxxxxxxxxxx4xdbaxxxxxxxxxxx5xex3xbxxxxxdxfx5xxxxx0",
6263
"status": "active",
@@ -99,7 +100,7 @@
99100
}
100101
},
101102
{
102-
"@timestamp": "2022-03-21T20:39:37.000Z",
103+
"@timestamp": "2022-03-30T10:05:57.000Z",
103104
"destination": {
104105
"as": {
105106
"number": 29518,
@@ -155,6 +156,7 @@
155156
"clicks_permitted": {
156157
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
157158
"classification": "phish",
159+
"click_time": "2022-03-21T20:39:37.000Z",
158160
"threat": {
159161
"id": "92c17aaxxxxxxxxxx07xx7xxxx9xexcx3x3xxxxxx8xx3xxxx",
160162
"status": "active",
@@ -254,6 +256,7 @@
254256
"clicks_permitted": {
255257
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
256258
"classification": "spam",
259+
"click_time": "2022-03-30T10:51:53.000Z",
257260
"threat": {
258261
"id": "xxxxxxbx1cxcxx0xcx5xxxxdx5xex8xbx7xxxeexxxxxxxx9",
259262
"status": "cleared",
@@ -352,6 +355,7 @@
352355
"clicks_permitted": {
353356
"campaign_id": "46x01x8x-x899-404x-xxx9-111xx393d1x7",
354357
"classification": "phish",
358+
"click_time": "2022-03-30T00:56:14.000Z",
355359
"threat": {
356360
"id": "xxxdxxdx6x7x6xxxxx5xxx837ex4x4xcx8xcxxxexxx2xxxxxx5",
357361
"status": "active",

packages/proofpoint_tap/data_stream/clicks_permitted/elasticsearch/ingest_pipeline/default.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,19 @@ processors:
5555
if: ctx.email?.to?.address instanceof String
5656
- date:
5757
field: json.clickTime
58+
target_field: proofpoint_tap.clicks_permitted.click_time
5859
if: ctx.json?.clickTime != null && ctx.json.clickTime != ''
5960
formats:
6061
- ISO8601
6162
on_failure:
6263
- append:
6364
field: error.message
6465
value: '{{{_ingest.on_failure_message}}}'
66+
- set:
67+
field: '@timestamp'
68+
copy_from: proofpoint_tap.clicks_permitted.click_time
69+
ignore_failure: true
70+
ignore_empty_value: true
6571
- rename:
6672
field: json.id
6773
target_field: event.id
@@ -126,6 +132,18 @@ processors:
126132
- append:
127133
field: error.message
128134
value: '{{{_ingest.on_failure_message}}}'
135+
- script:
136+
lang: painless
137+
description: Set the @timestamp to the maximum of clickTime and threatTime.
138+
tag: timestamp-is-maximum
139+
if: ctx.proofpoint_tap?.clicks_permitted?.threat?.time instanceof String
140+
ignore_failure: true
141+
source: |
142+
def ts = Instant.parse(ctx['@timestamp']);
143+
def threatTime = Instant.parse(ctx.proofpoint_tap.clicks_permitted.threat.time);
144+
if (threatTime.isAfter(ts)) {
145+
ctx['@timestamp'] = ctx.proofpoint_tap.clicks_permitted.threat.time;
146+
}
129147
- uri_parts:
130148
field: json.url
131149
keep_original: false

packages/proofpoint_tap/data_stream/clicks_permitted/fields/fields.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
- name: campaign_id
88
type: keyword
99
description: An identifier for the campaign of which the threat is a member, if available at the time of the query. Threats can be linked to campaigns even after these events are retrieved.
10+
- name: click_time
11+
type: date
12+
description: The time the user clicked on the URL.
1013
- name: classification
1114
type: keyword
1215
description: The threat category of the malicious URL.

packages/proofpoint_tap/data_stream/message_blocked/_dev/test/pipeline/test-message-blocked.log-expected.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"expected": [
33
{
4-
"@timestamp": "2022-01-01T00:45:55.050Z",
4+
"@timestamp": "2022-01-01T02:03:40.050Z",
55
"ecs": {
66
"version": "8.11.0"
77
},
@@ -126,7 +126,7 @@
126126
]
127127
},
128128
{
129-
"@timestamp": "2022-01-01T01:25:59.059Z",
129+
"@timestamp": "2022-01-01T10:10:02.020Z",
130130
"ecs": {
131131
"version": "8.11.0"
132132
},
@@ -250,7 +250,7 @@
250250
]
251251
},
252252
{
253-
"@timestamp": "2022-01-01T04:51:56.269Z",
253+
"@timestamp": "2022-01-01T11:06:50.580Z",
254254
"ecs": {
255255
"version": "8.11.0"
256256
},
@@ -381,7 +381,7 @@
381381
]
382382
},
383383
{
384-
"@timestamp": "2022-01-01T00:25:20.010Z",
384+
"@timestamp": "2022-01-01T05:02:48.832Z",
385385
"ecs": {
386386
"version": "8.11.0"
387387
},
@@ -581,7 +581,7 @@
581581
]
582582
},
583583
{
584-
"@timestamp": "2022-01-01T00:00:00.000Z",
584+
"@timestamp": "2022-01-01T03:02:25.092Z",
585585
"ecs": {
586586
"version": "8.11.0"
587587
},

packages/proofpoint_tap/data_stream/message_blocked/elasticsearch/ingest_pipeline/default.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,19 @@ processors:
488488
ignore_missing: true
489489
ignore_failure: true
490490
if: ctx.proofpoint_tap?.message_blocked?.threat_info_map instanceof List
491+
- script:
492+
lang: painless
493+
description: Set the @timestamp to the maximum of messageTime and threatTime.
494+
tag: timestamp-is-maximum
495+
if: ctx.proofpoint_tap?.message_blocked?.threat_info_map instanceof List
496+
ignore_failure: true
497+
source: |
498+
def ts = Instant.parse(ctx['@timestamp']);
499+
for (item in ctx.proofpoint_tap.message_blocked.threat_info_map) {
500+
if (item?.threat?.time instanceof String && Instant.parse(item.threat.time).isAfter(ts)) {
501+
ctx['@timestamp'] = item.threat.time;
502+
}
503+
}
491504
- remove:
492505
field: event.original
493506
if: ctx.tags?.contains('preserve_original_event') != true

packages/proofpoint_tap/data_stream/message_delivered/_dev/test/pipeline/test-message-delivered.log-expected.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"expected": [
33
{
4-
"@timestamp": "2022-01-05T10:05:56.020Z",
4+
"@timestamp": "2022-03-29T18:48:33.000Z",
55
"ecs": {
66
"version": "8.11.0"
77
},
@@ -88,7 +88,7 @@
8888
]
8989
},
9090
{
91-
"@timestamp": "2022-01-01T00:00:00.000Z",
91+
"@timestamp": "2022-05-01T19:00:00.653Z",
9292
"ecs": {
9393
"version": "8.11.0"
9494
},
@@ -158,7 +158,7 @@
158158
]
159159
},
160160
{
161-
"@timestamp": "2022-01-01T00:00:00.000Z",
161+
"@timestamp": "2022-11-25T13:05:05.592Z",
162162
"ecs": {
163163
"version": "8.11.0"
164164
},
@@ -234,7 +234,7 @@
234234
]
235235
},
236236
{
237-
"@timestamp": "2022-01-01T00:00:00.000Z",
237+
"@timestamp": "2022-10-11T00:23:02.519Z",
238238
"ecs": {
239239
"version": "8.11.0"
240240
},
@@ -310,7 +310,7 @@
310310
]
311311
},
312312
{
313-
"@timestamp": "2022-03-15T15:00:20.000Z",
313+
"@timestamp": "2022-04-01T18:44:01.050Z",
314314
"ecs": {
315315
"version": "8.11.0"
316316
},
@@ -458,7 +458,7 @@
458458
]
459459
},
460460
{
461-
"@timestamp": "2021-09-28T16:28:59.490Z",
461+
"@timestamp": "2022-04-01T23:14:30.450Z",
462462
"ecs": {
463463
"version": "8.11.0"
464464
},
@@ -762,7 +762,7 @@
762762
]
763763
},
764764
{
765-
"@timestamp": "2022-03-24T13:24:57.000Z",
765+
"@timestamp": "2022-04-01T20:56:13.000Z",
766766
"ecs": {
767767
"version": "8.11.0"
768768
},

packages/proofpoint_tap/data_stream/message_delivered/elasticsearch/ingest_pipeline/default.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,19 @@ processors:
467467
ignore_missing: true
468468
ignore_failure: true
469469
if: ctx.proofpoint_tap?.message_delivered?.threat_info_map instanceof List
470+
- script:
471+
lang: painless
472+
description: Set the @timestamp to the maximum of messageTime and threatTime.
473+
tag: timestamp-is-maximum
474+
if: ctx.proofpoint_tap?.message_delivered?.threat_info_map instanceof List
475+
ignore_failure: true
476+
source: |
477+
def ts = Instant.parse(ctx['@timestamp']);
478+
for (item in ctx.proofpoint_tap.message_delivered.threat_info_map) {
479+
if (item?.threat?.time instanceof String && Instant.parse(item.threat.time).isAfter(ts)) {
480+
ctx['@timestamp'] = item.threat.time;
481+
}
482+
}
470483
- remove:
471484
field: event.original
472485
if: ctx.tags?.contains('preserve_original_event') != true

packages/proofpoint_tap/docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ An example event for `clicks_blocked` looks as following:
222222
| log.offset | Log offset | long |
223223
| proofpoint_tap.clicks_blocked.campaign_id | An identifier for the campaign of which the threat is a member, if available at the time of the query. Threats can be linked to campaigns even after these events are retrieved. | keyword |
224224
| proofpoint_tap.clicks_blocked.classification | The threat category of the malicious URL. | keyword |
225+
| proofpoint_tap.clicks_blocked.click_time | The time the user clicked on the URL. | date |
225226
| proofpoint_tap.clicks_blocked.sender_ip | The IP address of the sender. | ip |
226227
| proofpoint_tap.clicks_blocked.threat.id | The unique identifier associated with this threat. It can be used to query the forensics and campaign endpoints. | keyword |
227228
| proofpoint_tap.clicks_blocked.threat.status | The current state of the threat. | keyword |
@@ -459,6 +460,7 @@ An example event for `clicks_permitted` looks as following:
459460
| log.offset | Log offset | long |
460461
| proofpoint_tap.clicks_permitted.campaign_id | An identifier for the campaign of which the threat is a member, if available at the time of the query. Threats can be linked to campaigns even after these events are retrieved. | keyword |
461462
| proofpoint_tap.clicks_permitted.classification | The threat category of the malicious URL. | keyword |
463+
| proofpoint_tap.clicks_permitted.click_time | The time the user clicked on the URL. | date |
462464
| proofpoint_tap.clicks_permitted.sender_ip | The IP address of the sender. | ip |
463465
| proofpoint_tap.clicks_permitted.threat.id | The unique identifier associated with this threat. It can be used to query the forensics and campaign endpoints. | keyword |
464466
| proofpoint_tap.clicks_permitted.threat.status | The current state of the threat. | keyword |

packages/proofpoint_tap/manifest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
format_version: "3.0.3"
22
name: proofpoint_tap
33
title: Proofpoint TAP
4-
version: "1.18.1"
4+
version: "1.19.0"
55
description: Collect logs from Proofpoint TAP with Elastic Agent.
66
type: integration
77
categories:

0 commit comments

Comments
 (0)