tcell_agent 0.2.21 → 0.2.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tcell_agent.rb +1 -0
  3. data/lib/tcell_agent/api.rb +3 -2
  4. data/lib/tcell_agent/appsensor/injections_matcher.rb +137 -0
  5. data/lib/tcell_agent/appsensor/injections_reporter.rb +67 -0
  6. data/lib/tcell_agent/appsensor/meta_data.rb +71 -0
  7. data/lib/tcell_agent/appsensor/rules/appsensor_rule_manager.rb +5 -2
  8. data/lib/tcell_agent/appsensor/rules/appsensor_rule_set.rb +1 -1
  9. data/lib/tcell_agent/appsensor/sensor.rb +48 -0
  10. data/lib/tcell_agent/configuration.rb +15 -2
  11. data/lib/tcell_agent/instrumentation.rb +3 -2
  12. data/lib/tcell_agent/logger.rb +19 -3
  13. data/lib/tcell_agent/patches.rb +26 -0
  14. data/lib/tcell_agent/patches/block_rule.rb +58 -0
  15. data/lib/tcell_agent/patches/meta_data.rb +54 -0
  16. data/lib/tcell_agent/patches/sensors_matcher.rb +30 -0
  17. data/lib/tcell_agent/policies/appsensor/cmdi_sensor.rb +4 -0
  18. data/lib/tcell_agent/policies/appsensor/database_sensor.rb +7 -3
  19. data/lib/tcell_agent/policies/appsensor/fpt_sensor.rb +4 -0
  20. data/lib/tcell_agent/policies/appsensor/injection_sensor.rb +32 -38
  21. data/lib/tcell_agent/policies/appsensor/misc_sensor.rb +4 -4
  22. data/lib/tcell_agent/policies/appsensor/nullbyte_sensor.rb +4 -0
  23. data/lib/tcell_agent/policies/appsensor/payloads_policy.rb +3 -1
  24. data/lib/tcell_agent/policies/appsensor/response_codes_sensor.rb +3 -3
  25. data/lib/tcell_agent/policies/appsensor/retr_sensor.rb +4 -0
  26. data/lib/tcell_agent/policies/appsensor/size_sensor.rb +9 -3
  27. data/lib/tcell_agent/policies/appsensor/user_agent_sensor.rb +3 -3
  28. data/lib/tcell_agent/policies/appsensor_policy.rb +55 -131
  29. data/lib/tcell_agent/policies/content_security_policy.rb +148 -137
  30. data/lib/tcell_agent/policies/patches_policy.rb +41 -13
  31. data/lib/tcell_agent/rails.rb +11 -109
  32. data/lib/tcell_agent/rails/auth/devise.rb +5 -1
  33. data/lib/tcell_agent/rails/dlp.rb +5 -2
  34. data/lib/tcell_agent/rails/dlp/process_request.rb +88 -0
  35. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +1 -1
  36. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +3 -13
  37. data/lib/tcell_agent/rails/on_start.rb +5 -101
  38. data/lib/tcell_agent/rails/routes.rb +240 -81
  39. data/lib/tcell_agent/rails/routes/grape.rb +113 -0
  40. data/lib/tcell_agent/rails/routes/route_id.rb +29 -0
  41. data/lib/tcell_agent/sensor_events/app_config.rb +21 -13
  42. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +7 -26
  43. data/lib/tcell_agent/servers/passenger.rb +10 -0
  44. data/lib/tcell_agent/start_background_thread.rb +82 -0
  45. data/lib/tcell_agent/utils/params.rb +1 -1
  46. data/lib/tcell_agent/version.rb +1 -1
  47. data/spec/lib/tcell_agent/appsensor/injections_matcher_spec.rb +504 -0
  48. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +222 -0
  49. data/spec/lib/tcell_agent/appsensor/rules/appsensor_rule_manager_spec.rb +7 -13
  50. data/spec/lib/tcell_agent/appsensor/rules/appsensor_rule_set_spec.rb +18 -18
  51. data/spec/lib/tcell_agent/patches/block_rule_spec.rb +381 -0
  52. data/spec/lib/tcell_agent/patches/sensors_matcher_spec.rb +35 -0
  53. data/spec/lib/tcell_agent/patches_spec.rb +156 -0
  54. data/spec/lib/tcell_agent/policies/appsensor/cmdi_sensor_spec.rb +21 -10
  55. data/spec/lib/tcell_agent/policies/appsensor/fpt_sensor_spec.rb +20 -9
  56. data/spec/lib/tcell_agent/policies/appsensor/nullbyte_sensor_spec.rb +44 -9
  57. data/spec/lib/tcell_agent/policies/appsensor/request_size_sensor_spec.rb +4 -4
  58. data/spec/lib/tcell_agent/policies/appsensor/response_codes_sensor_spec.rb +13 -13
  59. data/spec/lib/tcell_agent/policies/appsensor/response_size_sensor_spec.rb +5 -5
  60. data/spec/lib/tcell_agent/policies/appsensor/retr_sensor_spec.rb +20 -9
  61. data/spec/lib/tcell_agent/policies/appsensor/sqli_sensor_spec.rb +24 -14
  62. data/spec/lib/tcell_agent/policies/appsensor/xss_sensor_spec.rb +243 -241
  63. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +128 -200
  64. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +126 -55
  65. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +485 -24
  66. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +5 -0
  67. data/spec/lib/tcell_agent/rails/middleware/dlp_middleware_spec.rb +4 -2
  68. data/spec/lib/tcell_agent/rails/routes/grape_spec.rb +294 -0
  69. data/spec/lib/tcell_agent/rails/routes/route_id_spec.rb +80 -0
  70. data/spec/lib/tcell_agent/rails/routes/routes_spec.rb +182 -0
  71. metadata +30 -7
  72. data/lib/tcell_agent/policies/appsensor/login_sensor.rb +0 -39
  73. data/lib/tcell_agent/policies/appsensor/sensor.rb +0 -46
  74. data/lib/tcell_agent/rails/path_parameters_setter.rb +0 -43
  75. data/spec/lib/tcell_agent/policies/appsensor/login_sensor_spec.rb +0 -104
@@ -16,6 +16,10 @@ module TCellAgent
16
16
  @rule_manager.get_ruleset_for("nullbyte")
17
17
  end
18
18
 
19
+ def applicable_for_param_type?(param_type)
20
+ InjectionSensor::COOKIE_PARAM != param_type
21
+ end
22
+
19
23
  end
20
24
 
21
25
  end
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  require 'tcell_agent/utils/params'
2
4
 
3
5
  module TCellAgent
@@ -91,7 +93,7 @@ module TCellAgent
91
93
  pattern
92
94
  )
93
95
  event.post_process
94
- TCellAgent.appfirewall_payloads_logger.info(event.to_json)
96
+ TCellAgent.appfirewall_payloads_logger.info(JSON.dump(event))
95
97
  end
96
98
  end
97
99
  end
@@ -1,10 +1,10 @@
1
- require 'tcell_agent/policies/appsensor/sensor'
1
+ require 'tcell_agent/appsensor/sensor'
2
2
 
3
3
 
4
4
  module TCellAgent
5
5
  module Policies
6
6
 
7
- class ResponseCodesSensor < Sensor
7
+ class ResponseCodesSensor
8
8
 
9
9
  RESPONSE_CODE_DP_DICT = {
10
10
  401 => "s401",
@@ -53,7 +53,7 @@ module TCellAgent
53
53
  if dp
54
54
  param = payload = pattern = nil
55
55
  meta = { code: response_code }
56
- send_event(appsensor_meta, dp, param, meta, payload, pattern)
56
+ TCellAgent::AppSensor::Sensor.send_event(appsensor_meta, dp, param, meta, payload, pattern)
57
57
  end
58
58
 
59
59
  def to_s
@@ -12,6 +12,10 @@ module TCellAgent
12
12
  )
13
13
  end
14
14
 
15
+ def applicable_for_param_type?(param_type)
16
+ InjectionSensor::POST_PARAM != param_type && InjectionSensor::JSON_PARAM != param_type
17
+ end
18
+
15
19
  end
16
20
 
17
21
  end
@@ -1,9 +1,9 @@
1
- require 'tcell_agent/policies/appsensor/sensor'
1
+ require 'tcell_agent/appsensor/sensor'
2
2
 
3
3
  module TCellAgent
4
4
  module Policies
5
5
 
6
- class SizeSensor < Sensor
6
+ class SizeSensor
7
7
 
8
8
  attr_accessor :enabled, :limit, :excluded_route_ids, :dp_code
9
9
 
@@ -31,7 +31,13 @@ module TCellAgent
31
31
  if content_length && content_length > @limit
32
32
  param = payload = pattern = nil
33
33
  meta = { "sz" => content_length }
34
- send_event(appsensor_meta, @dp_code, param, meta, payload, pattern)
34
+ TCellAgent::AppSensor::Sensor.send_event(
35
+ appsensor_meta,
36
+ @dp_code,
37
+ param,
38
+ meta,
39
+ payload,
40
+ pattern)
35
41
  end
36
42
  end
37
43
 
@@ -1,9 +1,9 @@
1
- require 'tcell_agent/policies/appsensor/sensor'
1
+ require 'tcell_agent/appsensor/sensor'
2
2
 
3
3
  module TCellAgent
4
4
  module Policies
5
5
 
6
- class UserAgentSensor < Sensor
6
+ class UserAgentSensor
7
7
  DP_CODE = "uaempty"
8
8
 
9
9
  attr_accessor :enabled, :empty_enabled, :excluded_route_ids
@@ -30,7 +30,7 @@ module TCellAgent
30
30
 
31
31
  user_agent = appsensor_meta.user_agent
32
32
  if !user_agent || user_agent.strip == ""
33
- send_event(appsensor_meta, DP_CODE, nil, nil, nil, nil)
33
+ TCellAgent::AppSensor::Sensor.send_event(appsensor_meta, DP_CODE, nil, nil, nil, nil)
34
34
  end
35
35
  end
36
36
 
@@ -1,8 +1,8 @@
1
1
  require 'tcell_agent/instrumentation'
2
+ require 'tcell_agent/appsensor/injections_reporter'
2
3
  require 'tcell_agent/policies/appsensor/cmdi_sensor'
3
4
  require 'tcell_agent/policies/appsensor/database_sensor'
4
5
  require 'tcell_agent/policies/appsensor/fpt_sensor'
5
- require 'tcell_agent/policies/appsensor/login_sensor'
6
6
  require 'tcell_agent/policies/appsensor/misc_sensor'
7
7
  require 'tcell_agent/policies/appsensor/nullbyte_sensor'
8
8
  require 'tcell_agent/policies/appsensor/payloads_policy'
@@ -20,17 +20,9 @@ module TCellAgent
20
20
  module Policies
21
21
 
22
22
  class AppSensorPolicy
23
-
24
23
  DETECTION_POINTS_V1 = [
25
24
  "req_res_size",
26
25
  "resp_codes",
27
- "xss",
28
- "sqli",
29
- "cmdi",
30
- "fpt",
31
- "null",
32
- "retr",
33
- "login_failure",
34
26
  "ua",
35
27
  "errors",
36
28
  "database"]
@@ -45,19 +37,28 @@ module TCellAgent
45
37
  "fpt" => FptSensor,
46
38
  "nullbyte" => NullbyteSensor,
47
39
  "retr" => RetrSensor,
48
- "login" => LoginSensor,
49
40
  "ua" => UserAgentSensor,
50
41
  "errors" => MiscSensor,
51
42
  "database" => DatabaseSensor
52
43
  }
53
44
 
54
- attr_accessor :policy_id, :options, :payloads_policy, :enabled
45
+ DETECTION_POINTS_V2_NON_INJECTION = {
46
+ "req_size" => RequestSizeSensor,
47
+ "resp_size" => ResponseSizeSensor,
48
+ "resp_codes" => ResponseCodesSensor,
49
+ "ua" => UserAgentSensor,
50
+ "errors" => MiscSensor,
51
+ "database" => DatabaseSensor
52
+ }
53
+
54
+ attr_accessor :policy_id, :options, :enabled, :injections_reporter
55
55
 
56
56
  def initialize
57
57
  @policy_id = nil
58
58
  @options = Hash.new
59
59
  @enabled = false
60
- @payloads_policy = PayloadsPolicy.new
60
+ @injections_reporter =
61
+ TCellAgent::AppSensor::InjectionsReporter.from_json(0, {}, PayloadsPolicy.new)
61
62
  end
62
63
 
63
64
  def process_meta_event(appsensor_meta)
@@ -67,7 +68,8 @@ module TCellAgent
67
68
  check_request_size(appsensor_meta)
68
69
  check_response_size(appsensor_meta)
69
70
  check_response_code(appsensor_meta)
70
- check_params_for_injections(appsensor_meta)
71
+
72
+ @injections_reporter.check(appsensor_meta)
71
73
  end
72
74
 
73
75
  def process_db_rows(tcell_data, number_of_records)
@@ -112,62 +114,6 @@ module TCellAgent
112
114
  end
113
115
  end
114
116
 
115
- def check_param_for_injections(param_type, appsensor_meta, param_name, param_value)
116
- return if @options["xss"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
117
- return if @options["sqli"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
118
- if InjectionSensor::COOKIE_PARAM != param_type
119
- return if @options["cmdi"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
120
- end
121
- if InjectionSensor::COOKIE_PARAM != param_type
122
- return if @options["fpt"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
123
- end
124
- if InjectionSensor::COOKIE_PARAM != param_type
125
- return if @options["nullbyte"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
126
- end
127
- if InjectionSensor::POST_PARAM != param_type && InjectionSensor::JSON_PARAM != param_type
128
- return if @options["retr"].check(param_type, appsensor_meta, param_name, param_value, @payloads_policy)
129
- end
130
- end
131
-
132
- def check_params_for_injections(appsensor_meta)
133
-
134
- TCellAgent::Utils::Params.flatten(appsensor_meta.path_parameters || {}).each do |param_name, param_value|
135
- TCellAgent::Instrumentation.safe_block("AppSensor Check Path Params injections") do
136
- param_name = param_name[-1]
137
- next if param_name == :controller || param_name == :action
138
- check_param_for_injections(InjectionSensor::URI_PARAM, appsensor_meta, param_name.to_s, param_value)
139
- end
140
- end
141
-
142
- TCellAgent::Utils::Params.flatten(appsensor_meta.get_dict || {}).each do |param_name, param_value|
143
- TCellAgent::Instrumentation.safe_block("AppSensor Check GET var injections") do
144
- param_name = param_name[-1]
145
- check_param_for_injections(InjectionSensor::GET_PARAM, appsensor_meta, param_name, param_value)
146
- end
147
- end
148
-
149
- (appsensor_meta.post_dict || {}).each do |param_name, param_value|
150
- TCellAgent::Instrumentation.safe_block("AppSensor Check POST var injections") do
151
- param_name = param_name[-1]
152
- check_param_for_injections(InjectionSensor::POST_PARAM, appsensor_meta, param_name, param_value)
153
- end
154
- end
155
-
156
- (appsensor_meta.body_dict || {}).each do |param_name, param_value|
157
- TCellAgent::Instrumentation.safe_block("AppSensor Check JSON var injections") do
158
- param_name = param_name[-1]
159
- check_param_for_injections(InjectionSensor::JSON_PARAM, appsensor_meta, param_name, param_value)
160
- end
161
- end
162
-
163
- TCellAgent::Utils::Params.flatten(appsensor_meta.cookie_dict || {}).each do |param_name, param_value|
164
- TCellAgent::Instrumentation.safe_block("AppSensor Check COOKIE var injections") do
165
- param_name = param_name[-1]
166
- check_param_for_injections(InjectionSensor::COOKIE_PARAM, appsensor_meta, param_name, param_value)
167
- end
168
- end
169
- end
170
-
171
117
  def csrf_rejected(tcell_data, exception_class)
172
118
  TCellAgent::Instrumentation.safe_block("AppSensor CSRF Exception processing") do
173
119
  if self.options.has_key?("errors")
@@ -198,9 +144,6 @@ module TCellAgent
198
144
  if policy_json.has_key?("data")
199
145
  data_json = policy_json["data"]
200
146
 
201
- rule_manager = AppSensorRuleManager.new
202
- rule_manager.load_default_rules_file()
203
-
204
147
  if policy_json["version"] && policy_json["version"] == 2
205
148
  if data_json
206
149
  sensors_json = data_json.fetch("sensors", {})
@@ -209,16 +152,21 @@ module TCellAgent
209
152
 
210
153
  else
211
154
  sensor_policy.enabled = true
212
- sensor_policy.payloads_policy = PayloadsPolicy.from_json(
213
- data_json.fetch("options", {})
214
- )
215
155
 
216
- DETECTION_POINTS_V2.each do |sensor_name, sensor_class|
156
+ DETECTION_POINTS_V2_NON_INJECTION.each do |sensor_name, sensor_class|
217
157
  settings = sensors_json.fetch(sensor_name, {})
218
- settings["enabled"] = sensors_json.has_key?(sensor_name)
219
- settings["rule_manager"] = rule_manager
220
- sensor_policy.options[sensor_name] = sensor_class.new(settings)
158
+ updated_settings = {
159
+ "enabled" => sensors_json.has_key?(sensor_name)
160
+ }.merge(settings)
161
+
162
+ sensor_policy.options[sensor_name] = sensor_class.new(updated_settings)
221
163
  end
164
+
165
+ payloads_policy = PayloadsPolicy.from_json(
166
+ data_json.fetch("options", {})
167
+ )
168
+ sensor_policy.injections_reporter =
169
+ TCellAgent::AppSensor::InjectionsReporter.from_json(2, sensors_json, payloads_policy)
222
170
  end
223
171
  end
224
172
 
@@ -231,64 +179,40 @@ module TCellAgent
231
179
 
232
180
  else
233
181
  sensor_policy.enabled = true
234
- sensor_policy.payloads_policy = PayloadsPolicy.from_json({
182
+
183
+ payloads_policy = PayloadsPolicy.from_json({
235
184
  "payloads" => {
236
185
  "send_payloads" => true,
237
186
  "log_payloads" => true
238
187
  }
239
188
  })
240
189
 
241
- DETECTION_POINTS_V1.each do |sensor_name|
242
- if "req_res_size" == sensor_name
243
- enabled = options_json.fetch(sensor_name, false)
244
- sensor_policy.options["req_size"] = RequestSizeSensor.new({"enabled" => enabled})
245
- sensor_policy.options["resp_size"] = ResponseSizeSensor.new({"enabled" => enabled})
246
-
247
- elsif "resp_codes" == sensor_name
248
- enabled = options_json.fetch(sensor_name, false)
249
- sensor_policy.options[sensor_name] = ResponseCodesSensor.new({
250
- "enabled" => enabled,
251
- "series_400_enabled" => true,
252
- "series_500_enabled" => true})
253
-
254
- elsif "null" == sensor_name
255
- enabled = options_json.fetch(sensor_name, false)
256
- sensor_policy.options["nullbyte"] = NullbyteSensor.new(
257
- {
258
- "enabled" => enabled,
259
- "v1_compatability_enabled" => true,
260
- "rule_manager" => rule_manager
261
- }
262
- )
263
-
264
- elsif "login_failure" == sensor_name
265
- enabled = options_json.fetch(sensor_name, false)
266
- sensor_policy.options["login"] = LoginSensor.new({"enabled" => enabled})
267
-
268
- elsif "ua" == sensor_name
269
- sensor_policy.options[sensor_name] = UserAgentSensor.new({
270
- "enabled" => false, "empty_enabled" => false
271
- })
272
-
273
- elsif "errors" == sensor_name
274
- sensor_policy.options[sensor_name] = MiscSensor.new({
275
- "enabled" => false,
276
- "csrf_exception_enabled" => false,
277
- "sql_exception_enabled" => false
278
- })
279
-
280
- else
281
- enabled = options_json.fetch(sensor_name, false)
282
- clazz = DETECTION_POINTS_V2[sensor_name]
283
- sensor_policy.options[sensor_name] = clazz.new(
284
- {
285
- "enabled" => enabled,
286
- "v1_compatability_enabled" => true,
287
- "rule_manager" => rule_manager
288
- }
289
- )
290
- end
291
- end
190
+ sensor_policy.injections_reporter =
191
+ TCellAgent::AppSensor::InjectionsReporter.from_json(1, data_json, payloads_policy)
192
+
193
+ enabled = options_json.fetch("req_res_size", false)
194
+ sensor_policy.options["req_size"] = RequestSizeSensor.new({"enabled" => enabled})
195
+ sensor_policy.options["resp_size"] = ResponseSizeSensor.new({"enabled" => enabled})
196
+
197
+ enabled = options_json.fetch("resp_codes", false)
198
+ sensor_policy.options["resp_codes"] = ResponseCodesSensor.new({
199
+ "enabled" => enabled,
200
+ "series_400_enabled" => true,
201
+ "series_500_enabled" => true})
202
+
203
+ sensor_policy.options["ua"] = UserAgentSensor.new({
204
+ "enabled" => false, "empty_enabled" => false
205
+ })
206
+
207
+ sensor_policy.options["errors"] = MiscSensor.new({
208
+ "enabled" => false,
209
+ "csrf_exception_enabled" => false,
210
+ "sql_exception_enabled" => false
211
+ })
212
+
213
+ sensor_policy.options["database"] = DatabaseSensor.new({
214
+ "enabled" => false
215
+ })
292
216
  end
293
217
  end
294
218
  end
@@ -6,150 +6,161 @@ require 'tcell_agent/sensor_events/util/sanitizer_utilities'
6
6
  require 'tcell_agent/configuration'
7
7
 
8
8
  module TCellAgent
9
- module Policies
10
- class ContentSecurityPolicy
11
- class ContentSecurityPolicyHeader
12
- @@approved_headers = [
13
- "csp",
14
- "csp-report"
15
- ]
16
- attr_accessor :type
17
- attr_accessor :raw_value
18
- attr_accessor :report_uri
19
- attr_accessor :policy_id
20
- def initialize(type, value, report_uri=nil, policy_id=nil)
21
- if !(type && value)
22
- raise "Type and value were not set"
23
- end
24
- if type.downcase == "content-security-policy"
25
- type = "csp"
26
- elsif type.downcase == "content-security-policy-report-only"
27
- type = "csp-report"
28
- end
29
- if not @@approved_headers.include?(type.downcase)
30
- raise "Type was not included in approved_headers"
31
- end
32
- if value != value.gsub(/[^\p{L}\w\d\-_\ :\/,;.'\*"%?@#=$]/,'')
33
- raise "Value is not valid"
34
- end
35
- if policy_id
36
- self.policy_id = policy_id
37
- end
38
- self.type = type
39
- self.raw_value = value
40
- self.report_uri = report_uri
41
- end
42
- def self.jhash(str)
43
- str.each_char.reduce(0) do |result, char|
44
- [((result << 5) - result) + char.ord].pack('L').unpack('l').first
45
- end
46
- end
47
- def value(transaction_id=nil, route_id=nil, session_id=nil, user_id=nil)
48
- if !self.report_uri
49
- return self.raw_value
50
- end
51
- begin
52
- uri = URI.parse(self.report_uri)
53
- new_query_ar = URI.decode_www_form(uri.query || '')
54
- if transaction_id
55
- new_query_ar << ["tid", transaction_id]
56
- end
57
- if session_id and session_id.length > 0
58
- new_query_ar << ["sid", session_id]
59
- end
60
- if route_id
61
- new_query_ar << ["rid", route_id]
62
- end
63
- if new_query_ar != []
64
- uri.query = URI.encode_www_form(new_query_ar)
65
- end
66
- report_uri = uri.to_s
67
- if self.policy_id
68
- checksum = ContentSecurityPolicyHeader.jhash(self.policy_id + report_uri)
69
- if new_query_ar != []
70
- report_uri = report_uri + "&"
71
- else
72
- report_uri = report_uri + "?"
73
- end
74
- report_uri = report_uri + "c=" + checksum.to_s
75
- end
76
- return "#{self.raw_value}; report-uri #{report_uri}"
77
- rescue Exception=>e
78
- return self.raw_value
79
- end
80
- end
81
- end
9
+ module Policies
82
10
 
83
- attr_accessor :headers
84
- attr_accessor :policy_id
85
- attr_accessor :js_agent_api_key
86
-
87
- def each(transaction_id=nil, route_id=nil, hmac_session_id=nil, user_id=nil, &block)
88
- result = []
89
- headers.each do | header |
90
- header_value = header.value(transaction_id, route_id, hmac_session_id)
91
- header_names = ContentSecurityPolicy.cspHeadersForType(header.type)
92
- header_names.each do | header_name |
93
- result.push( {"name"=>header_name, "value"=>header_value} )
94
- end #doloop
95
- end
96
- result.each(&block)
11
+ class ContentSecurityPolicy
12
+ class ContentSecurityPolicyHeader
13
+ @@approved_headers = [
14
+ "csp",
15
+ "csp-report"
16
+ ]
17
+ attr_accessor :type
18
+ attr_accessor :raw_value
19
+ attr_accessor :report_uri
20
+ attr_accessor :policy_id
21
+ def initialize(type, value, report_uri=nil, policy_id=nil)
22
+ if !(type && value)
23
+ raise "Type and value were not set"
24
+ end
25
+ if type.downcase == "content-security-policy"
26
+ type = "csp"
27
+ elsif type.downcase == "content-security-policy-report-only"
28
+ type = "csp-report"
29
+ end
30
+ if not @@approved_headers.include?(type.downcase)
31
+ raise "Type was not included in approved_headers"
32
+ end
33
+ if value != value.gsub(/[^\p{L}\w\d\-_\ :\/,;.'\*"%?@#=$]/,'')
34
+ raise "Value is not valid"
35
+ end
36
+ if policy_id
37
+ self.policy_id = policy_id
38
+ end
39
+ self.type = type
40
+ self.raw_value = value
41
+ self.report_uri = report_uri
42
+ end
43
+ def self.jhash(str)
44
+ str.each_char.reduce(0) do |result, char|
45
+ [((result << 5) - result) + char.ord].pack('L').unpack('l').first
46
+ end
47
+ end
48
+ def value(transaction_id=nil, route_id=nil, session_id=nil, user_id=nil)
49
+ if !self.report_uri
50
+ return self.raw_value
51
+ end
52
+ begin
53
+ uri = URI.parse(self.report_uri)
54
+ new_query_ar = URI.decode_www_form(uri.query || '')
55
+ if transaction_id
56
+ new_query_ar << ["tid", transaction_id]
97
57
  end
98
- def self.from_json(policy_json)
99
- if (!policy_json)
100
- return nil
101
- end
102
- csp = ContentSecurityPolicy.new
103
- if policy_json.has_key?("policy_id")
104
- csp.policy_id = policy_json["policy_id"]
105
- else
106
- raise "Policy ID missing"
107
- end
108
- if policy_json.has_key?("data")
109
- data_json = policy_json["data"]
110
- if data_json.has_key?("options")
111
- options_json = data_json["options"]
112
- csp.js_agent_api_key = options_json.fetch("js_agent_api_key", nil)
113
- end
114
- end
115
- if policy_json.has_key?("headers")
116
- headers = policy_json["headers"]
117
- csp_headers = []
118
- headers.each do |header|
119
- if header.has_key?("name") && header.has_key?("value")
120
- begin
121
- csp_header = ContentSecurityPolicyHeader.new(header["name"], header["value"], header["report-uri"], csp.policy_id)
122
- csp_headers.push(csp_header)
123
- rescue Exception => secure_header_exception
124
- #pass
125
- end
126
- end
127
- end
128
- csp.headers = csp_headers
129
- end
130
- return csp
58
+ if session_id and session_id.length > 0
59
+ new_query_ar << ["sid", session_id]
131
60
  end
132
- def self.cspHeadersForType(csp_type)
133
- if (!csp_type)
134
- return []
135
- end
136
- if csp_type == "csp"
137
- return ["Content-Security-Policy"]#,"X-Content-Security-Policy","X-WebKit-CSP"]
138
- elsif csp_type == "csp-report"
139
- return ["Content-Security-Policy-Report-Only"]#,"X-Content-Security-Policy-Report-Only","X-WebKit-CSP-Report-Only"]
140
- else
141
- return []
142
- end
61
+ if route_id
62
+ new_query_ar << ["rid", route_id]
143
63
  end
144
- def js_agent_app_id
145
- return TCellAgent.configuration.app_id
64
+ if new_query_ar != []
65
+ uri.query = URI.encode_www_form(new_query_ar)
146
66
  end
147
- def js_agent_api_base_url
148
- return TCellAgent.configuration.js_agent_api_base_url
67
+ report_uri = uri.to_s
68
+ if self.policy_id
69
+ checksum = ContentSecurityPolicyHeader.jhash(self.policy_id + report_uri)
70
+ if new_query_ar != []
71
+ report_uri = report_uri + "&"
72
+ else
73
+ report_uri = report_uri + "?"
74
+ end
75
+ report_uri = report_uri + "c=" + checksum.to_s
149
76
  end
150
- def js_agent_url
151
- return TCellAgent.configuration.js_agent_url
77
+ return "#{self.raw_value}; report-uri #{report_uri}"
78
+ rescue Exception
79
+ return self.raw_value
80
+ end
81
+ end
82
+ end
83
+
84
+ attr_accessor :headers
85
+ attr_accessor :policy_id
86
+ attr_accessor :js_agent_api_key
87
+
88
+ def each(transaction_id=nil, route_id=nil, hmac_session_id=nil, user_id=nil, &block)
89
+ result = []
90
+ headers.each do | header |
91
+ header_value = header.value(transaction_id, route_id, hmac_session_id)
92
+ header_names = ContentSecurityPolicy.cspHeadersForType(header.type)
93
+ header_names.each do | header_name |
94
+ result.push( {"name"=>header_name, "value"=>header_value} )
95
+ end #doloop
96
+ end
97
+ result.each(&block)
98
+ end
99
+ def self.from_json(policy_json)
100
+ if (!policy_json)
101
+ return nil
102
+ end
103
+ csp = ContentSecurityPolicy.new
104
+ if policy_json.has_key?("policy_id")
105
+ csp.policy_id = policy_json["policy_id"]
106
+ else
107
+ raise "Policy ID missing"
108
+ end
109
+
110
+ if policy_json.has_key?("data")
111
+ data_json = policy_json["data"]
112
+ if data_json.has_key?("options")
113
+ options_json = data_json["options"]
114
+ csp.js_agent_api_key = options_json.fetch("js_agent_api_key", nil)
115
+ end
116
+ end
117
+
118
+ if policy_json.has_key?("headers")
119
+ TCellAgent.configuration.js_agent_url = TCellAgent.configuration.startup_js_agent_url
120
+
121
+ headers = policy_json["headers"]
122
+ csp_headers = []
123
+
124
+
125
+ headers.each do |header|
126
+ if header.has_key?("name") && header.has_key?("value")
127
+ begin
128
+ if TCellAgent.configuration.startup_js_agent_url == "https://api.tcell.io/tcellagent.min.js" && header["value"] =~ /https:\/\/jsagent.tcell.io/
129
+ TCellAgent.configuration.js_agent_url = "https://jsagent.tcell.io/tcellagent.min.js"
130
+ end
131
+
132
+ csp_header = ContentSecurityPolicyHeader.new(header["name"], header["value"], header["report-uri"], csp.policy_id)
133
+ csp_headers.push(csp_header)
134
+ rescue
135
+ end
152
136
  end
137
+ end
138
+ csp.headers = csp_headers
153
139
  end
140
+ return csp
141
+ end
142
+ def self.cspHeadersForType(csp_type)
143
+ if (!csp_type)
144
+ return []
145
+ end
146
+ if csp_type == "csp"
147
+ return ["Content-Security-Policy"]#,"X-Content-Security-Policy","X-WebKit-CSP"]
148
+ elsif csp_type == "csp-report"
149
+ return ["Content-Security-Policy-Report-Only"]#,"X-Content-Security-Policy-Report-Only","X-WebKit-CSP-Report-Only"]
150
+ else
151
+ return []
152
+ end
153
+ end
154
+ def js_agent_app_id
155
+ return TCellAgent.configuration.app_id
156
+ end
157
+ def js_agent_api_base_url
158
+ return TCellAgent.configuration.js_agent_api_base_url
159
+ end
160
+ def js_agent_url
161
+ return TCellAgent.configuration.js_agent_url
162
+ end
154
163
  end
164
+
165
+ end
155
166
  end