logstash-filter-empowclassifier 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTORS +11 -0
- data/Gemfile +2 -0
- data/LICENSE +11 -0
- data/README.md +90 -0
- data/lib/logstash/filters/center-client.rb +208 -0
- data/lib/logstash/filters/classification-request.rb +17 -0
- data/lib/logstash/filters/classifier-cache.rb +51 -0
- data/lib/logstash/filters/classifier.rb +325 -0
- data/lib/logstash/filters/cognito-client.rb +48 -0
- data/lib/logstash/filters/elastic-db.rb +128 -0
- data/lib/logstash/filters/empowclassifier.rb +249 -0
- data/lib/logstash/filters/field-handler.rb +127 -0
- data/lib/logstash/filters/local-classifier.rb +94 -0
- data/lib/logstash/filters/plugin-logic.rb +163 -0
- data/lib/logstash/filters/response.rb +36 -0
- data/lib/logstash/filters/utils.rb +46 -0
- data/logstash-filter-empowclassifier.gemspec +38 -0
- data/spec/filters/bulk-processor_spec.rb +92 -0
- data/spec/filters/center-client_spec.rb +88 -0
- data/spec/filters/classifier-cache_spec.rb +44 -0
- data/spec/filters/classifier_spec.rb +78 -0
- data/spec/filters/cognito-client_spec.rb +20 -0
- data/spec/filters/elastic-db_spec.rb +44 -0
- data/spec/filters/empowclassifier_spec.rb +103 -0
- data/spec/filters/field-handler_spec.rb +101 -0
- data/spec/filters/local-classifier_spec.rb +46 -0
- data/spec/filters/plugin-logic_spec.rb +127 -0
- data/spec/filters/utils_spec.rb +74 -0
- data/spec/spec_helper.rb +2 -0
- metadata +260 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module LogStash
|
4
|
+
module Filters
|
5
|
+
module Empow
|
6
|
+
class CognitoClient
|
7
|
+
include LogStash::Util::Loggable
|
8
|
+
|
9
|
+
def initialize(username, password, aws_region_name, aws_client_id)
|
10
|
+
@logger = self.logger
|
11
|
+
|
12
|
+
@logger.debug("aws region: #{aws_region_name}")
|
13
|
+
@logger.debug("aws aws_client_id: #{aws_client_id}")
|
14
|
+
@logger.debug("cognito username: #{username}")
|
15
|
+
|
16
|
+
@username = username
|
17
|
+
@password = password
|
18
|
+
@aws_region_name = aws_region_name
|
19
|
+
@aws_client_id = aws_client_id
|
20
|
+
|
21
|
+
Aws.config.update({
|
22
|
+
region: @aws_region_name,
|
23
|
+
credentials: Aws::Credentials.new('aaaa', 'aaaa')
|
24
|
+
})
|
25
|
+
|
26
|
+
@client = Aws::CognitoIdentityProvider::Client.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def authenticate
|
30
|
+
resp = @client.initiate_auth({
|
31
|
+
auth_flow: "USER_PASSWORD_AUTH",
|
32
|
+
auth_parameters: {
|
33
|
+
'USERNAME': @username,
|
34
|
+
'PASSWORD': @password,
|
35
|
+
},
|
36
|
+
client_id: @aws_client_id,
|
37
|
+
})
|
38
|
+
|
39
|
+
id_token = resp.authentication_result.id_token
|
40
|
+
token_type = resp.authentication_result.token_type
|
41
|
+
|
42
|
+
token = token_type + " " + id_token
|
43
|
+
return id_token
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'elasticsearch'
|
2
|
+
require 'hashie'
|
3
|
+
|
4
|
+
module LogStash; module Filters; module Empow;
|
5
|
+
class PersistentKeyValueDB
|
6
|
+
#include LogStash::Util::Loggable
|
7
|
+
|
8
|
+
def initialize(hosts, username, password, index)
|
9
|
+
#@logger ||= self.logger
|
10
|
+
|
11
|
+
#@logger.debug("opening the local classification db")
|
12
|
+
|
13
|
+
@elastic ||= Elasticsearch::Client.new(:hosts => hosts)
|
14
|
+
@index = index
|
15
|
+
|
16
|
+
create_index index
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_index(index)
|
20
|
+
return if @elastic.indices.exists? index: index
|
21
|
+
|
22
|
+
@elastic.indices.create index: index, body: {
|
23
|
+
mappings: {
|
24
|
+
_doc: {
|
25
|
+
properties: {
|
26
|
+
product_type: {
|
27
|
+
type: 'keyword'
|
28
|
+
},
|
29
|
+
product: {
|
30
|
+
type: 'keyword'
|
31
|
+
},
|
32
|
+
term_key: {
|
33
|
+
type: 'keyword'
|
34
|
+
},
|
35
|
+
classification: {
|
36
|
+
enabled: false
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def query(product_type, product, term)
|
45
|
+
#@logger.debug("quering local classification db")
|
46
|
+
|
47
|
+
# fix nil product
|
48
|
+
if product.nil?
|
49
|
+
product = 'nil_safe_product_key'
|
50
|
+
end
|
51
|
+
|
52
|
+
response = @elastic.search index: @index, type: '_doc', body: {
|
53
|
+
query: {
|
54
|
+
bool: {
|
55
|
+
must: [
|
56
|
+
{ term: { product_type: product_type } },
|
57
|
+
{
|
58
|
+
bool: {
|
59
|
+
should: [
|
60
|
+
{
|
61
|
+
bool: {
|
62
|
+
must: [
|
63
|
+
{ term: { term_key: term } },
|
64
|
+
{ term: { product: product } }
|
65
|
+
]
|
66
|
+
}
|
67
|
+
},
|
68
|
+
{
|
69
|
+
bool: {
|
70
|
+
must: {
|
71
|
+
term: { term_key: term }
|
72
|
+
},
|
73
|
+
must_not: {
|
74
|
+
exists: { field: 'product' }
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
]
|
79
|
+
}
|
80
|
+
}
|
81
|
+
]
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
mash = Hashie::Mash.new response
|
87
|
+
|
88
|
+
return nil if mash.hits.hits.first.nil?
|
89
|
+
|
90
|
+
return mash.hits.hits.first._source.classification
|
91
|
+
end
|
92
|
+
|
93
|
+
def save(doc_id, product_type, product, term, classification)
|
94
|
+
#@logger.debug("saving key to local classification db")
|
95
|
+
|
96
|
+
@elastic.index index: @index, type: '_doc', id: doc_id, body: {
|
97
|
+
product_type: product_type,
|
98
|
+
product: product,
|
99
|
+
term_key: term,
|
100
|
+
classification: classification
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def close
|
105
|
+
#@logger.debug("clsoing the local classification db")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end; end; end
|
110
|
+
|
111
|
+
=begin
|
112
|
+
db = LogStash::Filters::Empow::PersistentKeyValueDB.new('192.168.3.24:9200', 'user', 'pass', 'key-val-8')
|
113
|
+
|
114
|
+
db.save("am", "p3", "dummy signature", "v1")
|
115
|
+
db.save("am", "p3", "dummy signature 2", "v1")
|
116
|
+
|
117
|
+
db.save("am", "p1", "dummy", "v1")
|
118
|
+
db.save("am", nil, "dummy", "v1")
|
119
|
+
p db.query "am", "p1", "h1"
|
120
|
+
db.save("am", "p1", "h1", "v1")
|
121
|
+
p db.query "am", "p1", "h1"
|
122
|
+
p db.query "am", "p1", "h2"
|
123
|
+
p db.query "am", "no-such-product", "h1"
|
124
|
+
p db.query "am", nil, "h1"
|
125
|
+
p db.query "am", nil, "dummy"
|
126
|
+
|
127
|
+
p db.query "am", "p3", "dummy signature 2"
|
128
|
+
=end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/filters/base"
|
3
|
+
require "elasticsearch"
|
4
|
+
|
5
|
+
require_relative "elastic-db"
|
6
|
+
require_relative "local-classifier"
|
7
|
+
require_relative "classifier"
|
8
|
+
require_relative "center-client"
|
9
|
+
require_relative "plugin-logic"
|
10
|
+
require_relative "utils"
|
11
|
+
|
12
|
+
#
|
13
|
+
class LogStash::Filters::EmpowClassifier < LogStash::Filters::Base
|
14
|
+
|
15
|
+
config_name "empowclassifier"
|
16
|
+
|
17
|
+
# The mail address used when registering to the classification center.
|
18
|
+
config :username, :validate => :string, :required => true
|
19
|
+
|
20
|
+
# The password for the classification center.
|
21
|
+
config :password, :validate => :string, :required => true
|
22
|
+
|
23
|
+
# user pool id. this parameter needs to be set only when using an entire empow stack, open source users should leave this unchanged.
|
24
|
+
config :pool_id, :validate => :string, :default => '8dljcvt4jfif762le0ald6j'
|
25
|
+
|
26
|
+
# Size of the local response cache
|
27
|
+
config :cache_size, :validate => :number, :default => 10000
|
28
|
+
|
29
|
+
# The maximum number of events that may wait in memory for a classification result from the classification center
|
30
|
+
config :max_pending_requests, :validate => :number, :default => 10000
|
31
|
+
|
32
|
+
# Time to wait in seconds an event will wait for a classification before returning to the pipeline with no result
|
33
|
+
config :pending_request_timeout, :validate => :number, :default => 60
|
34
|
+
|
35
|
+
# Max number of concurrent threads classifying via the classification center
|
36
|
+
# These threads mostly wait on I/O during the web request, and aren't cpu intensive.
|
37
|
+
# Idle workers are closed after one minute, only one idle worker remains alive for incoming request on peace time.
|
38
|
+
config :max_classification_center_workers, :validate => :number, :default => 5
|
39
|
+
|
40
|
+
# Classfication center bulk request size
|
41
|
+
config :bulk_request_size, :validate => :number, :default => 50
|
42
|
+
|
43
|
+
# Seconds to wait for batch to fill up before querying the classification center.
|
44
|
+
config :bulk_request_interval, :validate => :number, :default => 2
|
45
|
+
|
46
|
+
# Max number of times each request will be query the classification center.
|
47
|
+
config :max_query_retries, :validate => :number, :default => 5
|
48
|
+
|
49
|
+
# Seconds to wait before reclassifying an in-progress request. In progress response will occur when the classification center is processing a new threat.
|
50
|
+
config :time_between_queries, :validate => :number, :default => 10
|
51
|
+
|
52
|
+
# Allows renaimg the log field containing the log's product type. Possible values are AM for Anti-Malware and IDS for Intrusion Detection systems.
|
53
|
+
# For example, if our log contained a 'log_type' field (instead of the expected product_type field),
|
54
|
+
# We would configure the plugin as follows:
|
55
|
+
# [source,ruby]
|
56
|
+
# filter {
|
57
|
+
# empowclassifier {
|
58
|
+
# username => "happy"
|
59
|
+
# password => "festivus"
|
60
|
+
# product_type_field => "log_type"
|
61
|
+
# }
|
62
|
+
# }
|
63
|
+
config :product_type_field, :validate => :string, :default => "product_type"
|
64
|
+
|
65
|
+
# Allows renaimg the log field containing the log's product name.
|
66
|
+
# Assuming our log contained a 'product' field (instead of the expected product_name field),
|
67
|
+
# We would configure the plugin as follows:
|
68
|
+
# [source,ruby]
|
69
|
+
# filter {
|
70
|
+
# empowclassifier {
|
71
|
+
# username => "happy"
|
72
|
+
# password => "festivus"
|
73
|
+
# product_type_field => "product"
|
74
|
+
# }
|
75
|
+
# }
|
76
|
+
config :product_name_field, :validate => :string, :default => "product_name"
|
77
|
+
config :threat_field, :validate => :string, :default => "threat"
|
78
|
+
|
79
|
+
# Configs the name of the field used to indicate whether the source described in the log was within the internal network.
|
80
|
+
# Example:
|
81
|
+
# [source,ruby]
|
82
|
+
# filter {
|
83
|
+
# empowclassifier {
|
84
|
+
# ...
|
85
|
+
# src_internal_field => "internal_src"
|
86
|
+
# }
|
87
|
+
# }
|
88
|
+
config :src_internal_field, :validate => :string, :default => "is_src_internal"
|
89
|
+
|
90
|
+
# Configs the name of the field used to indicate whether the destination described in the log was within the internal network.
|
91
|
+
# Example:
|
92
|
+
# [source,ruby]
|
93
|
+
# filter {
|
94
|
+
# empowclassifier {
|
95
|
+
# ...
|
96
|
+
# dst_internal_field => "internal_dst"
|
97
|
+
# }
|
98
|
+
# }
|
99
|
+
config :dst_internal_field, :validate => :string, :default => "is_dst_internal"
|
100
|
+
|
101
|
+
# changes the api root for customers of the commercial empow stack
|
102
|
+
config :base_url, :validate => :string, :default => ""
|
103
|
+
|
104
|
+
config :async_local_cache, :validate => :boolean, :default => true
|
105
|
+
|
106
|
+
# elastic config params
|
107
|
+
########################
|
108
|
+
|
109
|
+
config :elastic_hosts, :validate => :array
|
110
|
+
|
111
|
+
# The index or alias to write to
|
112
|
+
config :elastic_index, :validate => :string, :default => "empow-intent-db"
|
113
|
+
|
114
|
+
config :elastic_user, :validate => :string
|
115
|
+
config :elastic_password, :validate => :password
|
116
|
+
|
117
|
+
# failure tags
|
118
|
+
###############
|
119
|
+
config :tag_on_product_type_failure, :validate => :array, :default => ['_empow_no_product_type']
|
120
|
+
config :tag_on_signature_failure, :validate => :array, :default => ['_empow_no_signature']
|
121
|
+
config :tag_on_timeout, :validate => :array, :default => ['_empow_classifer_timeout']
|
122
|
+
config :tag_on_error, :validate => :array, :default => ['_empow_classifer_error']
|
123
|
+
|
124
|
+
CLASSIFICATION_URL = "https://s0apxz9wik.execute-api.us-east-2.amazonaws.com" #"https://intent.cloud.empow.co"
|
125
|
+
CACHE_TTL = (24*60*60)
|
126
|
+
|
127
|
+
public
|
128
|
+
def register
|
129
|
+
@logger.info("registering empow classifcation plugin")
|
130
|
+
|
131
|
+
validate_params()
|
132
|
+
|
133
|
+
local_db = create_local_database
|
134
|
+
|
135
|
+
local_classifier = LogStash::Filters::Empow::LocalClassifier.new(@cache_size, CACHE_TTL, @async_local_cache, local_db)
|
136
|
+
|
137
|
+
base_url = get_effective_url()
|
138
|
+
online_classifier = LogStash::Filters::Empow::ClassificationCenterClient.new(@username, @password, @pool_id, base_url)
|
139
|
+
|
140
|
+
classifer = LogStash::Filters::Empow::Classifier.new(online_classifier, local_classifier, @max_classification_center_workers, @bulk_request_size, @bulk_request_interval, @max_query_retries, @time_between_queries)
|
141
|
+
|
142
|
+
field_handler = LogStash::Filters::Empow::FieldHandler.new(@product_type_field, @product_name_field, @threat_field, @src_internal_field, @dst_internal_field)
|
143
|
+
|
144
|
+
@plugin_core ||= LogStash::Filters::Empow::PluginLogic.new(classifer, field_handler, @pending_request_timeout, @max_pending_requests, @tag_on_timeout, @tag_on_error)
|
145
|
+
|
146
|
+
@logger.info("empow classifcation plugin registered")
|
147
|
+
end # def register
|
148
|
+
|
149
|
+
private
|
150
|
+
def get_effective_url
|
151
|
+
if (@base_url.nil? or @base_url.strip == 0)
|
152
|
+
return CLASSIFICATION_URL
|
153
|
+
end
|
154
|
+
|
155
|
+
return CLASSIFICATION_URL
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
def validate_params
|
160
|
+
raise ArgumentError, 'threat field cannot be empty' if LogStash::Filters::Empow::Utils.is_blank_string(@threat_field)
|
161
|
+
|
162
|
+
raise ArgumentError, 'bulk_request_size must be an positive number between 1 and 1000' if (@bulk_request_size < 1 or @bulk_request_size > 1000)
|
163
|
+
|
164
|
+
raise ArgumentError, 'bulk_request_interval must be an greater or equal to 1' if (@bulk_request_interval < 1)
|
165
|
+
end
|
166
|
+
|
167
|
+
def close
|
168
|
+
@logger.info("closing the empow classifcation plugin")
|
169
|
+
|
170
|
+
@plugin_core.close
|
171
|
+
|
172
|
+
@logger.info("empow classifcation plugin closed")
|
173
|
+
end
|
174
|
+
|
175
|
+
def periodic_flush
|
176
|
+
true
|
177
|
+
end
|
178
|
+
|
179
|
+
public def flush(options = {})
|
180
|
+
@logger.debug("entered flush")
|
181
|
+
|
182
|
+
events_to_flush = []
|
183
|
+
|
184
|
+
begin
|
185
|
+
parked_events = @plugin_core.flush(options)
|
186
|
+
|
187
|
+
parked_events.each do |event|
|
188
|
+
# need to clone as original event was canceled
|
189
|
+
cloned_event = event.clone
|
190
|
+
events_to_flush << cloned_event
|
191
|
+
end
|
192
|
+
|
193
|
+
rescue StandardError => e
|
194
|
+
@logger.error("encountered an exception while processing flush. #{e}")
|
195
|
+
end
|
196
|
+
|
197
|
+
@logger.debug("flush ended", :flushed_event_count => events_to_flush.length)
|
198
|
+
|
199
|
+
return events_to_flush
|
200
|
+
end
|
201
|
+
|
202
|
+
public def filter(event)
|
203
|
+
res = event
|
204
|
+
|
205
|
+
begin
|
206
|
+
res = @plugin_core.classify(event)
|
207
|
+
|
208
|
+
if res.nil?
|
209
|
+
event.cancel # don't stream this event just yet ...
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
# event was classified and returned, not some overflow event
|
214
|
+
if res.equal? event
|
215
|
+
filter_matched(event)
|
216
|
+
return
|
217
|
+
end
|
218
|
+
|
219
|
+
# got here with a parked event
|
220
|
+
res = res.clone
|
221
|
+
filter_matched(res)
|
222
|
+
|
223
|
+
@logger.debug("filter matched for overflow event", :event => res)
|
224
|
+
|
225
|
+
rescue StandardError => e
|
226
|
+
@logger.error("encountered an exception while classifying", :error => e, :event => event, :backtrace => e.backtrace)
|
227
|
+
|
228
|
+
@tag_on_error.each{|tag| event.tag(tag)}
|
229
|
+
|
230
|
+
return res
|
231
|
+
end
|
232
|
+
end # def filter
|
233
|
+
|
234
|
+
private def create_local_database
|
235
|
+
# if no elastic host has been configured, no local db should be used
|
236
|
+
if @elastic_hosts.nil?
|
237
|
+
@logger.info("no local persisted cache is configured")
|
238
|
+
return nil
|
239
|
+
end
|
240
|
+
|
241
|
+
begin
|
242
|
+
return LogStash::Filters::Empow::PersistentKeyValueDB.new(:elastic_hosts, :elastic_user, :elastic_password, :elastic_index)
|
243
|
+
rescue StandardError => e
|
244
|
+
@logger.error("caught an exception while trying to configured persisted cache", e)
|
245
|
+
end
|
246
|
+
|
247
|
+
return nil
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require_relative "classification-request"
|
2
|
+
require_relative "utils"
|
3
|
+
|
4
|
+
class LogStash::Filters::Empow::FieldHandler
|
5
|
+
|
6
|
+
IDS = "IDS"
|
7
|
+
AM = "AM"
|
8
|
+
CUSTOM = "CUSTOM"
|
9
|
+
|
10
|
+
public
|
11
|
+
def initialize(product_type_field, product_name_field, threat_field, src_internal_field, dst_internal_field)
|
12
|
+
@product_type_field = product_type_field
|
13
|
+
@product_name_field = product_name_field
|
14
|
+
|
15
|
+
if threat_field.nil? || threat_field.strip.length == 0
|
16
|
+
raise ArgumentError, 'threat field cannot be empty'
|
17
|
+
end
|
18
|
+
|
19
|
+
@threat_field = '[' + threat_field + ']'
|
20
|
+
|
21
|
+
@ids_signature_field = @threat_field + '[signature]'
|
22
|
+
@malware_name_field = @threat_field + '[malware_name]'
|
23
|
+
|
24
|
+
@src_internal_field = @threat_field + '[' + src_internal_field + ']'
|
25
|
+
@dst_internal_field = @threat_field + '[' + dst_internal_field + ']'
|
26
|
+
|
27
|
+
@hash_field = @threat_field + '[hash]'
|
28
|
+
end
|
29
|
+
|
30
|
+
public
|
31
|
+
def event_to_classification_request(event)
|
32
|
+
product_type = event.get(@product_type_field)
|
33
|
+
product = event.get(@product_name_field)
|
34
|
+
is_src_internal = event.get(@src_internal_field)
|
35
|
+
is_dst_internal = event.get(@dst_internal_field)
|
36
|
+
|
37
|
+
if product_type.nil?
|
38
|
+
LogStash::Filters::Empow::Utils.add_error(event, "missing_product_type")
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
|
42
|
+
is_src_internal = LogStash::Filters::Empow::Utils.convert_to_boolean(is_src_internal)
|
43
|
+
|
44
|
+
if is_src_internal.nil?
|
45
|
+
is_src_internal = true
|
46
|
+
LogStash::Filters::Empow::Utils.add_warn(event, 'src_internal_wrong_value')
|
47
|
+
end
|
48
|
+
|
49
|
+
is_dst_internal = LogStash::Filters::Empow::Utils.convert_to_boolean(is_dst_internal)
|
50
|
+
|
51
|
+
if is_dst_internal.nil?
|
52
|
+
is_dst_internal = true
|
53
|
+
LogStash::Filters::Empow::Utils.add_warn(event, 'dst_internal_wrong_value')
|
54
|
+
end
|
55
|
+
|
56
|
+
case product_type
|
57
|
+
when IDS
|
58
|
+
return nil if !is_valid_ids_request(product, event)
|
59
|
+
when AM
|
60
|
+
return nil if !is_valid_antimalware_request(product, event)
|
61
|
+
else # others are resolved in the cloud
|
62
|
+
return nil if !is_valid_product(product, event)
|
63
|
+
end
|
64
|
+
|
65
|
+
original_threat = event.get(@threat_field)
|
66
|
+
|
67
|
+
threat = copy_threat(original_threat)
|
68
|
+
|
69
|
+
if (threat.nil?)
|
70
|
+
LogStash::Filters::Empow::Utils.add_error(event, "missing_threat_field")
|
71
|
+
return nil
|
72
|
+
end
|
73
|
+
|
74
|
+
threat['is_src_internal'] = is_src_internal
|
75
|
+
threat['is_dst_internal'] = is_dst_internal
|
76
|
+
|
77
|
+
return LogStash::Filters::Empow::ClassificationRequest.new(product_type, product, threat)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def copy_threat(threat)
|
82
|
+
return nil if (threat.nil? or threat.size == 0)
|
83
|
+
|
84
|
+
res = Hash.new
|
85
|
+
|
86
|
+
threat.each do |k, v|
|
87
|
+
res[k] = v
|
88
|
+
end
|
89
|
+
|
90
|
+
return res
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
def is_valid_ids_request(product, event)
|
95
|
+
sid = event.get(@ids_signature_field)
|
96
|
+
|
97
|
+
if sid.nil? || sid.strip.length == 0
|
98
|
+
LogStash::Filters::Empow::Utils.add_error(event, "missing_ids_signature")
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
return is_valid_product(product, event)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def is_valid_product(product, event)
|
107
|
+
if (product.nil? or product.strip.length == 0)
|
108
|
+
LogStash::Filters::Empow::Utils.add_error(event, "missing_product_name")
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
|
112
|
+
return true
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def is_valid_antimalware_request(product, event)
|
117
|
+
malware_name = event.get(@malware_name_field)
|
118
|
+
malware_hash = event.get(@hash_field)
|
119
|
+
|
120
|
+
if malware_hash.nil? and (malware_name.nil? or product.nil?)
|
121
|
+
LogStash::Filters::Empow::Utils.add_error(event, "anti_malware_missing_hash_or_name")
|
122
|
+
return false
|
123
|
+
end
|
124
|
+
|
125
|
+
return true
|
126
|
+
end
|
127
|
+
end
|