ai_root_shield 0.4.0 → 1.0.0
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 +4 -4
- data/CHANGELOG.md +52 -4
- data/README.md +191 -14
- data/bindings/python/README.md +304 -0
- data/bindings/python/ai_root_shield.py +438 -0
- data/bindings/python/setup.py +65 -0
- data/examples/device_logs/android_safetynet_device.json +148 -0
- data/examples/device_logs/ios_jailbroken_device.json +172 -0
- data/exe/ai_root_shield +220 -7
- data/lib/ai_root_shield/ci_cd/security_test_module.rb +743 -0
- data/lib/ai_root_shield/dashboard/web_dashboard.rb +441 -0
- data/lib/ai_root_shield/enterprise/alert_system.rb +601 -0
- data/lib/ai_root_shield/enterprise/hybrid_detection_engine.rb +650 -0
- data/lib/ai_root_shield/enterprise/performance_optimizer.rb +613 -0
- data/lib/ai_root_shield/enterprise/policy_manager.rb +637 -0
- data/lib/ai_root_shield/integrations/siem_connector.rb +695 -0
- data/lib/ai_root_shield/platform/android_security_module.rb +263 -0
- data/lib/ai_root_shield/platform/hardware_security_analyzer.rb +452 -0
- data/lib/ai_root_shield/platform/ios_security_module.rb +513 -0
- data/lib/ai_root_shield/platform/unified_report_generator.rb +613 -0
- data/lib/ai_root_shield/version.rb +1 -1
- data/lib/ai_root_shield.rb +152 -1
- data/security_test_artifacts/security_report.json +124 -0
- data/security_test_artifacts/security_results.sarif +16 -0
- data/security_test_artifacts/security_tests.xml +3 -0
- metadata +20 -1
@@ -0,0 +1,695 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'uri'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
module AiRootShield
|
9
|
+
module Integrations
|
10
|
+
# SIEM and SOC integration connector for third-party security platforms
|
11
|
+
class SiemConnector
|
12
|
+
# Supported SIEM platforms
|
13
|
+
SUPPORTED_PLATFORMS = {
|
14
|
+
splunk: 'Splunk Enterprise/Cloud',
|
15
|
+
elastic: 'Elastic Stack (ELK)',
|
16
|
+
qradar: 'IBM QRadar',
|
17
|
+
sentinel: 'Microsoft Sentinel',
|
18
|
+
sumo_logic: 'Sumo Logic',
|
19
|
+
datadog: 'Datadog Security',
|
20
|
+
chronicle: 'Google Chronicle',
|
21
|
+
arcsight: 'Micro Focus ArcSight'
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
# Event severity levels
|
25
|
+
SEVERITY_LEVELS = {
|
26
|
+
info: 1,
|
27
|
+
low: 2,
|
28
|
+
medium: 3,
|
29
|
+
high: 4,
|
30
|
+
critical: 5
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
def initialize(platform, config = {})
|
34
|
+
@platform = platform.to_sym
|
35
|
+
@config = config
|
36
|
+
@api_endpoint = config[:api_endpoint]
|
37
|
+
@api_key = config[:api_key]
|
38
|
+
@index = config[:index] || 'ai_root_shield'
|
39
|
+
@source_type = config[:source_type] || 'mobile_security'
|
40
|
+
@timeout = config[:timeout] || 30
|
41
|
+
|
42
|
+
validate_configuration
|
43
|
+
end
|
44
|
+
|
45
|
+
# Send security events to SIEM platform
|
46
|
+
def send_security_event(analysis_results, metadata = {})
|
47
|
+
event_data = format_security_event(analysis_results, metadata)
|
48
|
+
|
49
|
+
case @platform
|
50
|
+
when :splunk
|
51
|
+
send_to_splunk(event_data)
|
52
|
+
when :elastic
|
53
|
+
send_to_elastic(event_data)
|
54
|
+
when :qradar
|
55
|
+
send_to_qradar(event_data)
|
56
|
+
when :sentinel
|
57
|
+
send_to_sentinel(event_data)
|
58
|
+
when :sumo_logic
|
59
|
+
send_to_sumo_logic(event_data)
|
60
|
+
when :datadog
|
61
|
+
send_to_datadog(event_data)
|
62
|
+
when :chronicle
|
63
|
+
send_to_chronicle(event_data)
|
64
|
+
when :arcsight
|
65
|
+
send_to_arcsight(event_data)
|
66
|
+
else
|
67
|
+
raise "Unsupported SIEM platform: #{@platform}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Send batch of security events
|
72
|
+
def send_batch_events(analysis_results_array, metadata = {})
|
73
|
+
batch_data = analysis_results_array.map do |results|
|
74
|
+
format_security_event(results, metadata)
|
75
|
+
end
|
76
|
+
|
77
|
+
case @platform
|
78
|
+
when :splunk
|
79
|
+
send_batch_to_splunk(batch_data)
|
80
|
+
when :elastic
|
81
|
+
send_batch_to_elastic(batch_data)
|
82
|
+
else
|
83
|
+
# For platforms without native batch support, send individually
|
84
|
+
batch_data.each { |event| send_security_event(event, metadata) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create security alert based on risk threshold
|
89
|
+
def create_security_alert(analysis_results, alert_config = {})
|
90
|
+
risk_score = analysis_results[:risk_score] || 0
|
91
|
+
threshold = alert_config[:threshold] || 70
|
92
|
+
|
93
|
+
return unless risk_score >= threshold
|
94
|
+
|
95
|
+
alert_data = {
|
96
|
+
alert_id: generate_alert_id,
|
97
|
+
timestamp: Time.now.utc.iso8601,
|
98
|
+
severity: determine_alert_severity(risk_score),
|
99
|
+
title: generate_alert_title(analysis_results),
|
100
|
+
description: generate_alert_description(analysis_results),
|
101
|
+
risk_score: risk_score,
|
102
|
+
risk_factors: analysis_results[:risk_factors] || [],
|
103
|
+
platform: analysis_results[:platform] || 'unknown',
|
104
|
+
device_info: extract_device_info(analysis_results),
|
105
|
+
remediation_steps: generate_remediation_steps(analysis_results),
|
106
|
+
tags: generate_alert_tags(analysis_results)
|
107
|
+
}
|
108
|
+
|
109
|
+
send_alert(alert_data)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Query SIEM for historical security events
|
113
|
+
def query_security_events(query_params = {})
|
114
|
+
case @platform
|
115
|
+
when :splunk
|
116
|
+
query_splunk(query_params)
|
117
|
+
when :elastic
|
118
|
+
query_elastic(query_params)
|
119
|
+
when :qradar
|
120
|
+
query_qradar(query_params)
|
121
|
+
else
|
122
|
+
raise "Query not supported for platform: #{@platform}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Generate security dashboard URL
|
127
|
+
def generate_dashboard_url(dashboard_type = 'overview')
|
128
|
+
case @platform
|
129
|
+
when :splunk
|
130
|
+
"#{@api_endpoint}/app/search/ai_root_shield_#{dashboard_type}"
|
131
|
+
when :elastic
|
132
|
+
"#{@api_endpoint}/app/kibana#/dashboard/ai-root-shield-#{dashboard_type}"
|
133
|
+
when :datadog
|
134
|
+
"#{@api_endpoint}/dashboard/ai-root-shield-#{dashboard_type}"
|
135
|
+
else
|
136
|
+
@api_endpoint
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Validate SIEM configuration
|
143
|
+
def validate_configuration
|
144
|
+
raise "API endpoint required for #{@platform}" unless @api_endpoint
|
145
|
+
raise "API key required for #{@platform}" unless @api_key
|
146
|
+
|
147
|
+
unless SUPPORTED_PLATFORMS.key?(@platform)
|
148
|
+
raise "Unsupported SIEM platform: #{@platform}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Format security event for SIEM ingestion
|
153
|
+
def format_security_event(analysis_results, metadata)
|
154
|
+
{
|
155
|
+
timestamp: Time.now.utc.iso8601,
|
156
|
+
event_type: 'mobile_security_analysis',
|
157
|
+
source: 'ai_root_shield',
|
158
|
+
version: AiRootShield::VERSION,
|
159
|
+
severity: determine_event_severity(analysis_results[:risk_score]),
|
160
|
+
risk_score: analysis_results[:risk_score] || 0,
|
161
|
+
risk_level: determine_risk_level(analysis_results[:risk_score]),
|
162
|
+
platform: analysis_results[:platform] || 'unknown',
|
163
|
+
risk_factors: analysis_results[:risk_factors] || [],
|
164
|
+
device_info: extract_device_info(analysis_results),
|
165
|
+
security_analysis: format_security_analysis(analysis_results),
|
166
|
+
compliance_status: extract_compliance_status(analysis_results),
|
167
|
+
metadata: metadata,
|
168
|
+
tags: generate_event_tags(analysis_results)
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
# Splunk integration methods
|
173
|
+
def send_to_splunk(event_data)
|
174
|
+
uri = URI("#{@api_endpoint}/services/collector/event")
|
175
|
+
|
176
|
+
payload = {
|
177
|
+
time: Time.now.to_i,
|
178
|
+
host: Socket.gethostname,
|
179
|
+
source: 'ai_root_shield',
|
180
|
+
sourcetype: @source_type,
|
181
|
+
index: @index,
|
182
|
+
event: event_data
|
183
|
+
}
|
184
|
+
|
185
|
+
send_http_request(uri, payload, {
|
186
|
+
'Authorization' => "Splunk #{@api_key}",
|
187
|
+
'Content-Type' => 'application/json'
|
188
|
+
})
|
189
|
+
end
|
190
|
+
|
191
|
+
def send_batch_to_splunk(batch_data)
|
192
|
+
uri = URI("#{@api_endpoint}/services/collector/event")
|
193
|
+
|
194
|
+
batch_payload = batch_data.map do |event|
|
195
|
+
{
|
196
|
+
time: Time.now.to_i,
|
197
|
+
host: Socket.gethostname,
|
198
|
+
source: 'ai_root_shield',
|
199
|
+
sourcetype: @source_type,
|
200
|
+
index: @index,
|
201
|
+
event: event
|
202
|
+
}
|
203
|
+
end.join("\n")
|
204
|
+
|
205
|
+
send_http_request(uri, batch_payload, {
|
206
|
+
'Authorization' => "Splunk #{@api_key}",
|
207
|
+
'Content-Type' => 'application/json'
|
208
|
+
})
|
209
|
+
end
|
210
|
+
|
211
|
+
def query_splunk(query_params)
|
212
|
+
search_query = build_splunk_query(query_params)
|
213
|
+
uri = URI("#{@api_endpoint}/services/search/jobs")
|
214
|
+
|
215
|
+
payload = {
|
216
|
+
search: search_query,
|
217
|
+
output_mode: 'json'
|
218
|
+
}
|
219
|
+
|
220
|
+
send_http_request(uri, payload, {
|
221
|
+
'Authorization' => "Splunk #{@api_key}",
|
222
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
223
|
+
})
|
224
|
+
end
|
225
|
+
|
226
|
+
# Elastic Stack integration methods
|
227
|
+
def send_to_elastic(event_data)
|
228
|
+
uri = URI("#{@api_endpoint}/#{@index}/_doc")
|
229
|
+
|
230
|
+
send_http_request(uri, event_data, {
|
231
|
+
'Authorization' => "ApiKey #{@api_key}",
|
232
|
+
'Content-Type' => 'application/json'
|
233
|
+
})
|
234
|
+
end
|
235
|
+
|
236
|
+
def send_batch_to_elastic(batch_data)
|
237
|
+
uri = URI("#{@api_endpoint}/_bulk")
|
238
|
+
|
239
|
+
bulk_payload = batch_data.map do |event|
|
240
|
+
index_line = { index: { _index: @index } }
|
241
|
+
"#{index_line.to_json}\n#{event.to_json}"
|
242
|
+
end.join("\n") + "\n"
|
243
|
+
|
244
|
+
send_http_request(uri, bulk_payload, {
|
245
|
+
'Authorization' => "ApiKey #{@api_key}",
|
246
|
+
'Content-Type' => 'application/x-ndjson'
|
247
|
+
})
|
248
|
+
end
|
249
|
+
|
250
|
+
def query_elastic(query_params)
|
251
|
+
uri = URI("#{@api_endpoint}/#{@index}/_search")
|
252
|
+
|
253
|
+
query = build_elastic_query(query_params)
|
254
|
+
|
255
|
+
send_http_request(uri, query, {
|
256
|
+
'Authorization' => "ApiKey #{@api_key}",
|
257
|
+
'Content-Type' => 'application/json'
|
258
|
+
})
|
259
|
+
end
|
260
|
+
|
261
|
+
# QRadar integration methods
|
262
|
+
def send_to_qradar(event_data)
|
263
|
+
uri = URI("#{@api_endpoint}/api/siem/events")
|
264
|
+
|
265
|
+
qradar_event = format_qradar_event(event_data)
|
266
|
+
|
267
|
+
send_http_request(uri, qradar_event, {
|
268
|
+
'SEC' => @api_key,
|
269
|
+
'Content-Type' => 'application/json'
|
270
|
+
})
|
271
|
+
end
|
272
|
+
|
273
|
+
def query_qradar(query_params)
|
274
|
+
uri = URI("#{@api_endpoint}/api/siem/events")
|
275
|
+
|
276
|
+
query = build_qradar_query(query_params)
|
277
|
+
uri.query = URI.encode_www_form(query)
|
278
|
+
|
279
|
+
send_http_request(uri, nil, {
|
280
|
+
'SEC' => @api_key,
|
281
|
+
'Accept' => 'application/json'
|
282
|
+
}, 'GET')
|
283
|
+
end
|
284
|
+
|
285
|
+
# Microsoft Sentinel integration methods
|
286
|
+
def send_to_sentinel(event_data)
|
287
|
+
uri = URI("#{@api_endpoint}/api/logs")
|
288
|
+
|
289
|
+
sentinel_event = format_sentinel_event(event_data)
|
290
|
+
|
291
|
+
send_http_request(uri, sentinel_event, {
|
292
|
+
'Authorization' => "Bearer #{@api_key}",
|
293
|
+
'Content-Type' => 'application/json',
|
294
|
+
'Log-Type' => 'AiRootShieldSecurityEvent'
|
295
|
+
})
|
296
|
+
end
|
297
|
+
|
298
|
+
# Sumo Logic integration methods
|
299
|
+
def send_to_sumo_logic(event_data)
|
300
|
+
uri = URI(@api_endpoint) # Sumo Logic HTTP collector endpoint
|
301
|
+
|
302
|
+
send_http_request(uri, event_data, {
|
303
|
+
'Content-Type' => 'application/json',
|
304
|
+
'X-Sumo-Name' => 'AI Root Shield Security Events',
|
305
|
+
'X-Sumo-Category' => 'mobile_security'
|
306
|
+
})
|
307
|
+
end
|
308
|
+
|
309
|
+
# Datadog integration methods
|
310
|
+
def send_to_datadog(event_data)
|
311
|
+
uri = URI("#{@api_endpoint}/v1/logs")
|
312
|
+
|
313
|
+
datadog_event = format_datadog_event(event_data)
|
314
|
+
|
315
|
+
send_http_request(uri, datadog_event, {
|
316
|
+
'DD-API-KEY' => @api_key,
|
317
|
+
'Content-Type' => 'application/json'
|
318
|
+
})
|
319
|
+
end
|
320
|
+
|
321
|
+
# Google Chronicle integration methods
|
322
|
+
def send_to_chronicle(event_data)
|
323
|
+
uri = URI("#{@api_endpoint}/v1/unstructuredlogentries:batchCreate")
|
324
|
+
|
325
|
+
chronicle_event = format_chronicle_event(event_data)
|
326
|
+
|
327
|
+
send_http_request(uri, chronicle_event, {
|
328
|
+
'Authorization' => "Bearer #{@api_key}",
|
329
|
+
'Content-Type' => 'application/json'
|
330
|
+
})
|
331
|
+
end
|
332
|
+
|
333
|
+
# ArcSight integration methods
|
334
|
+
def send_to_arcsight(event_data)
|
335
|
+
uri = URI("#{@api_endpoint}/logger/api/events")
|
336
|
+
|
337
|
+
arcsight_event = format_arcsight_event(event_data)
|
338
|
+
|
339
|
+
send_http_request(uri, arcsight_event, {
|
340
|
+
'Authorization' => "Basic #{@api_key}",
|
341
|
+
'Content-Type' => 'application/json'
|
342
|
+
})
|
343
|
+
end
|
344
|
+
|
345
|
+
# Alert methods
|
346
|
+
def send_alert(alert_data)
|
347
|
+
case @platform
|
348
|
+
when :splunk
|
349
|
+
send_splunk_alert(alert_data)
|
350
|
+
when :elastic
|
351
|
+
send_elastic_alert(alert_data)
|
352
|
+
when :datadog
|
353
|
+
send_datadog_alert(alert_data)
|
354
|
+
else
|
355
|
+
# Send as regular event with alert flag
|
356
|
+
alert_event = alert_data.merge(event_type: 'security_alert')
|
357
|
+
send_security_event(alert_event)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# HTTP request helper
|
362
|
+
def send_http_request(uri, payload, headers, method = 'POST')
|
363
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
364
|
+
http.use_ssl = uri.scheme == 'https'
|
365
|
+
http.read_timeout = @timeout
|
366
|
+
|
367
|
+
request = case method.upcase
|
368
|
+
when 'GET'
|
369
|
+
Net::HTTP::Get.new(uri)
|
370
|
+
when 'POST'
|
371
|
+
Net::HTTP::Post.new(uri)
|
372
|
+
when 'PUT'
|
373
|
+
Net::HTTP::Put.new(uri)
|
374
|
+
else
|
375
|
+
raise "Unsupported HTTP method: #{method}"
|
376
|
+
end
|
377
|
+
|
378
|
+
headers.each { |key, value| request[key] = value }
|
379
|
+
|
380
|
+
if payload
|
381
|
+
request.body = payload.is_a?(String) ? payload : payload.to_json
|
382
|
+
end
|
383
|
+
|
384
|
+
response = http.request(request)
|
385
|
+
|
386
|
+
unless response.code.start_with?('2')
|
387
|
+
raise "SIEM request failed: #{response.code} - #{response.body}"
|
388
|
+
end
|
389
|
+
|
390
|
+
JSON.parse(response.body) if response.body && !response.body.empty?
|
391
|
+
rescue JSON::ParserError
|
392
|
+
response.body
|
393
|
+
end
|
394
|
+
|
395
|
+
# Utility methods
|
396
|
+
def determine_event_severity(risk_score)
|
397
|
+
case risk_score
|
398
|
+
when 0..20
|
399
|
+
SEVERITY_LEVELS[:info]
|
400
|
+
when 21..40
|
401
|
+
SEVERITY_LEVELS[:low]
|
402
|
+
when 41..70
|
403
|
+
SEVERITY_LEVELS[:medium]
|
404
|
+
when 71..85
|
405
|
+
SEVERITY_LEVELS[:high]
|
406
|
+
else
|
407
|
+
SEVERITY_LEVELS[:critical]
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def determine_alert_severity(risk_score)
|
412
|
+
case risk_score
|
413
|
+
when 70..79
|
414
|
+
'high'
|
415
|
+
when 80..89
|
416
|
+
'critical'
|
417
|
+
else
|
418
|
+
'critical'
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def determine_risk_level(risk_score)
|
423
|
+
case risk_score
|
424
|
+
when 0..20
|
425
|
+
'LOW'
|
426
|
+
when 21..40
|
427
|
+
'MEDIUM'
|
428
|
+
when 41..70
|
429
|
+
'HIGH'
|
430
|
+
else
|
431
|
+
'CRITICAL'
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def extract_device_info(analysis_results)
|
436
|
+
{
|
437
|
+
platform: analysis_results[:platform],
|
438
|
+
device_model: analysis_results.dig(:device_info, :model),
|
439
|
+
os_version: analysis_results.dig(:device_info, :os_version),
|
440
|
+
app_version: analysis_results.dig(:device_info, :app_version)
|
441
|
+
}
|
442
|
+
end
|
443
|
+
|
444
|
+
def format_security_analysis(analysis_results)
|
445
|
+
{
|
446
|
+
safetynet: analysis_results[:safetynet],
|
447
|
+
play_integrity: analysis_results[:play_integrity],
|
448
|
+
jailbreak_detection: analysis_results[:jailbreak_detection],
|
449
|
+
code_signing: analysis_results[:code_signing],
|
450
|
+
hardware_security: analysis_results[:hardware_security],
|
451
|
+
system_integrity: analysis_results[:system_integrity]
|
452
|
+
}.compact
|
453
|
+
end
|
454
|
+
|
455
|
+
def extract_compliance_status(analysis_results)
|
456
|
+
analysis_results[:compliance] || {}
|
457
|
+
end
|
458
|
+
|
459
|
+
def generate_event_tags(analysis_results)
|
460
|
+
tags = ['mobile_security', 'ai_root_shield']
|
461
|
+
tags << analysis_results[:platform] if analysis_results[:platform]
|
462
|
+
tags << 'high_risk' if (analysis_results[:risk_score] || 0) > 70
|
463
|
+
tags << 'jailbroken' if analysis_results[:risk_factors]&.any? { |f| f.include?('JAILBREAK') }
|
464
|
+
tags << 'rooted' if analysis_results[:risk_factors]&.any? { |f| f.include?('ROOT') }
|
465
|
+
tags
|
466
|
+
end
|
467
|
+
|
468
|
+
def generate_alert_id
|
469
|
+
"ARS-ALERT-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{SecureRandom.hex(4).upcase}"
|
470
|
+
end
|
471
|
+
|
472
|
+
def generate_alert_title(analysis_results)
|
473
|
+
risk_score = analysis_results[:risk_score] || 0
|
474
|
+
platform = analysis_results[:platform] || 'Unknown'
|
475
|
+
|
476
|
+
"High Risk Mobile Device Detected - #{platform} (Risk Score: #{risk_score})"
|
477
|
+
end
|
478
|
+
|
479
|
+
def generate_alert_description(analysis_results)
|
480
|
+
risk_factors = analysis_results[:risk_factors] || []
|
481
|
+
platform = analysis_results[:platform] || 'unknown'
|
482
|
+
|
483
|
+
description = "AI Root Shield detected a high-risk #{platform} device with #{risk_factors.size} security issues:\n"
|
484
|
+
risk_factors.first(5).each { |factor| description += "• #{factor}\n" }
|
485
|
+
description += "Immediate security review recommended."
|
486
|
+
|
487
|
+
description
|
488
|
+
end
|
489
|
+
|
490
|
+
def generate_remediation_steps(analysis_results)
|
491
|
+
steps = []
|
492
|
+
risk_factors = analysis_results[:risk_factors] || []
|
493
|
+
|
494
|
+
risk_factors.each do |factor|
|
495
|
+
case factor
|
496
|
+
when /ROOT|JAILBREAK/
|
497
|
+
steps << "Block device access until security compliance is restored"
|
498
|
+
when /EMULATOR/
|
499
|
+
steps << "Implement additional emulator detection measures"
|
500
|
+
when /FRIDA|XPOSED/
|
501
|
+
steps << "Deploy runtime application self-protection (RASP)"
|
502
|
+
when /INTEGRITY/
|
503
|
+
steps << "Verify application signature and code integrity"
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
steps.uniq.first(5)
|
508
|
+
end
|
509
|
+
|
510
|
+
def generate_alert_tags(analysis_results)
|
511
|
+
tags = generate_event_tags(analysis_results)
|
512
|
+
tags << 'security_alert'
|
513
|
+
tags << 'requires_action'
|
514
|
+
tags
|
515
|
+
end
|
516
|
+
|
517
|
+
# Platform-specific formatting methods
|
518
|
+
def format_qradar_event(event_data)
|
519
|
+
{
|
520
|
+
events: [{
|
521
|
+
eventTime: Time.now.to_i * 1000,
|
522
|
+
eventCategory: 1003, # Security event category
|
523
|
+
severity: event_data[:severity],
|
524
|
+
sourceIP: '127.0.0.1',
|
525
|
+
destinationIP: '127.0.0.1',
|
526
|
+
eventName: 'Mobile Security Analysis',
|
527
|
+
eventDescription: event_data.to_json,
|
528
|
+
properties: event_data.transform_keys(&:to_s)
|
529
|
+
}]
|
530
|
+
}
|
531
|
+
end
|
532
|
+
|
533
|
+
def format_sentinel_event(event_data)
|
534
|
+
[{
|
535
|
+
TimeGenerated: event_data[:timestamp],
|
536
|
+
EventType: event_data[:event_type],
|
537
|
+
Severity: event_data[:severity],
|
538
|
+
RiskScore: event_data[:risk_score],
|
539
|
+
Platform: event_data[:platform],
|
540
|
+
RiskFactors: event_data[:risk_factors].join(','),
|
541
|
+
EventData: event_data.to_json
|
542
|
+
}]
|
543
|
+
end
|
544
|
+
|
545
|
+
def format_datadog_event(event_data)
|
546
|
+
{
|
547
|
+
ddsource: 'ai_root_shield',
|
548
|
+
ddtags: event_data[:tags].join(','),
|
549
|
+
hostname: Socket.gethostname,
|
550
|
+
message: event_data.to_json,
|
551
|
+
service: 'mobile_security',
|
552
|
+
timestamp: Time.now.to_i * 1000
|
553
|
+
}
|
554
|
+
end
|
555
|
+
|
556
|
+
def format_chronicle_event(event_data)
|
557
|
+
{
|
558
|
+
entries: [{
|
559
|
+
logText: event_data.to_json,
|
560
|
+
timestamp: {
|
561
|
+
seconds: Time.now.to_i
|
562
|
+
}
|
563
|
+
}]
|
564
|
+
}
|
565
|
+
end
|
566
|
+
|
567
|
+
def format_arcsight_event(event_data)
|
568
|
+
{
|
569
|
+
events: [{
|
570
|
+
name: 'Mobile Security Analysis',
|
571
|
+
deviceEventClassId: 'mobile_security_analysis',
|
572
|
+
severity: event_data[:severity],
|
573
|
+
message: event_data.to_json,
|
574
|
+
deviceProduct: 'AI Root Shield',
|
575
|
+
deviceVendor: 'Ahmet KAHRAMAN',
|
576
|
+
deviceVersion: AiRootShield::VERSION
|
577
|
+
}]
|
578
|
+
}
|
579
|
+
end
|
580
|
+
|
581
|
+
# Query builders
|
582
|
+
def build_splunk_query(query_params)
|
583
|
+
base_query = "search index=#{@index} source=ai_root_shield"
|
584
|
+
|
585
|
+
if query_params[:start_time]
|
586
|
+
base_query += " earliest=#{query_params[:start_time]}"
|
587
|
+
end
|
588
|
+
|
589
|
+
if query_params[:end_time]
|
590
|
+
base_query += " latest=#{query_params[:end_time]}"
|
591
|
+
end
|
592
|
+
|
593
|
+
if query_params[:platform]
|
594
|
+
base_query += " platform=#{query_params[:platform]}"
|
595
|
+
end
|
596
|
+
|
597
|
+
if query_params[:risk_threshold]
|
598
|
+
base_query += " risk_score>=#{query_params[:risk_threshold]}"
|
599
|
+
end
|
600
|
+
|
601
|
+
base_query
|
602
|
+
end
|
603
|
+
|
604
|
+
def build_elastic_query(query_params)
|
605
|
+
query = {
|
606
|
+
query: {
|
607
|
+
bool: {
|
608
|
+
must: []
|
609
|
+
}
|
610
|
+
}
|
611
|
+
}
|
612
|
+
|
613
|
+
if query_params[:start_time] || query_params[:end_time]
|
614
|
+
range_query = { range: { timestamp: {} } }
|
615
|
+
range_query[:range][:timestamp][:gte] = query_params[:start_time] if query_params[:start_time]
|
616
|
+
range_query[:range][:timestamp][:lte] = query_params[:end_time] if query_params[:end_time]
|
617
|
+
query[:query][:bool][:must] << range_query
|
618
|
+
end
|
619
|
+
|
620
|
+
if query_params[:platform]
|
621
|
+
query[:query][:bool][:must] << { term: { platform: query_params[:platform] } }
|
622
|
+
end
|
623
|
+
|
624
|
+
if query_params[:risk_threshold]
|
625
|
+
query[:query][:bool][:must] << { range: { risk_score: { gte: query_params[:risk_threshold] } } }
|
626
|
+
end
|
627
|
+
|
628
|
+
query
|
629
|
+
end
|
630
|
+
|
631
|
+
def build_qradar_query(query_params)
|
632
|
+
query = {}
|
633
|
+
|
634
|
+
if query_params[:start_time]
|
635
|
+
query[:startTime] = query_params[:start_time]
|
636
|
+
end
|
637
|
+
|
638
|
+
if query_params[:end_time]
|
639
|
+
query[:endTime] = query_params[:end_time]
|
640
|
+
end
|
641
|
+
|
642
|
+
query[:filter] = "eventName='Mobile Security Analysis'"
|
643
|
+
|
644
|
+
query
|
645
|
+
end
|
646
|
+
|
647
|
+
# Alert senders
|
648
|
+
def send_splunk_alert(alert_data)
|
649
|
+
# Send to Splunk as notable event
|
650
|
+
uri = URI("#{@api_endpoint}/services/notable_update")
|
651
|
+
|
652
|
+
payload = {
|
653
|
+
ruleNames: ['AI Root Shield High Risk Alert'],
|
654
|
+
status: 'new',
|
655
|
+
urgency: alert_data[:severity],
|
656
|
+
comment: alert_data[:description],
|
657
|
+
eventIds: [alert_data[:alert_id]]
|
658
|
+
}
|
659
|
+
|
660
|
+
send_http_request(uri, payload, {
|
661
|
+
'Authorization' => "Splunk #{@api_key}",
|
662
|
+
'Content-Type' => 'application/json'
|
663
|
+
})
|
664
|
+
end
|
665
|
+
|
666
|
+
def send_elastic_alert(alert_data)
|
667
|
+
# Send to Elasticsearch as alert document
|
668
|
+
uri = URI("#{@api_endpoint}/ai_root_shield_alerts/_doc/#{alert_data[:alert_id]}")
|
669
|
+
|
670
|
+
send_http_request(uri, alert_data, {
|
671
|
+
'Authorization' => "ApiKey #{@api_key}",
|
672
|
+
'Content-Type' => 'application/json'
|
673
|
+
})
|
674
|
+
end
|
675
|
+
|
676
|
+
def send_datadog_alert(alert_data)
|
677
|
+
# Send to Datadog as event
|
678
|
+
uri = URI("#{@api_endpoint}/v1/events")
|
679
|
+
|
680
|
+
payload = {
|
681
|
+
title: alert_data[:title],
|
682
|
+
text: alert_data[:description],
|
683
|
+
alert_type: alert_data[:severity],
|
684
|
+
source_type_name: 'ai_root_shield',
|
685
|
+
tags: alert_data[:tags]
|
686
|
+
}
|
687
|
+
|
688
|
+
send_http_request(uri, payload, {
|
689
|
+
'DD-API-KEY' => @api_key,
|
690
|
+
'Content-Type' => 'application/json'
|
691
|
+
})
|
692
|
+
end
|
693
|
+
end
|
694
|
+
end
|
695
|
+
end
|