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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tcell_agent +97 -32
  3. data/lib/tcell_agent.rb +4 -4
  4. data/lib/tcell_agent/agent.rb +68 -13
  5. data/lib/tcell_agent/agent/event_processor.rb +256 -79
  6. data/lib/tcell_agent/agent/fork_pipe_manager.rb +114 -0
  7. data/lib/tcell_agent/agent/policy_manager.rb +28 -16
  8. data/lib/tcell_agent/agent/policy_types.rb +3 -4
  9. data/lib/tcell_agent/agent/route_manager.rb +45 -0
  10. data/lib/tcell_agent/agent/static_agent.rb +48 -10
  11. data/lib/tcell_agent/api.rb +0 -2
  12. data/lib/tcell_agent/appsensor/path_traversal.rb +1 -1
  13. data/lib/tcell_agent/configuration.rb +19 -6
  14. data/lib/tcell_agent/instrumentation.rb +123 -0
  15. data/lib/tcell_agent/logger.rb +4 -1
  16. data/lib/tcell_agent/policies/content_security_policy.rb +44 -8
  17. data/lib/tcell_agent/policies/dataloss_policy.rb +122 -65
  18. data/lib/tcell_agent/rails.rb +19 -10
  19. data/{config/initializers/authlogic_auth.rb → lib/tcell_agent/rails/auth/authlogic.rb} +1 -0
  20. data/{config/initializers/devise_auth.rb → lib/tcell_agent/rails/auth/devise.rb} +2 -81
  21. data/lib/tcell_agent/rails/dlp.rb +40 -36
  22. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +2 -2
  23. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +8 -2
  24. data/lib/tcell_agent/rails/routes.rb +15 -19
  25. data/lib/tcell_agent/routes/table.rb +35 -0
  26. data/lib/tcell_agent/sensor_events/app_sensor.rb +22 -33
  27. data/lib/tcell_agent/sensor_events/discovery.rb +30 -0
  28. data/lib/tcell_agent/sensor_events/dlp.rb +9 -4
  29. data/lib/tcell_agent/sensor_events/sensor.rb +3 -0
  30. data/lib/tcell_agent/sensor_events/server_agent.rb +30 -6
  31. data/lib/tcell_agent/sensor_events/util/utils.rb +5 -1
  32. data/lib/tcell_agent/start_background_thread.rb +27 -22
  33. data/lib/tcell_agent/utils/queue_with_timeout.rb +65 -1
  34. data/lib/tcell_agent/version.rb +1 -1
  35. data/spec/lib/tcell_agent/instrumentation_spec.rb +198 -0
  36. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +37 -2
  37. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +81 -8
  38. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +3 -3
  39. data/spec/spec_helper.rb +16 -0
  40. metadata +11 -11
  41. data/config/initializers/init.rb +0 -8
  42. data/lib/tcell_agent/dataloss.rb +0 -0
  43. data/lib/tcell_agent/policies/add_script_tag_policy.rb +0 -47
  44. data/lib/tcell_agent/rails/devise.rb +0 -0
  45. 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
- alias_method :original_create, :create
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
- # class ActiveRecord::Base
55
- # after_initialize do |user|
56
- # puts "You have initialized an object!"
57
- # puts user
58
- # end
59
-
60
- # after_find do |record|
61
- # dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DataLoss)
62
- # if dlp_policy
63
- # request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(Thread.current.object_id, nil)
64
- # if request_env
65
- # model = record.class
66
- # model.columns.each do |col|
67
- # #puts "#{model.table_name} .. #{col.name}"
68
- # actions = dlp_policy.get_actions_for(model.table_name, col.name)
69
- # if (actions.include?("body_redact"))
70
- # (request_env["filter_body_set"] ||= Set.new).add(record[col.name.to_sym])
71
- # #request_env["filter_body_set"].add()
72
- # end
73
- # if (actions.include?("log_redact"))
74
- # (request_env["filter_log_set"] ||= Set.new).add(record[col.name.to_sym])
75
- # #request_env["filter_log_set"].add(record[col.name.to_sym])
76
- # end
77
- # end
78
- # end
79
- # end
80
- # end
81
- # end
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("Handling JSAgent add") {
169
- dlp_policy = TCellAgent.policy(TCellAgent::PolicyTypes::DataLoss)
170
- if dlp_policy
171
- tcell_context = request.env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
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
- dlp_policy.log_enforce(tcell_context, message)
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::AddScriptTag)
52
+ script_tag_policy = TCellAgent.policy(TCellAgent::PolicyTypes::CSP)
53
53
  if (script_tag_policy &&
54
- script_tag_policy.enabled)
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
- class Engine < Rails::Engine
4
- ActiveSupport.on_load(:action_controller) do
5
- ActionController::Base.class_eval do
6
- around_filter :tell_around_filter_routes
7
- def tell_around_filter_routes
8
- begin
9
- TCellAgent::Instrumentation.safe_block("Determining Rails Route ID") {
10
- route = Rails.application.routes.router.recognize(request) { |route, _| route }.first
11
- if route
12
- route_path = route[2].path.spec
13
- tcell_context = request.env[TCellAgent::Instrumentation::Rails::Middleware::TCELL_ID]
14
- tcell_context.route_id = TCellAgent::SensorEvents::Util.calculateRouteId(request.method.downcase, route_path)
15
- end
16
- }
17
- yield
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, :request_body, :remote_addr,
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, :response_body,
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 for_params
78
- if @get_params
79
- @get_params.each do |param_name, param_value|
80
- if !param_value || !param_value.instance_of?(String) || param_value == ""
81
- next
82
- end
83
- yield('get', param_name, param_value)
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.each do |param_name, param_value|
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.each do |param_name, param_value|
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))