logstash-filter-empowclassifier 0.3.15
Sign up to get free protection for your applications and to get access to all the features.
- 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
|