contrast-agent 6.6.3 → 6.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.gitmodules +0 -3
  4. data/ext/cs__scope/cs__scope.c +1 -1
  5. data/lib/contrast/agent/assess/contrast_event.rb +2 -24
  6. data/lib/contrast/agent/assess/events/source_event.rb +7 -61
  7. data/lib/contrast/agent/assess/finalizers/hash.rb +11 -0
  8. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +0 -55
  9. data/lib/contrast/agent/assess/policy/policy_node.rb +3 -3
  10. data/lib/contrast/agent/assess/policy/policy_node_utils.rb +0 -1
  11. data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
  12. data/lib/contrast/agent/assess/policy/source_method.rb +24 -1
  13. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -5
  14. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +6 -1
  15. data/lib/contrast/agent/assess/policy/trigger_method.rb +38 -119
  16. data/lib/contrast/agent/assess/policy/trigger_node.rb +3 -3
  17. data/lib/contrast/agent/assess/property/evented.rb +2 -12
  18. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +42 -82
  19. data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -27
  20. data/lib/contrast/agent/assess/rule/response/body_rule.rb +1 -3
  21. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +77 -62
  22. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +1 -1
  23. data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +6 -1
  24. data/lib/contrast/agent/assess/rule/response/header_rule.rb +5 -5
  25. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +1 -1
  26. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +1 -1
  27. data/lib/contrast/agent/assess/tracker.rb +1 -7
  28. data/lib/contrast/agent/at_exit_hook.rb +1 -7
  29. data/lib/contrast/agent/excluder.rb +206 -0
  30. data/lib/contrast/agent/exclusion_matcher.rb +6 -0
  31. data/lib/contrast/agent/inventory/database_config.rb +18 -23
  32. data/lib/contrast/agent/middleware.rb +0 -1
  33. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +4 -0
  34. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -0
  35. data/lib/contrast/agent/protect/rule/base.rb +64 -24
  36. data/lib/contrast/agent/protect/rule/base_service.rb +1 -0
  37. data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -104
  38. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +129 -0
  39. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +169 -0
  40. data/lib/contrast/agent/protect/rule/deserialization.rb +7 -5
  41. data/lib/contrast/agent/protect/rule/path_traversal.rb +9 -7
  42. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +16 -14
  43. data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +51 -0
  44. data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +67 -0
  45. data/lib/contrast/agent/protect/rule/sqli.rb +6 -31
  46. data/lib/contrast/agent/protect/rule/xxe.rb +11 -6
  47. data/lib/contrast/agent/protect/rule.rb +3 -1
  48. data/lib/contrast/agent/reporting/attack_result/attack_result.rb +8 -0
  49. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +91 -36
  50. data/lib/contrast/agent/reporting/attack_result/user_input.rb +11 -0
  51. data/lib/contrast/agent/reporting/details/bot_blocker_details.rb +29 -0
  52. data/lib/contrast/agent/reporting/details/cmd_injection_details.rb +30 -0
  53. data/lib/contrast/agent/reporting/details/details.rb +18 -0
  54. data/lib/contrast/agent/reporting/details/http_method_tempering_details.rb +27 -0
  55. data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +27 -0
  56. data/lib/contrast/agent/reporting/details/no_sqli_details.rb +36 -0
  57. data/lib/contrast/agent/reporting/details/path_traversal_details.rb +24 -0
  58. data/lib/contrast/agent/reporting/details/path_traversal_semantic_analysis_details.rb +32 -0
  59. data/lib/contrast/agent/reporting/details/protect_rule_details.rb +17 -0
  60. data/lib/contrast/agent/reporting/details/sqli_dangerous_functions.rb +22 -0
  61. data/lib/contrast/agent/reporting/details/sqli_details.rb +36 -0
  62. data/lib/contrast/agent/reporting/details/untrusted_deserialization_details.rb +27 -0
  63. data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +24 -0
  64. data/lib/contrast/agent/reporting/details/xss_details.rb +33 -0
  65. data/lib/contrast/agent/reporting/details/xss_match.rb +30 -0
  66. data/lib/contrast/agent/reporting/details/xxe_details.rb +36 -0
  67. data/lib/contrast/agent/reporting/details/xxe_match.rb +25 -0
  68. data/lib/contrast/agent/reporting/details/xxe_wrapper.rb +25 -0
  69. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +1 -1
  70. data/lib/contrast/agent/reporting/masker/masker.rb +78 -65
  71. data/lib/contrast/agent/reporting/masker/masker_utils.rb +1 -30
  72. data/lib/contrast/agent/reporting/reporter.rb +1 -2
  73. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +2 -2
  74. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +81 -15
  75. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +13 -25
  76. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +17 -22
  77. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +46 -125
  78. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +5 -16
  79. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +10 -18
  80. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +6 -14
  81. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +1 -1
  82. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +7 -21
  83. data/lib/contrast/agent/reporting/reporting_events/finding.rb +19 -49
  84. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +12 -9
  85. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +1 -1
  86. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +23 -21
  87. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +5 -18
  88. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +1 -0
  89. data/lib/contrast/{api/decorators/trace_taint_range_tags.rb → agent/reporting/reporting_events/finding_event_taint_range_tags.rb} +7 -6
  90. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +45 -10
  91. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +1 -1
  92. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +2 -2
  93. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -14
  94. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +11 -0
  95. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +3 -1
  96. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +11 -23
  97. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +8 -26
  98. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
  99. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +4 -7
  100. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
  101. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +2 -1
  102. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +3 -3
  103. data/lib/contrast/agent/request.rb +4 -2
  104. data/lib/contrast/agent/request_context.rb +12 -15
  105. data/lib/contrast/agent/request_context_extend.rb +67 -69
  106. data/lib/contrast/agent/request_handler.rb +1 -11
  107. data/lib/contrast/agent/response.rb +0 -18
  108. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  109. data/lib/contrast/agent/telemetry/events/event.rb +1 -1
  110. data/lib/contrast/agent/telemetry/events/metric_event.rb +1 -1
  111. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +3 -3
  112. data/lib/contrast/agent/version.rb +1 -1
  113. data/lib/contrast/api/communication/messaging_queue.rb +2 -3
  114. data/lib/contrast/api/communication/socket_client.rb +4 -4
  115. data/lib/contrast/api/communication/speedracer.rb +4 -8
  116. data/lib/contrast/api/decorators/agent_startup.rb +5 -6
  117. data/lib/contrast/api/decorators/application_settings.rb +2 -1
  118. data/lib/contrast/api/decorators/application_startup.rb +6 -6
  119. data/lib/contrast/api/decorators/message.rb +0 -4
  120. data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -6
  121. data/lib/contrast/api/decorators.rb +0 -6
  122. data/lib/contrast/api/dtm.pb.rb +0 -489
  123. data/lib/contrast/components/agent.rb +16 -12
  124. data/lib/contrast/components/api.rb +10 -10
  125. data/lib/contrast/components/app_context.rb +9 -9
  126. data/lib/contrast/components/app_context_extend.rb +1 -1
  127. data/lib/contrast/components/assess.rb +92 -38
  128. data/lib/contrast/components/assess_rules.rb +36 -0
  129. data/lib/contrast/components/config.rb +54 -12
  130. data/lib/contrast/components/contrast_service.rb +8 -8
  131. data/lib/contrast/components/heap_dump.rb +1 -1
  132. data/lib/contrast/components/protect.rb +5 -5
  133. data/lib/contrast/components/ruby_component.rb +81 -0
  134. data/lib/contrast/components/sampling.rb +1 -1
  135. data/lib/contrast/components/security_logger.rb +23 -0
  136. data/lib/contrast/components/service.rb +55 -0
  137. data/lib/contrast/components/settings.rb +12 -4
  138. data/lib/contrast/config/base_configuration.rb +1 -1
  139. data/lib/contrast/config/protect_rules_configuration.rb +17 -3
  140. data/lib/contrast/config/server_configuration.rb +1 -1
  141. data/lib/contrast/config.rb +0 -6
  142. data/lib/contrast/configuration.rb +81 -17
  143. data/lib/contrast/extension/assess/exec_trigger.rb +3 -1
  144. data/lib/contrast/extension/assess/marshal.rb +3 -2
  145. data/lib/contrast/extension/assess/string.rb +0 -1
  146. data/lib/contrast/extension/extension.rb +1 -1
  147. data/lib/contrast/framework/base_support.rb +0 -5
  148. data/lib/contrast/framework/grape/support.rb +1 -23
  149. data/lib/contrast/framework/manager.rb +0 -10
  150. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -6
  151. data/lib/contrast/framework/rails/support.rb +5 -58
  152. data/lib/contrast/framework/sinatra/support.rb +2 -21
  153. data/lib/contrast/logger/cef_log.rb +21 -3
  154. data/lib/contrast/logger/log.rb +1 -11
  155. data/lib/contrast/tasks/config.rb +4 -2
  156. data/lib/contrast/utils/assess/event_limit_utils.rb +28 -12
  157. data/lib/contrast/utils/assess/trigger_method_utils.rb +10 -18
  158. data/lib/contrast/utils/findings.rb +6 -5
  159. data/lib/contrast/utils/hash_digest.rb +9 -24
  160. data/lib/contrast/utils/hash_digest_extend.rb +6 -6
  161. data/lib/contrast/utils/invalid_configuration_util.rb +21 -58
  162. data/lib/contrast/utils/log_utils.rb +47 -17
  163. data/lib/contrast/utils/net_http_base.rb +7 -8
  164. data/lib/contrast/utils/patching/policy/patch_utils.rb +3 -2
  165. data/lib/contrast/utils/stack_trace_utils.rb +0 -25
  166. data/lib/contrast/utils/string_utils.rb +9 -0
  167. data/lib/contrast/utils/telemetry_client.rb +13 -7
  168. data/lib/contrast.rb +5 -10
  169. metadata +39 -28
  170. data/lib/contrast/agent/reporting/reporting_events/trace_event_source.rb +0 -30
  171. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -43
  172. data/lib/contrast/api/decorators/activity.rb +0 -33
  173. data/lib/contrast/api/decorators/architecture_component.rb +0 -36
  174. data/lib/contrast/api/decorators/finding.rb +0 -29
  175. data/lib/contrast/api/decorators/route_coverage.rb +0 -91
  176. data/lib/contrast/api/decorators/trace_event.rb +0 -120
  177. data/lib/contrast/api/decorators/trace_event_object.rb +0 -63
  178. data/lib/contrast/api/decorators/trace_event_signature.rb +0 -69
  179. data/lib/contrast/api/decorators/trace_taint_range.rb +0 -52
  180. data/lib/contrast/config/assess_configuration.rb +0 -93
  181. data/lib/contrast/config/assess_rules_configuration.rb +0 -32
  182. data/lib/contrast/config/root_configuration.rb +0 -90
  183. data/lib/contrast/config/ruby_configuration.rb +0 -81
  184. data/lib/contrast/config/service_configuration.rb +0 -49
  185. data/lib/contrast/utils/preflight_util.rb +0 -13
@@ -30,21 +30,18 @@ module Contrast
30
30
 
31
31
  # Mask sensitive data according to the contrast sensitive data rules.
32
32
  #
33
- # @param [Contrast::Api::Dtm::Activity]
33
+ # @param [Contrast::Agent::Reporting::ApplicationActivity]
34
34
  def mask activity
35
- return unless Contrast::Agent::Reporter.enabled?
36
35
  return unless activity
37
36
 
38
- logger.debug('Searching for sensitive data',
39
- activity: activity.__id__,
40
- request: activity.http_request&.uuid)
37
+ logger.debug('Masker: masking sensitive data', activity: activity.__id__, request: activity.request&.__id__)
41
38
  mask_body(activity)
42
39
  mask_query_string(activity)
43
40
  mask_request_params(activity)
44
41
  mask_request_cookies(activity)
45
42
  mask_request_headers(activity)
46
43
  rescue StandardError => _e
47
- logger.debug('Could not mask activity!', activity: activity.__id__, request: activity.http_request&.uuid)
44
+ logger.debug('Could not mask activity!', activity: activity.__id__, request: activity.request&.__id__)
48
45
  end
49
46
 
50
47
  private
@@ -64,68 +61,67 @@ module Contrast
64
61
 
65
62
  # Mask request body:
66
63
  #
67
- # @param activity [Contrast::Api::Dtm::Activity]
64
+ # @param activity [Contrast::Agent::Reporting::ApplicationActivity]
68
65
  # @return masked_body [String, nil]
69
66
  def mask_body activity
70
67
  return unless mask_body?
71
68
 
72
- body = activity.http_request.request_body
69
+ body = activity.request.body
73
70
  return if body.nil? || body.empty?
74
71
 
75
- activity.http_request.request_body = BODY_MASK
76
- activity.http_request.request_body_binary = BODY_BINARY_MASK
72
+ activity.request.body = BODY_MASK
73
+ activity.request.body_binary = BODY_BINARY_MASK
77
74
  end
78
75
 
79
76
  # Mask request params.
80
77
  #
81
- # @param activity [Contrast::Api::Dtm::Activity]
78
+ # @param activity [Contrast::Agent::Reporting::ApplicationActivity]
82
79
  # @return masked_body [String, nil]
83
80
  def mask_request_params activity
84
- params = activity.http_request.normalized_request_params
81
+ params = activity.request.parameters
85
82
  return unless params
86
83
 
87
- mask_with_dictionary(activity.results, params)
84
+ mask_with_dictionary(activity.attack_results, params)
88
85
  end
89
86
 
90
87
  def mask_request_headers activity
91
- if activity.http_request.parsed_request_headers
92
- # Used normalized request_headers
93
- mask_with_dictionary(activity.results, activity.http_request.normalized_request_headers)
94
- else
95
- headers = activity.http_request.request_headers
96
- mask_field_hash(headers, activity.results)
97
- end
88
+ headers = activity.request.headers
89
+ return if headers&.empty?
90
+
91
+ # Used normalized request_headers
92
+ mask = mask_with_dictionary(activity.attack_results, headers)
93
+ activity.request.headers = mask if mask
98
94
  end
99
95
 
100
96
  # Mask Cookies.
101
97
  #
102
- # @param activity [Contrast::Api::Dtm::Activity] Activity to mask
98
+ # @param activity [Contrast::Agent::Reporting::ApplicationActivity] Activity to mask
103
99
  # @return masked_values [Hash, nil]
104
100
  def mask_request_cookies activity
105
- cookies = activity.http_request.normalized_cookies
106
- return unless cookies
101
+ cookies = activity.request.cookies
102
+ return if cookies&.empty?
107
103
 
108
- mask_with_dictionary(activity.results, cookies)
104
+ mask_with_dictionary(activity.attack_results, cookies)
109
105
  end
110
106
 
111
107
  # Mask request query string:
112
108
  # exp: password => sensitive to password => contrast-redacted-password
113
109
  #
114
- # @param activity [Contrast::Api::Dtm::Activity]
110
+ # @param activity [Contrast::Agent::Reporting::ApplicationActivity]
115
111
  # @return masked_query [String]
116
112
  def mask_query_string activity
117
- qs = activity.http_request.query_string
113
+ qs = activity.request.query_string
118
114
  return if qs.nil? || qs.empty?
119
115
 
120
- mask_field_hash(qs, activity.results) unless qs.cs__is_a?(String)
121
- mask_raw_query(qs, activity.results)
116
+ mask = mask_raw_query(qs, activity.attack_results)
117
+ activity.request.query_string = mask if mask
122
118
  end
123
119
 
124
120
  # Mask if the value in the passed hash are matched against dictionary
125
121
  # keyword. If the mask_attack_vector flag is set, this will also mask
126
122
  # any attack.
127
123
  #
128
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
124
+ # @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
129
125
  # results to match against.
130
126
  # @param hash [Hash] Normalized hash representing the key/val pair from
131
127
  # the activity's http request parameters.
@@ -134,81 +130,98 @@ module Contrast
134
130
  return if hash.nil? || hash.empty?
135
131
 
136
132
  hash.each do |key, val|
137
- match = dictionary_matcher(key)
138
- next unless match
139
-
140
- # The normalized values are paired.
141
- # key => Contrast::Api::Dtm::Pair (key, val<Values>).
142
- # try one level down
143
- if val.cs__respond_to?(:values)
144
- mask_values(key, val, results)
133
+ next unless dictionary_match(key)
134
+
135
+ if val.cs__is_a?(Array)
136
+ mask_values(key, val, hash, results)
145
137
  else
146
138
  # Just assign keys.
147
139
  mask_hash(key, val, hash, results)
148
140
  end
149
141
  end
150
- hash
151
142
  end
152
143
 
153
- # Mask the values of DTM pair with attack vector condition check.
154
- # if the attack vector flag is set then mask the attack value.
144
+ # Mask the values of key value pair with array of string as input.
145
+ # If the mask_attack_vector? flag is set then the attack vector won't be
146
+ # masked.
155
147
  #
156
- # @param key [String] current iterable key from Protobuf::Field::FieldHash
157
- # pointing to Contrast::Api::Dtm::Pair<key, val>(holding the value to mask)
158
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
148
+ # @param key [String]
149
+ # @param hash [Hash] Normalized hash representing the key/val pair.
150
+ # @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
159
151
  # results to match against.
160
- # @param val [Contrast::Api::Dtm::Pair<Value>]
161
- def mask_values key, val, results
162
- val.values.each.with_index do |v, idx|
152
+ # @param val [String, Array<String>]
153
+ def mask_values key, val, hash, results
154
+ val.each.with_index do |v, idx|
163
155
  # Mask the attack vector only if the flag is set.
164
- val.values[idx] = MASK + key.downcase if attack_vector?(results, v) && mask_attack_vector?
156
+ hash[key][idx] = MASK + key.downcase if attack_vector?(results, v) && mask_attack_vector?
165
157
  # It is not attack vector and we mask it as normal.
166
- val.values[idx] = MASK + key.downcase unless attack_vector?(results, v)
158
+ hash[key][idx] = MASK + key.downcase unless attack_vector?(results, v)
167
159
  end
168
- val
160
+ hash
169
161
  end
170
162
 
171
- # Handles the masking of Field hash with string values.
172
- # this case is used when called from #mask_field_hash
173
- # and #mask_raw_query helper methods. Since they dont
174
- # return values containing sub-values (key, val<Values>).
163
+ # Handles the masking of hash
175
164
  #
176
165
  # @param key [String] current iterable key from Protobuf::Field::FieldHash
177
166
  # @param val [String] normalized value to be matched against the results
178
167
  # and masked.
179
168
  # @param hash [Hash] Normalized hash representing the key/val pair.
180
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
169
+ # @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
181
170
  # results to match against.
171
+ # @return [Hash]
182
172
  def mask_hash key, val, hash, results
173
+ # Mask the attack vector only if the flag is set.
183
174
  hash[key] = MASK + key.downcase if attack_vector?(results, val) && mask_attack_vector?
175
+ # It is not attack vector we mask it.
184
176
  hash[key] = MASK + key.downcase unless attack_vector?(results, val)
177
+ hash
185
178
  end
186
179
 
187
180
  # Match to see if values matches input from AttackResults array.
188
181
  # If match is found and the attack result's response is any of
189
182
  # [BAP(Block At Perimeter), BLOCKED, PROBED] the return is true.
190
183
  #
191
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
184
+ # @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
192
185
  # results to match against.
193
186
  # @param value [String] Input to match.
194
- # @return true | false
187
+ # @return [Boolean]
195
188
  def attack_vector? results, value
196
189
  return false unless value && results
197
190
 
198
- results.each do |result|
199
- # Check samples Contrast::Api::Dtm::RaspRuleSample
200
- # is the value in sample and the response is valid?
201
- result.samples.any? do |sample|
202
- # Check user input Contrast::Api::Dtm::UserInput.
203
- match = sample.user_input.value == value.to_s &&
204
- result.response&.name != Contrast::Agent::Reporting::ResponseType::NO_ACTION
191
+ results.each do |attacker|
192
+ attacker.each do |activity|
193
+ blocked = iterate_attack_samples(activity.blocked, value)
194
+ return blocked if blocked
195
+
196
+ exploited = iterate_attack_samples(activity.exploited, value)
197
+ return exploited if exploited
205
198
 
206
- return match if match
199
+ ineffective = iterate_attack_samples(activity.ineffective, value)
200
+ return ineffective if ineffective
201
+
202
+ suspicious = iterate_attack_samples(activity.suspicious, value)
203
+ return suspicious if suspicious
207
204
  end
208
205
  end
209
206
  false
210
207
  end
211
208
 
209
+ # Go through activity samples and search for a matching input.
210
+ #
211
+ # @param activity [Contrast::Agent::Reporting::ApplicationDefendAttackActivity]
212
+ # @param value [String] Input to match.
213
+ # @return [Boolean]
214
+ def iterate_attack_samples activity, value
215
+ return false unless activity
216
+
217
+ activity.samples.any? do |sample|
218
+ match = sample.user_input.value == value.to_s
219
+
220
+ return true if match
221
+ end
222
+ false
223
+ end
224
+
212
225
  # Consult with our current settings state.
213
226
  #
214
227
  # @return true | false
@@ -227,7 +240,7 @@ module Contrast
227
240
  #
228
241
  # @param value [String] Value to check.
229
242
  # @return match [String, nil] from the Dictionary, or nil.
230
- def dictionary_matcher value
243
+ def dictionary_match value
231
244
  return unless @_dictionary
232
245
 
233
246
  @_dictionary.each do |rule|
@@ -9,35 +9,6 @@ module Contrast
9
9
  # helper methods used for masking
10
10
  module MaskerUtils
11
11
  include Contrast::Utils::ObjectShare
12
- # Helper to deal with Protobuf FieldHash.
13
- #
14
- # @param field_hash [Protobuf::Field::FieldHash] hash to be masked
15
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
16
- # results to match against.
17
- # @return [Hash]
18
- def mask_field_hash field_hash, results
19
- return {} unless field_hash&.any?
20
-
21
- hash = {}
22
- # Because this is the start of a built string, we have to be sure that it is not frozen.
23
- masked = +''
24
- field_hash.each do |entry|
25
- # Protobuf::Field::FieldHash produces array, with the key as first param and value as second.
26
- new_value = entry[1].delete(SEMICOLON).split(SPACE)
27
- new_value.each do |value|
28
- arr = value.split(EQUALS)
29
- # Add to new hash.
30
- hash[arr[0]] = arr[1]
31
- end
32
- # Mask the newly created hash.
33
- mask_with_dictionary(results, hash)
34
-
35
- # Restore to original form.
36
- hash.each { |k, v| masked += "#{ k }=#{ v }; " }
37
- masked.rstrip!
38
- field_hash[entry[0]] = masked
39
- end
40
- end
41
12
 
42
13
  # Mask raw query as it comes from the env.
43
14
  # exp:
@@ -45,7 +16,7 @@ module Contrast
45
16
  # 'ssn=contrast-redacted-ssn&id=contrast-redacted-id'
46
17
  #
47
18
  # @param query [String]
48
- # @param results [Array<Contrast::Api::Dtm::AttackResults>]
19
+ # @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivitys>]
49
20
  # results to match against.
50
21
  def mask_raw_query query, results
51
22
  masked = EMPTY_STRING
@@ -125,8 +125,7 @@ module Contrast
125
125
  #
126
126
  # @return [Boolean]
127
127
  def app_create_complete?
128
- return true if Contrast::CONTRAST_SERVICE.use_agent_communication?
129
- return true if Contrast::Agent.messaging_queue&.speedracer&.status&.startup_messages_sent?
128
+ return true if Contrast::APP_CONTEXT.session_id
130
129
 
131
130
  logger.debug('Service startup incomplete; Application may not be created; sleeping')
132
131
  sleep(5)
@@ -23,8 +23,8 @@ module Contrast
23
23
 
24
24
  def to_controlled_hash
25
25
  {
26
- environment: ::Contrast::CONFIG.root.server.environment,
27
- tags: ::Contrast::CONFIG.root.server.tags,
26
+ environment: ::Contrast::CONFIG.server.environment,
27
+ tags: ::Contrast::CONFIG.server.tags,
28
28
  version: Contrast::Agent::VERSION
29
29
  }
30
30
  end
@@ -5,6 +5,7 @@ require 'contrast/components/logger'
5
5
  require 'contrast/agent/reporting/reporting_events/application_reporting_event'
6
6
  require 'contrast/agent/reporting/reporting_events/application_defend_activity'
7
7
  require 'contrast/agent/reporting/reporting_events/application_inventory_activity'
8
+ require 'contrast/agent/reporting/attack_result/response_type'
8
9
 
9
10
  module Contrast
10
11
  module Agent
@@ -12,38 +13,103 @@ module Contrast
12
13
  # This is the new ApplicationActivity class which will include all the needed information for the new reporting
13
14
  # system to report
14
15
  class ApplicationActivity < Contrast::Agent::Reporting::ApplicationReportingEvent
15
- class << self
16
- # @param app_activity_dtm [Contrast::Api::Dtm::Activity]
17
- # @return [Contrast::Agent::Reporting::ApplicationActivity]
18
- def convert app_activity_dtm
19
- app_activity = new
20
- app_activity.attach_data(app_activity_dtm)
21
- app_activity
22
- end
23
- end
16
+ include Contrast::Agent::Reporting::ResponseType
17
+
18
+ # @return [Integer]
19
+ attr_accessor :query_count
20
+ # @return [Array]
21
+ attr_accessor :routes
22
+ # @return [Contrast::Agent::Response]
23
+ attr_accessor :response
24
24
 
25
25
  def initialize
26
+ @routes = []
27
+ @query_count = 0
26
28
  @event_method = :PUT
27
29
  @event_type = :application_activity
28
30
  @event_endpoint = Contrast::Agent::Reporting::Endpoints.application_activity
29
31
  super
30
32
  end
31
33
 
34
+ # @return [Contrast::Agent::Reporting::FindingRequest] Current context's request
35
+ def request
36
+ @_request ||= FindingRequest.convert(Contrast::Agent::REQUEST_TRACKER.current&.request)
37
+ end
38
+
39
+ # @return [Contrast::Agent::Reporting::ApplicationDefendActivity] main
40
+ # activity for all protect rules.
41
+ def defend
42
+ @_defend ||= Contrast::Agent::Reporting::ApplicationDefendActivity.new
43
+ end
44
+
45
+ # @return [Contrast::Agent::Reporting::ApplicationInventoryActivity] main
46
+ # activity for all inventory activity reporting.
47
+ def inventory
48
+ @_inventory ||= Contrast::Agent::Reporting::ApplicationInventoryActivity.new
49
+ end
50
+
51
+ # @return file_name [String] used for audit
32
52
  def file_name
33
53
  'activity-application'
34
54
  end
35
55
 
36
56
  def to_controlled_hash
37
57
  hsh = { lastUpdate: since_last_update }
38
- hsh[:defend] = @defend&.to_controlled_hash if @defend
39
- hsh[:inventory] = @inventory&.to_controlled_hash if @inventory
58
+ hsh[:defend] = @_defend&.to_controlled_hash if @_defend
59
+ hsh[:inventory] = @_inventory&.to_controlled_hash if @_inventory
40
60
  hsh
41
61
  end
42
62
 
43
- # @param activity_dtm [Contrast::Api::Dtm::ApplicationActivity]
44
- def attach_data activity_dtm
45
- @defend = Contrast::Agent::Reporting::ApplicationDefendActivity.convert(activity_dtm)
46
- @inventory = Contrast::Agent::Reporting::ApplicationInventoryActivity.convert(activity_dtm)
63
+ # Look for attack results and access to samples by
64
+ # searching with rule_id and response_type
65
+ #
66
+ # @param rule_id [String] name of the protect rule
67
+ # @param response_type[Symbol<Contrast::Agent::Reporting::ResponseType]
68
+ # filter by response type
69
+ # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity>, nil]
70
+ # return any matches.
71
+ def attack_results_for rule_id, response_type = nil
72
+ results = []
73
+ defend.attackers.each do |attacker|
74
+ results << case response_type
75
+ when BLOCKED, BLOCK_AT_PERIMETER
76
+ attacker.protection_rules[rule_id].blocked
77
+ when MONITORED
78
+ attacker.protection_rules[rule_id].exploited
79
+ when PROBED
80
+ attacker.protection_rules[rule_id].ineffective
81
+ when SUSPICIOUS
82
+ attacker.protection_rules[rule_id].suspicious
83
+ else
84
+ attacker.protection_rules[rule_id]
85
+ end
86
+ end
87
+ results
88
+ end
89
+
90
+ # By reference. List of all results only by values, no rule_ids.
91
+ #
92
+ # @return [Array<[Contrast::Agent::Reporting::ApplicationDefendAttackerActivity]>]
93
+ def attack_results
94
+ results = []
95
+ defend.attackers.each { |a| results << a.protection_rules.values }
96
+ results
97
+ end
98
+
99
+ # This is primary used for attaching new data and merging existing
100
+ # samples per rule entry in attackers, and to make sure the attack
101
+ # time_map is updated correctly.
102
+ #
103
+ # @param attack_result [Contrast::Agent::Reporting::AttackResult]
104
+ def attach_defend attack_result
105
+ defend.attach_data(attack_result)
106
+ end
107
+
108
+ # This is primary used for attaching new inventory reporting
109
+ #
110
+ # @param architecture [Contrast::Agent::Reporting::AttackResult]
111
+ def attach_inventory architecture
112
+ inventory.attach_data(architecture)
47
113
  end
48
114
  end
49
115
  end
@@ -13,20 +13,9 @@ module Contrast
13
13
  # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackerActivity>]
14
14
  attr_reader :attackers
15
15
 
16
- class << self
17
- # @param activity_dtm [Contrast::Api::Dtm::ApplicationActivity]
18
- # @return [Contrast::Agent::Reporting::ApplicationDefendActivity]
19
- def convert activity_dtm
20
- activity = new
21
- activity.attach_data(activity_dtm.results)
22
- activity
23
- end
24
- end
25
-
26
16
  def initialize
27
17
  @attackers = []
28
18
  @event_type = :application_defend_activity
29
- super
30
19
  end
31
20
 
32
21
  def to_controlled_hash
@@ -35,20 +24,19 @@ module Contrast
35
24
  }
36
25
  end
37
26
 
38
- # @param attack_dtms [Array<Contrast::Api::Dtm::AttackResult>]
39
- def attach_data attack_dtms
40
- attack_dtms.each do |attack_result|
41
- attacker_activity = Contrast::Agent::Reporting::ApplicationDefendAttackerActivity.convert(attack_result)
42
- existing_attacker_activity = attackers.find do |existing|
43
- existing.source_forwarded_for == attacker_activity.source_forwarded_for &&
44
- existing.source_ip == attacker_activity.source_ip
45
- end
46
- rule = attack_result.rule_id
47
- if existing_attacker_activity
48
- attach_existing(existing_attacker_activity, attacker_activity, rule)
49
- else
50
- attackers << attacker_activity
51
- end
27
+ # @param attack_result [Contrast::Agent::Reporting::AttackResult]
28
+ def attach_data attack_result
29
+ attacker_activity = Contrast::Agent::Reporting::ApplicationDefendAttackerActivity.new
30
+ attacker_activity.attach_data(attack_result)
31
+ existing_attacker_activity = attackers.find do |existing|
32
+ existing.source_forwarded_for == attacker_activity.source_forwarded_for &&
33
+ existing.source_ip == attacker_activity.source_ip
34
+ end
35
+ rule = attack_result.rule_id
36
+ if existing_attacker_activity
37
+ attach_existing(existing_attacker_activity, attacker_activity, rule)
38
+ else
39
+ attackers << attacker_activity
52
40
  end
53
41
  end
54
42
 
@@ -19,44 +19,39 @@ module Contrast
19
19
  attr_accessor :ineffective
20
20
  # @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
21
21
  attr_accessor :suspicious
22
-
23
- class << self
24
- # @param attack_result [Contrast::Api::Dtm::AttackResult]
25
- def convert attack_result
26
- activity = new
27
- activity.attach_data(attack_result)
28
- activity
29
- end
30
- end
22
+ # Helper method to determine before hand the response type and iv needed for access
23
+ #
24
+ # @return [Contrast::Agent::Reporting::ResponseType]
25
+ attr_reader :response_type
31
26
 
32
27
  def initialize
33
28
  @start_time = start_time
34
- super
35
29
  end
36
30
 
37
31
  def to_controlled_hash
38
32
  {
39
33
  startTime: @start_time,
40
- blocked: blocked&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
41
- exploited: exploited&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
42
- ineffective: ineffective&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
43
- suspicious: suspicious&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH
34
+ blocked: @blocked&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
35
+ exploited: @exploited&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
36
+ ineffective: @ineffective&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
37
+ suspicious: @suspicious&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH
44
38
  }
45
39
  end
46
40
 
47
- # @param attack_result [Contrast::Api::Dtm::AttackResult]
41
+ # @param attack_result [Contrast::Agent::Reporting::AttackResult]
48
42
  # @return [Contrast::Agent::Reporting::Defend::AttackSampleActivity]
49
43
  def attach_data attack_result
50
- attack_sample_activity =
51
- Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.convert(attack_result)
52
- case attack_result.response
53
- when ::Contrast::Api::Dtm::AttackResult::ResponseType::BLOCKED
44
+ attack_sample_activity = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
45
+ attack_sample_activity.attach_data(attack_result)
46
+ @response_type = attack_result.response
47
+ case response_type
48
+ when ::Contrast::Agent::Reporting::ResponseType::BLOCKED
54
49
  @blocked = attack_sample_activity
55
- when ::Contrast::Api::Dtm::AttackResult::ResponseType::MONITORED
50
+ when ::Contrast::Agent::Reporting::ResponseType::MONITORED
56
51
  @exploited = attack_sample_activity
57
- when ::Contrast::Api::Dtm::AttackResult::ResponseType::PROBED
52
+ when ::Contrast::Agent::Reporting::ResponseType::PROBED
58
53
  @ineffective = attack_sample_activity
59
- when ::Contrast::Api::Dtm::AttackResult::ResponseType::SUSPICIOUS
54
+ when ::Contrast::Agent::Reporting::ResponseType::SUSPICIOUS
60
55
  @suspicious = attack_sample_activity
61
56
  end
62
57
  end