tcell_agent 0.2.2 → 0.2.4
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/bin/tcell_agent +97 -32
- data/lib/tcell_agent.rb +4 -4
- data/lib/tcell_agent/agent.rb +68 -13
- data/lib/tcell_agent/agent/event_processor.rb +256 -79
- data/lib/tcell_agent/agent/fork_pipe_manager.rb +114 -0
- data/lib/tcell_agent/agent/policy_manager.rb +28 -16
- data/lib/tcell_agent/agent/policy_types.rb +3 -4
- data/lib/tcell_agent/agent/route_manager.rb +45 -0
- data/lib/tcell_agent/agent/static_agent.rb +48 -10
- data/lib/tcell_agent/api.rb +0 -2
- data/lib/tcell_agent/appsensor/path_traversal.rb +1 -1
- data/lib/tcell_agent/configuration.rb +19 -6
- data/lib/tcell_agent/instrumentation.rb +123 -0
- data/lib/tcell_agent/logger.rb +4 -1
- data/lib/tcell_agent/policies/content_security_policy.rb +44 -8
- data/lib/tcell_agent/policies/dataloss_policy.rb +122 -65
- data/lib/tcell_agent/rails.rb +19 -10
- data/{config/initializers/authlogic_auth.rb → lib/tcell_agent/rails/auth/authlogic.rb} +1 -0
- data/{config/initializers/devise_auth.rb → lib/tcell_agent/rails/auth/devise.rb} +2 -81
- data/lib/tcell_agent/rails/dlp.rb +40 -36
- data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +2 -2
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +8 -2
- data/lib/tcell_agent/rails/routes.rb +15 -19
- data/lib/tcell_agent/routes/table.rb +35 -0
- data/lib/tcell_agent/sensor_events/app_sensor.rb +22 -33
- data/lib/tcell_agent/sensor_events/discovery.rb +30 -0
- data/lib/tcell_agent/sensor_events/dlp.rb +9 -4
- data/lib/tcell_agent/sensor_events/sensor.rb +3 -0
- data/lib/tcell_agent/sensor_events/server_agent.rb +30 -6
- data/lib/tcell_agent/sensor_events/util/utils.rb +5 -1
- data/lib/tcell_agent/start_background_thread.rb +27 -22
- data/lib/tcell_agent/utils/queue_with_timeout.rb +65 -1
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/lib/tcell_agent/instrumentation_spec.rb +198 -0
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +37 -2
- data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +81 -8
- data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +3 -3
- data/spec/spec_helper.rb +16 -0
- metadata +11 -11
- data/config/initializers/init.rb +0 -8
- data/lib/tcell_agent/dataloss.rb +0 -0
- data/lib/tcell_agent/policies/add_script_tag_policy.rb +0 -47
- data/lib/tcell_agent/rails/devise.rb +0 -0
- data/spec/lib/tcell_agent/policies/add_script_tag_policy_spec.rb +0 -37
@@ -1,13 +1,5 @@
|
|
1
|
-
# See the file "LICENSE" for the full license governing this code.
|
2
|
-
|
3
|
-
require 'tcell_agent/logger'
|
4
|
-
require 'tcell_agent/configuration'
|
5
|
-
require 'tcell_agent/userinfo'
|
6
|
-
require 'tcell_agent/instrumentation'
|
7
|
-
|
8
1
|
module TCellAgent
|
9
2
|
if defined?(Devise)
|
10
|
-
|
11
3
|
if (TCellAgent.configuration.enabled && TCellAgent.configuration.instrument_for_events)
|
12
4
|
TCellAgent.logger.debug("Instrumenting Devise")
|
13
5
|
|
@@ -16,62 +8,15 @@ module TCellAgent
|
|
16
8
|
require 'tcell_agent/sensor_events/app_sensor'
|
17
9
|
require 'tcell_agent/policies/appsensor_policy'
|
18
10
|
|
19
|
-
# Devise::OmniauthCallbacksController.class_eval do
|
20
|
-
# after_filter :log_after_login
|
21
|
-
# alias_method :original_failure, :failure
|
22
|
-
|
23
|
-
# def failure
|
24
|
-
# TCellAgent::Instrumentation.safe_block("Omniauth login failed") {
|
25
|
-
# login_fraud_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LoginFraud)
|
26
|
-
# if (login_fraud_policy && login_fraud_policy.enabled && login_fraud_policy.login_failed_enabled)
|
27
|
-
# hmac_session_id = request.env["tcell.request_data"].hmac_session_id
|
28
|
-
# event = TCellAgent::SensorEvents::LoginFailure.new(request, response, nil, hmac_session_id)
|
29
|
-
# TCellAgent.send_event(event)
|
30
|
-
# end
|
31
|
-
# appsensor_policy = TCellAgent.policy(TCellAgent::PolicyTypes::AppSensor)
|
32
|
-
# if (appsensor_policy && appsensor_policy.enabled && appsensor_policy.option_enabled?("login_failure"))
|
33
|
-
# hmac_session_id = request.env["tcell.request_data"].hmac_session_id
|
34
|
-
# event = TCellAgent::SensorEvents::TCellAppSensorEvent.new(
|
35
|
-
# request.fullpath,
|
36
|
-
# TCellAgent::Policies::AppSensorPolicy::DP_LOGIN_FAILURE,
|
37
|
-
# request.remote_ip,
|
38
|
-
# nil,
|
39
|
-
# request.env["tcell.request_data"].route_id,
|
40
|
-
# data=nil,
|
41
|
-
# transaction_id=nil,
|
42
|
-
# session_id=hmac_session_id,
|
43
|
-
# user_id=nil)
|
44
|
-
# TCellAgent.send_event(event)
|
45
|
-
# end
|
46
|
-
# }
|
47
|
-
# original_failure
|
48
|
-
# end
|
49
|
-
# private
|
50
|
-
# def log_after_login
|
51
|
-
# TCellAgent::Instrumentation.safe_block("Omniauth login successful") {
|
52
|
-
# login_fraud_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LoginFraud)
|
53
|
-
# if (login_fraud_policy && login_fraud_policy.enabled && login_fraud_policy.login_success_enabled)
|
54
|
-
# omniauth = env["omniauth.auth"]
|
55
|
-
# if (omniauth)
|
56
|
-
# hmac_session_id = request.env["tcell.request_data"].hmac_session_id
|
57
|
-
# user_id = request.env["tcell.request_data"].user_id
|
58
|
-
# event = TCellAgent::SensorEvents::LoginSuccess.new(request, response, user_id, hmac_session_id)
|
59
|
-
# TCellAgent.send_event(event)
|
60
|
-
# end
|
61
|
-
# end
|
62
|
-
# }
|
63
|
-
# end
|
64
|
-
# end
|
65
|
-
|
66
11
|
Devise::SessionsController.class_eval do
|
67
|
-
after_filter :log_failed_login, :only => :new
|
68
12
|
|
13
|
+
after_filter :log_failed_login, :only => :new
|
69
14
|
alias_method :original_new, :new
|
70
15
|
def new
|
71
16
|
original_new
|
72
17
|
end
|
73
18
|
|
74
|
-
|
19
|
+
alias_method :original_create, :create
|
75
20
|
def create(&block)
|
76
21
|
results = original_create(&block)
|
77
22
|
TCellAgent::Instrumentation.safe_block("Devise login successful") {
|
@@ -137,31 +82,7 @@ module TCellAgent
|
|
137
82
|
def failed_login?
|
138
83
|
(options = env["warden.options"]) && options[:action] == "unauthenticated"
|
139
84
|
end
|
140
|
-
|
141
85
|
end
|
142
|
-
# Devise::PasswordsController.class_eval do
|
143
|
-
|
144
|
-
# after_filter :send_results
|
145
|
-
# def send_results
|
146
|
-
# puts response
|
147
|
-
# end
|
148
|
-
|
149
|
-
# def new
|
150
|
-
# #::TCellAgent::Sensors::LoginFraud.use_request(request)
|
151
|
-
# self.resource = resource_class.new
|
152
|
-
# end
|
153
|
-
|
154
|
-
# def create
|
155
|
-
# self.resource = resource_class.send_reset_password_instructions(resource_params)
|
156
|
-
# yield resource if block_given?
|
157
|
-
|
158
|
-
# if successfully_sent?(resource)
|
159
|
-
# respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name))
|
160
|
-
# else
|
161
|
-
# respond_with(resource)
|
162
|
-
# end
|
163
|
-
# end
|
164
|
-
# end
|
165
86
|
end # if instrument
|
166
87
|
end #if defined devise
|
167
88
|
end
|
@@ -51,34 +51,39 @@ require 'thread'
|
|
51
51
|
# end
|
52
52
|
# end
|
53
53
|
|
54
|
-
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
54
|
+
class ActiveRecord::Base
|
55
|
+
# after_initialize do |user|
|
56
|
+
# puts "You have initialized an object!"
|
57
|
+
# puts "ASDF"
|
58
|
+
# end
|
59
|
+
after_find do |record|
|
60
|
+
database_name = self.class.connection_config().fetch(:database,"*").split('/').last
|
61
|
+
#puts record
|
62
|
+
dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DataLoss)
|
63
|
+
if dlp_policy
|
64
|
+
request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, nil)
|
65
|
+
if request_env
|
66
|
+
tcell_context = request_env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
|
67
|
+
if tcell_context
|
68
|
+
model = record.class
|
69
|
+
column_names = model.columns.map { |col| col.name }
|
70
|
+
if (dlp_policy.database_discovery_enabled)
|
71
|
+
TCellAgent.discover_database_fields(tcell_context.route_id, database_name,"*",model.table_name, column_names)
|
72
|
+
end
|
73
|
+
model.columns.each do |col|
|
74
|
+
#puts "#{model.table_name} .. #{col.name}"
|
75
|
+
action_objs = dlp_policy.get_actions_for_table(database_name, "*", model.table_name, col.name, tcell_context.route_id)
|
76
|
+
if action_objs
|
77
|
+
action_objs.each do |action_obj|
|
78
|
+
tcell_context.add_response_db_filter(record[col.name.to_sym], action_obj, database_name, "*", model.table_name, col.name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
82
87
|
|
83
88
|
# - Request
|
84
89
|
# - Session Id event
|
@@ -158,25 +163,22 @@ module TCellAgent
|
|
158
163
|
end
|
159
164
|
|
160
165
|
module TCellAgent
|
161
|
-
class Engine < Rails::Engine
|
162
166
|
ActiveSupport.on_load(:action_controller) do
|
163
167
|
ActionController::Base.class_eval do
|
164
168
|
around_filter :global_request_logging
|
165
169
|
def global_request_logging
|
166
170
|
begin
|
167
171
|
yield
|
168
|
-
TCellAgent::Instrumentation.safe_block("
|
169
|
-
|
170
|
-
if
|
171
|
-
|
172
|
-
response.body = dlp_policy.response_body_enforce(tcell_context, response.body)
|
172
|
+
TCellAgent::Instrumentation.safe_block("Running DLP Logging Filters") {
|
173
|
+
tcell_context = request.env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
|
174
|
+
if tcell_context
|
175
|
+
response.body = tcell_context.filter_body(response.body)
|
173
176
|
end
|
174
177
|
}
|
175
178
|
end
|
176
179
|
end
|
177
180
|
end
|
178
181
|
end
|
179
|
-
end
|
180
182
|
end
|
181
183
|
|
182
184
|
class Logger
|
@@ -196,7 +198,9 @@ class Logger
|
|
196
198
|
request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, nil)
|
197
199
|
if message && dlp_policy && request_env
|
198
200
|
tcell_context = request_env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
|
199
|
-
|
201
|
+
if tcell_context
|
202
|
+
tcell_context.filter_log(message)
|
203
|
+
end
|
200
204
|
end
|
201
205
|
}
|
202
206
|
tcell_old_add(severity, message, progname)
|
@@ -49,9 +49,9 @@ module TCellAgent
|
|
49
49
|
TCellAgent::Instrumentation.safe_block("Handling JSAgent add") {
|
50
50
|
status, headers, rack_body = response
|
51
51
|
if (headers.fetch("Content-Type","").start_with?'text/html')
|
52
|
-
script_tag_policy = TCellAgent.policy(TCellAgent::PolicyTypes::
|
52
|
+
script_tag_policy = TCellAgent.policy(TCellAgent::PolicyTypes::CSP)
|
53
53
|
if (script_tag_policy &&
|
54
|
-
script_tag_policy.
|
54
|
+
script_tag_policy.js_agent_api_key)
|
55
55
|
newbody = []
|
56
56
|
rack_body.each { |str|
|
57
57
|
newbody << self.replace_in_body(script_tag_policy, str)
|
@@ -54,6 +54,7 @@ module TCellAgent
|
|
54
54
|
if content_security_policy
|
55
55
|
content_security_policy.each(
|
56
56
|
request.env["tcell.request_data"].transaction_id,
|
57
|
+
request.env["tcell.request_data"].route_id,
|
57
58
|
request.env["tcell.request_data"].hmac_session_id,
|
58
59
|
request.env["tcell.request_data"].user_id) do | header_pair |
|
59
60
|
headers[header_pair["name"]] = header_pair["value"]
|
@@ -141,7 +142,6 @@ module TCellAgent
|
|
141
142
|
event = TCellAgent::SensorEvents::TCellAppSensorEventProcessor.new
|
142
143
|
event.request_headers = request.env
|
143
144
|
event.request_content_length = (request.content_length || "0").to_i
|
144
|
-
event.request_body = request.body
|
145
145
|
event.response_content_length = (rack_response.length || "0").to_i
|
146
146
|
event.remote_addr = request.ip
|
147
147
|
event.uri = request.fullpath
|
@@ -149,6 +149,9 @@ module TCellAgent
|
|
149
149
|
event.post_params = request.POST
|
150
150
|
event.cookies = request.cookies
|
151
151
|
|
152
|
+
request_body = request.body
|
153
|
+
event.request_size = event.request_content_length
|
154
|
+
|
152
155
|
#status, headers, active_response = response
|
153
156
|
#if active_response.class != ActionDispatch::Response
|
154
157
|
# return response
|
@@ -156,13 +159,16 @@ module TCellAgent
|
|
156
159
|
|
157
160
|
event.status_code = status_code
|
158
161
|
event.response_headers = response_headers
|
159
|
-
event.response_body = response_body
|
160
162
|
|
161
163
|
event.route_id = request.env["tcell.request_data"].route_id
|
162
164
|
event.transaction_id = request.env["tcell.request_data"].transaction_id
|
163
165
|
event.session_id = request.env["tcell.request_data"].hmac_session_id
|
164
166
|
event.user_id = request.env["tcell.request_data"].user_id
|
165
167
|
|
168
|
+
#puts event.response_headers
|
169
|
+
#puts event.cookies, event.post_params, event.get_params, event.uri, event.remote_addr
|
170
|
+
#puts event.request_headers
|
171
|
+
|
166
172
|
TCellAgent.send_event(event)
|
167
173
|
end
|
168
174
|
}
|
@@ -1,29 +1,25 @@
|
|
1
1
|
|
2
2
|
module TCellAgent
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
ActiveSupport.on_load(:action_controller) do
|
4
|
+
ActionController::Base.class_eval do
|
5
|
+
around_filter :tell_around_filter_routes
|
6
|
+
def tell_around_filter_routes
|
7
|
+
begin
|
8
|
+
TCellAgent::Instrumentation.safe_block("Determining Rails Route ID") {
|
9
|
+
route = Rails.application.routes.router.recognize(request) { |route, _| route }.first
|
10
|
+
if route
|
11
|
+
route_path = route[2].path.spec
|
12
|
+
tcell_context = request.env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
|
13
|
+
tcell_context.route_id = TCellAgent::SensorEvents::Util.calculateRouteId(request.method.downcase, route_path)
|
14
|
+
end
|
15
|
+
}
|
16
|
+
yield
|
17
|
+
end
|
18
18
|
end
|
19
|
-
end
|
20
|
-
end
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
23
|
module TCellAgent
|
28
24
|
module Instrumentation
|
29
25
|
module Rails
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TCellAgent
|
2
|
+
module Routes
|
3
|
+
class FieldEndpoint
|
4
|
+
attr_accessor :discovered
|
5
|
+
def initialize
|
6
|
+
super()
|
7
|
+
@discovered = false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class RouteEndpoint
|
12
|
+
attr_accessor :database
|
13
|
+
def initialize
|
14
|
+
@database = Hash.new {|h,k| # Database
|
15
|
+
h[k] = Hash.new {|h,k| # Schema
|
16
|
+
h[k] = Hash.new {|h,k| # Table
|
17
|
+
h[k] = Hash.new {|h,k| #Field
|
18
|
+
h[k] = FieldEndpoint.new
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class RouteTable
|
28
|
+
attr_accessor :routes
|
29
|
+
def initialize
|
30
|
+
@routes = Hash.new { |h,k| h[k] = RouteEndpoint.new }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end #/module Routes
|
35
|
+
end #/module TCellAgent
|
@@ -47,10 +47,10 @@ module TCellAgent
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
class TCellAppSensorEventProcessor < TCellSensorEvent
|
50
|
-
attr_accessor :request_headers, :
|
50
|
+
attr_accessor :request_headers, :request_size, :remote_addr,
|
51
51
|
:uri, :get_params, :post_params, :cookies,
|
52
52
|
:request_content_length, :request_content_type
|
53
|
-
attr_accessor :status_code, :response_headers,
|
53
|
+
attr_accessor :status_code, :response_headers,
|
54
54
|
:response_content_length,
|
55
55
|
:route_id, :transaction_id, :session_id, :user_id
|
56
56
|
def initialize
|
@@ -74,33 +74,28 @@ module TCellAgent
|
|
74
74
|
TCellAgent.send_event(event)
|
75
75
|
}
|
76
76
|
end
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
77
|
+
def loop_params_hash(method, param_hash, prefix, &block)
|
78
|
+
param_hash.each do |param_name, param_value|
|
79
|
+
if param_value && param_value.is_a?(Hash)
|
80
|
+
loop_params_hash(method, param_value, 'hash', &block)
|
81
|
+
elsif !param_value || !param_value.instance_of?(String) || param_value == ""
|
82
|
+
next
|
83
|
+
else
|
84
|
+
block.call(method, param_name, param_value)
|
84
85
|
end
|
85
86
|
end
|
87
|
+
end
|
88
|
+
def for_params(&block)
|
89
|
+
if @get_params
|
90
|
+
self.loop_params_hash('get', @get_params, nil, &block)
|
91
|
+
end
|
86
92
|
if @post_params
|
87
|
-
@post_params
|
88
|
-
if !param_value || !param_value.instance_of?(String) || param_value == ""
|
89
|
-
next
|
90
|
-
end
|
91
|
-
yield('post', param_name, param_value)
|
92
|
-
end
|
93
|
+
self.loop_params_hash('post', @post_params, nil, &block)
|
93
94
|
end
|
94
95
|
end
|
95
|
-
|
96
|
-
def for_get_params
|
96
|
+
def for_get_params(&block)
|
97
97
|
if @get_params
|
98
|
-
@get_params
|
99
|
-
if !param_value || !param_value.instance_of?(String) || param_value == ""
|
100
|
-
next
|
101
|
-
end
|
102
|
-
yield('get', param_name, param_value)
|
103
|
-
end
|
98
|
+
self.loop_params_hash('get', @get_params, nil, &block)
|
104
99
|
end
|
105
100
|
end
|
106
101
|
|
@@ -108,14 +103,7 @@ module TCellAgent
|
|
108
103
|
if (@response_content_length && @response_content_length > TCellAgent::Policies::AppSensorPolicy::MAX_NORMAL_RESPONSE_BYTES)
|
109
104
|
appsensor_event(TCellAgent::Policies::AppSensorPolicy::DP_UNUSUAL_RESPONSE_SIZE, response_content_length.to_s, nil)
|
110
105
|
end
|
111
|
-
request_size = 0
|
112
|
-
if @request_body
|
113
|
-
if @request_body.kind_of?(StringIO)
|
114
|
-
request_size = @request_body.size
|
115
|
-
else
|
116
|
-
request_size = @request_content_length
|
117
|
-
end
|
118
|
-
end
|
106
|
+
request_size = @request_size || 0
|
119
107
|
if (request_size > TCellAgent::Policies::AppSensorPolicy::MAX_NORMAL_REQUEST_BYTES)
|
120
108
|
appsensor_event(TCellAgent::Policies::AppSensorPolicy::DP_UNUSUAL_REQUEST_SIZE,request_size.to_s, nil)
|
121
109
|
end
|
@@ -167,6 +155,8 @@ module TCellAgent
|
|
167
155
|
}
|
168
156
|
end
|
169
157
|
|
158
|
+
|
159
|
+
|
170
160
|
if (!@sensor_triggered && appsensor_policy.option_enabled?("xss"))
|
171
161
|
TCellAgent::Instrumentation.safe_block("AppSensor Testing for XSS") {
|
172
162
|
for_params { | param_type, param_name, param_value |
|
@@ -177,8 +167,7 @@ module TCellAgent
|
|
177
167
|
}
|
178
168
|
}
|
179
169
|
end
|
180
|
-
|
181
|
-
if (!@sensor_triggered && appsensor_policy.option_enabled?("cmdi"))
|
170
|
+
if (!@sensor_triggered && appsensor_policy.option_enabled?("cmdi"))
|
182
171
|
TCellAgent::Instrumentation.safe_block("AppSensor Testing for CMDI") {
|
183
172
|
for_params { | param_type, param_name, param_value |
|
184
173
|
if (TCellAgent::AppSensor.isCmdi(param_value))
|