contrast-agent 6.6.5 → 6.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) 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 +36 -132
  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 -84
  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/excluder.rb +206 -0
  29. data/lib/contrast/agent/exclusion_matcher.rb +6 -0
  30. data/lib/contrast/agent/inventory/database_config.rb +6 -10
  31. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +4 -0
  32. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -0
  33. data/lib/contrast/agent/protect/rule/base.rb +49 -5
  34. data/lib/contrast/agent/protect/rule/base_service.rb +1 -0
  35. data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -105
  36. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +129 -0
  37. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +169 -0
  38. data/lib/contrast/agent/protect/rule/deserialization.rb +2 -1
  39. data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +51 -0
  40. data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +67 -0
  41. data/lib/contrast/agent/protect/rule/sqli.rb +6 -31
  42. data/lib/contrast/agent/protect/rule/xxe.rb +2 -0
  43. data/lib/contrast/agent/protect/rule.rb +3 -1
  44. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +6 -0
  45. data/lib/contrast/agent/reporting/details/sqli_dangerous_functions.rb +22 -0
  46. data/lib/contrast/agent/reporting/reporter.rb +1 -2
  47. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +2 -2
  48. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +1 -4
  49. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +1 -1
  50. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -23
  51. data/lib/contrast/agent/reporting/reporting_events/finding.rb +19 -49
  52. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +12 -9
  53. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +1 -1
  54. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +23 -21
  55. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +5 -18
  56. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +1 -0
  57. data/lib/contrast/{api/decorators/trace_taint_range_tags.rb → agent/reporting/reporting_events/finding_event_taint_range_tags.rb} +7 -6
  58. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +1 -1
  59. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +1 -1
  60. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +2 -2
  61. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -14
  62. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +11 -0
  63. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +3 -1
  64. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +11 -23
  65. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +8 -26
  66. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
  67. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +4 -7
  68. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
  69. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +3 -3
  70. data/lib/contrast/agent/request.rb +2 -2
  71. data/lib/contrast/agent/request_context.rb +8 -20
  72. data/lib/contrast/agent/request_context_extend.rb +15 -36
  73. data/lib/contrast/agent/request_handler.rb +0 -8
  74. data/lib/contrast/agent/response.rb +0 -18
  75. data/lib/contrast/agent/telemetry/events/event.rb +1 -1
  76. data/lib/contrast/agent/telemetry/events/metric_event.rb +1 -1
  77. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +3 -3
  78. data/lib/contrast/agent/version.rb +1 -1
  79. data/lib/contrast/api/communication/messaging_queue.rb +2 -3
  80. data/lib/contrast/api/communication/socket_client.rb +4 -4
  81. data/lib/contrast/api/communication/speedracer.rb +4 -8
  82. data/lib/contrast/api/decorators/agent_startup.rb +5 -6
  83. data/lib/contrast/api/decorators/application_settings.rb +2 -1
  84. data/lib/contrast/api/decorators/application_startup.rb +6 -6
  85. data/lib/contrast/api/decorators/message.rb +0 -4
  86. data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -6
  87. data/lib/contrast/api/decorators.rb +0 -6
  88. data/lib/contrast/api/dtm.pb.rb +0 -489
  89. data/lib/contrast/components/agent.rb +16 -12
  90. data/lib/contrast/components/api.rb +10 -10
  91. data/lib/contrast/components/app_context.rb +3 -3
  92. data/lib/contrast/components/app_context_extend.rb +1 -1
  93. data/lib/contrast/components/assess.rb +92 -38
  94. data/lib/contrast/components/assess_rules.rb +36 -0
  95. data/lib/contrast/components/config.rb +54 -12
  96. data/lib/contrast/components/contrast_service.rb +8 -8
  97. data/lib/contrast/components/heap_dump.rb +1 -1
  98. data/lib/contrast/components/protect.rb +5 -5
  99. data/lib/contrast/components/ruby_component.rb +81 -0
  100. data/lib/contrast/components/sampling.rb +1 -1
  101. data/lib/contrast/components/security_logger.rb +23 -0
  102. data/lib/contrast/components/service.rb +55 -0
  103. data/lib/contrast/components/settings.rb +12 -4
  104. data/lib/contrast/config/base_configuration.rb +1 -1
  105. data/lib/contrast/config/protect_rules_configuration.rb +17 -3
  106. data/lib/contrast/config/server_configuration.rb +1 -1
  107. data/lib/contrast/config.rb +0 -6
  108. data/lib/contrast/configuration.rb +81 -17
  109. data/lib/contrast/extension/assess/exec_trigger.rb +3 -1
  110. data/lib/contrast/extension/assess/marshal.rb +3 -2
  111. data/lib/contrast/extension/assess/string.rb +0 -1
  112. data/lib/contrast/extension/extension.rb +1 -1
  113. data/lib/contrast/framework/base_support.rb +0 -5
  114. data/lib/contrast/framework/grape/support.rb +1 -23
  115. data/lib/contrast/framework/manager.rb +0 -10
  116. data/lib/contrast/framework/rails/support.rb +5 -58
  117. data/lib/contrast/framework/sinatra/support.rb +2 -21
  118. data/lib/contrast/logger/cef_log.rb +21 -3
  119. data/lib/contrast/logger/log.rb +1 -11
  120. data/lib/contrast/tasks/config.rb +4 -2
  121. data/lib/contrast/utils/assess/event_limit_utils.rb +5 -8
  122. data/lib/contrast/utils/assess/trigger_method_utils.rb +10 -18
  123. data/lib/contrast/utils/findings.rb +6 -5
  124. data/lib/contrast/utils/hash_digest.rb +9 -24
  125. data/lib/contrast/utils/hash_digest_extend.rb +6 -6
  126. data/lib/contrast/utils/invalid_configuration_util.rb +21 -58
  127. data/lib/contrast/utils/log_utils.rb +32 -8
  128. data/lib/contrast/utils/net_http_base.rb +2 -2
  129. data/lib/contrast/utils/patching/policy/patch_utils.rb +3 -2
  130. data/lib/contrast/utils/stack_trace_utils.rb +0 -25
  131. data/lib/contrast/utils/string_utils.rb +9 -0
  132. data/lib/contrast/utils/telemetry_client.rb +13 -7
  133. data/lib/contrast.rb +5 -10
  134. metadata +22 -28
  135. data/lib/contrast/agent/reporting/reporting_events/trace_event_source.rb +0 -30
  136. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -36
  137. data/lib/contrast/api/decorators/activity.rb +0 -33
  138. data/lib/contrast/api/decorators/architecture_component.rb +0 -36
  139. data/lib/contrast/api/decorators/finding.rb +0 -29
  140. data/lib/contrast/api/decorators/route_coverage.rb +0 -91
  141. data/lib/contrast/api/decorators/trace_event.rb +0 -120
  142. data/lib/contrast/api/decorators/trace_event_object.rb +0 -63
  143. data/lib/contrast/api/decorators/trace_event_signature.rb +0 -69
  144. data/lib/contrast/api/decorators/trace_taint_range.rb +0 -52
  145. data/lib/contrast/config/assess_configuration.rb +0 -93
  146. data/lib/contrast/config/assess_rules_configuration.rb +0 -32
  147. data/lib/contrast/config/root_configuration.rb +0 -90
  148. data/lib/contrast/config/ruby_configuration.rb +0 -81
  149. data/lib/contrast/config/service_configuration.rb +0 -49
  150. data/lib/contrast/utils/preflight_util.rb +0 -13
@@ -0,0 +1,67 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/agent/reporting/details/sqli_dangerous_functions'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Protect
9
+ module Rule
10
+ # This class will include the check for SQL Injection Semantic Dangerous Functions
11
+ class SqliDangerousFunctions < Contrast::Agent::Protect::Rule::SqliBaseRule
12
+ NAME = 'sql-injection-semantic-dangerous-functions'
13
+ BLOCK_MESSAGE = 'SQLi Semantic Dangerous Functions rule triggered. Response blocked.'
14
+
15
+ SQL_DANGEROUS_FUNCTIONS = %w[unhex waitfor xp_cmdshell exec].cs__freeze
16
+
17
+ def rule_name
18
+ NAME
19
+ end
20
+
21
+ def infilter context, query_string
22
+ return unless infilter?(context)
23
+ return unless violated?(query_string)
24
+
25
+ result = build_violation(context, query_string)
26
+ return unless result
27
+
28
+ append_to_activity(context, result)
29
+
30
+ cef_logging(result, :successful_attack)
31
+ raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
32
+ end
33
+
34
+ protected
35
+
36
+ def violated? attack_string
37
+ SQL_DANGEROUS_FUNCTIONS.any? { |dang_func| attack_string.downcase.include?(dang_func) }
38
+ end
39
+
40
+ def build_violation context, potential_attack_string
41
+ result = build_attack_result(context)
42
+ update_successful_attack_response(context, nil, result, potential_attack_string)
43
+ append_sample(context, nil, result, potential_attack_string)
44
+ result
45
+ end
46
+
47
+ # Override if rule can make use of the candidate string or kwargs to
48
+ # build rasp rule sample.
49
+ def build_sample context, ia_result, candidate_string, **_kwargs
50
+ sample = build_base_sample(context, nil)
51
+ sample.details = Contrast::Agent::Reporting::Details::SqliDangerousFunctions.new
52
+ sample.details.query = candidate_string
53
+
54
+ if ia_result.nil?
55
+ ui = Contrast::Agent::Reporting::UserInput.new
56
+ ui.input_type = :UNKNOWN
57
+ ui.value = candidate_string
58
+ sample.user_input = ui
59
+ end
60
+
61
+ sample
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -5,13 +5,15 @@ require 'contrast/agent/protect/rule/base_service'
5
5
  require 'contrast/agent/protect/policy/applies_sqli_rule'
6
6
  require 'contrast/agent/protect/rule/sql_sample_builder'
7
7
  require 'contrast/agent/reporting/input_analysis/input_type'
8
+ require 'contrast/agent/protect/rule/sqli/sqli_base_rule'
9
+ require 'contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions'
8
10
 
9
11
  module Contrast
10
12
  module Agent
11
13
  module Protect
12
14
  module Rule
13
15
  # The Ruby implementation of the Protect SQL Injection rule.
14
- class Sqli < Contrast::Agent::Protect::Rule::BaseService
16
+ class Sqli < Contrast::Agent::Protect::Rule::SqliBaseRule
15
17
  # Generate a sample for the SQLI injection detection rule, allowing for reporting to and rendering
16
18
  # by TeamServer
17
19
  include SqlSampleBuilder::SqliSample
@@ -22,28 +24,9 @@ module Contrast
22
24
  include Contrast::Agent::Reporting::InputType
23
25
  end
24
26
 
25
- APPLICABLE_USER_INPUTS = [
26
- BODY, COOKIE_NAME, COOKIE_VALUE, HEADER,
27
- PARAMETER_NAME, PARAMETER_VALUE, JSON_VALUE,
28
- MULTIPART_VALUE, MULTIPART_FIELD_NAME,
29
- XML_VALUE, DWR_VALUE
30
- ].cs__freeze
31
27
  NAME = 'sql-injection'
32
- BLOCK_MESSAGE = 'SQLi rule triggered. Response blocked.'
33
28
 
34
- class << self
35
- # @param attack_sample [Contrast::Api::Dtm::RaspRuleSample]
36
- # @return [Hash] the details for this specific rule
37
- def extract_details attack_sample
38
- {
39
- start: attack_sample.sqli.start_idx,
40
- end: attack_sample.sqli.end_idx,
41
- boundaryOverrunIndex: attack_sample.sqli.boundary_overrun_idx,
42
- inputBoundaryIndex: attack_sample.sqli.input_boundary_idx,
43
- query: attack_sample.sqli.query
44
- }
45
- end
46
- end
29
+ SUB_RULES = [Contrast::Agent::Protect::Rule::SqliDangerousFunctions.new].cs__freeze
47
30
 
48
31
  def rule_name
49
32
  NAME
@@ -53,16 +36,8 @@ module Contrast
53
36
  BLOCK_MESSAGE
54
37
  end
55
38
 
56
- def infilter context, database, query_string
57
- return unless infilter?(context)
58
-
59
- result = find_attacker(context, query_string, database: database)
60
- return unless result
61
-
62
- append_to_activity(context, result)
63
-
64
- cef_logging(result, :successful_attack, value: query_string)
65
- raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
39
+ def sub_rules
40
+ SUB_RULES
66
41
  end
67
42
  end
68
43
  end
@@ -59,6 +59,8 @@ module Contrast
59
59
  # @raise [Contrast::SecurityException] Security exception if an XXE
60
60
  # attack is found and the rule is in block mode.
61
61
  def infilter context, framework, xml
62
+ return if protect_excluded_by_url?(context)
63
+
62
64
  result = find_attacker(context, xml, framework: framework)
63
65
  return unless result
64
66
 
@@ -28,12 +28,14 @@ require 'contrast/agent/protect/rule/sqli/default_sql_scanner'
28
28
  require 'contrast/agent/protect/rule/sqli/mysql_sql_scanner'
29
29
  require 'contrast/agent/protect/rule/sqli/postgres_sql_scanner'
30
30
  require 'contrast/agent/protect/rule/sqli/sqlite_sql_scanner'
31
+ require 'contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions'
31
32
 
32
33
  # The classes required for Path Traversal
33
34
  require 'contrast/agent/protect/rule/path_traversal'
34
35
 
35
- # The classes required for Command Injection
36
+ # The classes required for Command Injection and sub-rules
36
37
  require 'contrast/agent/protect/rule/cmd_injection'
38
+ require 'contrast/agent/protect/rule/cmdi/cmdi_backdoors'
37
39
 
38
40
  # The classes required for XXE
39
41
  require 'contrast/agent/protect/rule/xxe'
@@ -25,6 +25,10 @@ module Contrast
25
25
  attr_accessor :virtual_patch
26
26
 
27
27
  class << self
28
+ # @param context [Contrast::Agent::RequestContext]
29
+ # @param ia_result [Contrast::Api::Settings::InputAnalysisResult] the analysis of the input that was
30
+ # determined to be an attack
31
+ # @return [Contrast::Agent::Reporting::RaspRuleSample]
28
32
  def build context, ia_result
29
33
  sample = new
30
34
  sample.time_stamp = context&.timer&.start_ms
@@ -35,6 +39,8 @@ module Contrast
35
39
  sample
36
40
  end
37
41
 
42
+ # @param ia_result [Contrast::Api::Settings::InputAnalysisResult] the analysis of the input that was
43
+ # determined to be an attack
38
44
  def build_user_input_from_ia ia_result
39
45
  # TODO: RUBY-99999 remove once only using Agent IA
40
46
  result = if ia_result.cs__is_a?(Contrast::Api::Settings::InputAnalysisResult)
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/agent/reporting/details/protect_rule_details'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Reporting
9
+ module Details
10
+ # SqliDangerousFunctions IA result details info.
11
+ class SqliDangerousFunctions < ProtectRuleDetails
12
+ # @return [String]
13
+ attr_accessor :query
14
+
15
+ def to_controlled_hash
16
+ { query: query }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -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
@@ -19,14 +19,11 @@ module Contrast
19
19
  attr_accessor :query_count
20
20
  # @return [Array]
21
21
  attr_accessor :routes
22
- # @return [Array]
23
- attr_accessor :dynamic_sources
24
22
  # @return [Contrast::Agent::Response]
25
23
  attr_accessor :response
26
24
 
27
25
  def initialize
28
26
  @routes = []
29
- @dynamic_sources = {}
30
27
  @query_count = 0
31
28
  @event_method = :PUT
32
29
  @event_type = :application_activity
@@ -77,7 +74,7 @@ module Contrast
77
74
  results << case response_type
78
75
  when BLOCKED, BLOCK_AT_PERIMETER
79
76
  attacker.protection_rules[rule_id].blocked
80
- when EXPLOITED
77
+ when MONITORED
81
78
  attacker.protection_rules[rule_id].exploited
82
79
  when PROBED
83
80
  attacker.protection_rules[rule_id].ineffective
@@ -27,7 +27,7 @@ module Contrast
27
27
  #
28
28
  # @return [Hash]
29
29
  def to_controlled_hash
30
- app_config = ::Contrast::CONFIG.root.application
30
+ app_config = ::Contrast::CONFIG.application
31
31
  {
32
32
  code: app_config.code,
33
33
  group: app_config.group,
@@ -29,18 +29,6 @@ module Contrast
29
29
  AC_TYPE_DB = 'db'
30
30
  VALID_TYPES = %w[db ldap ws].cs__freeze
31
31
 
32
- # class << self
33
- # # Convert a DTM for SpeedRacer to an Event for TeamServer.
34
- # #
35
- # # @param component_dtm [Contrast::Api::Dtm::ArchitectureComponent]
36
- # # @return [Contrast::Agent::Reporting::ArchitectureComponent]
37
- # def convert component_dtm
38
- # report = new
39
- # report.attach_data(component_dtm)
40
- # report
41
- # end
42
- # end
43
-
44
32
  class << self
45
33
  def build_database
46
34
  msg = new
@@ -49,17 +37,6 @@ module Contrast
49
37
  end
50
38
  end
51
39
 
52
- # # Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly.
53
- # #
54
- # # @param component_dtm [Contrast::Api::Dtm::ArchitectureComponent]
55
- # def attach_data component_dtm
56
- # @remote_host = component_dtm.remote_host
57
- # @remote_port = component_dtm.remote_port
58
- # @type = component_dtm.type
59
- # @url = component_dtm.url
60
- # @vendor = component_dtm.vendor
61
- # end
62
-
63
40
  # Convert the instance variables on the class, and other information, into the identifiers required for
64
41
  # TeamServer to process the JSON form of this message.
65
42
  #
@@ -29,14 +29,14 @@ module Contrast
29
29
  # @return [Array<Contrast::Agent::Reporting::FindingEvent>] the events associated with this finding, if the
30
30
  # finding is event (dataflow) based.
31
31
  attr_reader :events
32
- # @return [String] the evidence associated with this finding, if the finding is event based. deprecated in
33
- # favor of properties
32
+ # # @return [String] the evidence associated with this finding, if the finding is event based. deprecated in
33
+ # # favor of properties
34
34
  # attr_reader :evidence
35
35
  # @return [Hash<String,String>] properties that prove the violation of the rule for this finding
36
36
  attr_reader :properties
37
37
  # @return [Contrast::Agent::Reporting::FindingRequest] the request associated with this finding, if the finding
38
38
  # is request based
39
- attr_reader :request
39
+ attr_accessor :request
40
40
  # @return [String] the uniquely identifying hash of this finding
41
41
  attr_accessor :hash_code
42
42
 
@@ -54,16 +54,6 @@ module Contrast
54
54
  xxssprotection-header-disabled
55
55
  ].cs__freeze
56
56
 
57
- class << self
58
- # @param finding_dtm [Contrast::Api::Dtm::Finding]
59
- # @return [Contrast::Agent::Reporting::Finding]
60
- def convert finding_dtm
61
- report = new(finding_dtm.rule_id)
62
- report.attach_property_data(finding_dtm)
63
- report
64
- end
65
- end
66
-
67
57
  def initialize rule_id
68
58
  @event_method = :PUT
69
59
  @event_endpoint = "#{ Contrast::API.api_url }/api/ng/traces"
@@ -100,28 +90,10 @@ module Contrast
100
90
  event_data = Contrast::Agent::Assess::Events::EventData.new(trigger_node, source, object, ret, args)
101
91
  contrast_event = Contrast::Agent::Assess::ContrastEvent.new(event_data)
102
92
  events << Contrast::Agent::Reporting::FindingEvent.convert(contrast_event)
103
- attach_properties
104
93
  return unless request
105
94
 
106
95
  @request = Contrast::Agent::Reporting::FindingRequest.convert(request)
107
- @routes << Contrast::Agent::Reporting::RouteDiscovery.convert(request.route) if request.route
108
- end
109
-
110
- # Attach the data from a Contrast::Api::Dtm::Finding required for property based findings generated during
111
- # response analysis.
112
- #
113
- # @param finding_dtm [Contrast::Api::Dtm::Finding]
114
- def attach_property_data finding_dtm
115
- @hash_code = finding_dtm.hash_code
116
- @rule_id = finding_dtm.rule_id
117
- finding_dtm.properties.each_pair do |key, value|
118
- @properties[key] = value
119
- end
120
- finding_dtm.routes.each do |route|
121
- @routes << Contrast::Agent::Reporting::RouteDiscovery.convert(route)
122
- end
123
- request = Contrast::Agent::REQUEST_TRACKER.current&.request
124
- @request = Contrast::Agent::Reporting::FindingRequest.convert(request) if request
96
+ @routes << request.discovered_route if request.discovered_route
125
97
  end
126
98
 
127
99
  # Convert the instance variables on the class, and other information, into the identifiers required for
@@ -137,16 +109,9 @@ module Contrast
137
109
  return
138
110
  end
139
111
 
140
- hsh = {
141
- created: created,
142
- hash: hash_code.to_s,
143
- ruleId: rule_id,
144
- session_id: ::Contrast::ASSESS.session_id,
145
- version: 4
146
- }
147
- hsh[:events] = events.map(&:to_controlled_hash) if event_based?
148
- # hsh[:evidence] = evidence unless event_based? || property_based?
149
- hsh[:properties] = properties if property_based?
112
+ hsh = base_hash
113
+ hsh[:events] = events.map(&:to_controlled_hash) if events.any?
114
+ hsh[:properties] = properties if properties.any?
150
115
  hsh[:tags] = Contrast::ASSESS.tags if Contrast::ASSESS.tags
151
116
  return hsh unless request_based?
152
117
 
@@ -155,6 +120,17 @@ module Contrast
155
120
  hsh
156
121
  end
157
122
 
123
+ # @return [Hash] the base of every finding, regardless of type
124
+ def base_hash
125
+ {
126
+ created: created,
127
+ hash: hash_code.to_s,
128
+ ruleId: rule_id,
129
+ session_id: ::Contrast::ASSESS.session_id,
130
+ version: 4
131
+ }
132
+ end
133
+
158
134
  # @raise [ArgumentError]
159
135
  def validate
160
136
  raise(ArgumentError, "#{ self } did not have a proper rule. Unable to continue.") unless @rule_id
@@ -174,12 +150,6 @@ module Contrast
174
150
 
175
151
  private
176
152
 
177
- # Our events have properties on them. To report them to TeamServer, we need to pull them from our object up to
178
- # the Contrast::Agent::Reporting::Finding level.
179
- #
180
- # TODO: RUBY-99999 put properties on events, not just on DTM
181
- def attach_properties; end
182
-
183
153
  def build_events events, event
184
154
  return unless event
185
155
 
@@ -196,7 +166,7 @@ module Contrast
196
166
  #
197
167
  # @return [Boolean]
198
168
  def event_based?
199
- !property_based? && !config_based?
169
+ !property_based? && !config_based? && !hardcoded?
200
170
  end
201
171
 
202
172
  # Rules which are property based must have a property to be sent to TeamServer. Eventually, each rule may own
@@ -100,6 +100,10 @@ module Contrast
100
100
  end
101
101
  end
102
102
 
103
+ def initialize
104
+ @event_sources = []
105
+ end
106
+
103
107
  # Parse the data from a Contrast::Agent::Assess::ContrastEvent to attach what is required for reporting to
104
108
  # TeamServer to this Contrast::Agent::Reporting::FindingEvent
105
109
  #
@@ -208,11 +212,9 @@ module Contrast
208
212
  #
209
213
  # @param event [Contrast::Agent::Assess::ContrastEvent]
210
214
  def event_sources! event
211
- @event_sources = []
212
215
  return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
213
216
 
214
- source = Contrast::Agent::Reporting::FindingEventSource.convert(event)
215
- event_sources << source if source
217
+ event_sources << event.event_source if event.event_source
216
218
  end
217
219
 
218
220
  # Convert the parent id's of the given ContrastEvent to the reportable form for this FindingEvent.
@@ -237,12 +239,13 @@ module Contrast
237
239
  #
238
240
  # @param event [Contrast::Agent::Assess::ContrastEvent]
239
241
  def stack! event
240
- @stack = []
241
- event.stack_trace.each do |stack_event|
242
- if (report = Contrast::Agent::Reporting::FindingEventStack.convert(stack_event))
243
- stack << report
244
- end
245
- end
242
+ @stack = if event.stack_trace
243
+ event.stack_trace.compact.map! do |stack_event|
244
+ Contrast::Agent::Reporting::FindingEventStack.new(stack_event)
245
+ end
246
+ else
247
+ Contrast::Utils::ObjectShare::EMPTY_ARRAY
248
+ end
246
249
  end
247
250
 
248
251
  # Convert the taint ranges of the given ContrastEvent to the reportable form for this FindingEvent.
@@ -61,7 +61,7 @@ module Contrast
61
61
  # 8 is STATIC in Java... we have to placate them for now it has been requested that flags be removed since it
62
62
  # isn't used
63
63
  @flags = 8 unless node.instance_method?
64
- @method_name = node.method_name
64
+ @method_name = node.method_name.to_s
65
65
  @return_type = type_name(event.ret)
66
66
  # if there's a ret, then this method isn't nil. not 100% full proof since you can return nil, but this is the
67
67
  # best we've got currently.
@@ -2,8 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'base64'
5
- require 'contrast/agent/assess/contrast_event'
6
- require 'contrast/agent/assess/events/source_event'
7
5
  require 'contrast/components/logger'
8
6
 
9
7
  module Contrast
@@ -21,25 +19,11 @@ module Contrast
21
19
  # @return [String] the type of the source
22
20
  attr_reader :type
23
21
 
24
- class << self
25
- # @param event [Contrast::Agent::Assess::Events::ContrastEvent] the event to pull the source off of
26
- # @return [Contrast::Agent::Reporting::FindingEventSource]
27
- def convert event
28
- return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
29
-
30
- report = new
31
- report.attach_data(event)
32
- report
33
- end
34
- end
35
-
36
- # Parse the data from a Contrast::Agent::Assess::Events::SourceEvent to attach what is required for reporting
37
- # to TeamServer to this Contrast::Agent::Reporting::FindingEventSource
38
- #
39
- # @param event [Contrast::Agent::Assess::Events::SourceEvent] the event to pull the source off of
40
- def attach_data event
41
- @name = event.source_name
42
- @type = event.source_type
22
+ # @param type [String]
23
+ # @param name [String]
24
+ def initialize type, name
25
+ @type = type
26
+ @name = name
43
27
  end
44
28
 
45
29
  # Convert the instance variables on the class, and other information, into the identifiers required for
@@ -61,6 +45,24 @@ module Contrast
61
45
  }
62
46
  end
63
47
 
48
+ # Convert this EventSource into the format expected for route observation
49
+ #
50
+ # @return [Hash]
51
+ # @raise [ArgumentError]
52
+ def to_controlled_observation_hash
53
+ begin
54
+ validate
55
+ rescue ArgumentError => e
56
+ logger.error('FindingEventSource observation validation failed with: ', e)
57
+ return
58
+ end
59
+
60
+ {
61
+ name: name, # rubocop:disable Security/Module/Name
62
+ type: type
63
+ }
64
+ end
65
+
64
66
  # @raise [ArgumentError]
65
67
  def validate
66
68
  raise(ArgumentError, "#{ self } did not have a proper type. Unable to continue.") unless type && !type.empty?
@@ -28,25 +28,12 @@ module Contrast
28
28
 
29
29
  AGENT_CLASS_MARKER = '/lib/contrast/'
30
30
 
31
- class << self
32
- # @param stack [String]
33
- # @return [Contrast::Agent::Reporting::FindingEventStack,nil]
34
- def convert stack
35
- return unless stack
36
- return if stack.include?(AGENT_CLASS_MARKER)
37
-
38
- report = new
39
- report.attach_data(stack)
40
- report
41
- end
42
- end
43
-
44
- # Parse the data from a Contrast::Agent::Assess::Tag to attach what is required for reporting to TeamServer to
45
- # this Contrast::Agent::Reporting::FindingEventTaintRange
31
+ # To play nice with the way that TeamServer is rendering these values, we only populate the file_name field with
32
+ # exactly what we want them to display.
46
33
  #
47
- # @param stack [String]
48
- def attach_data stack
49
- @file = stack
34
+ # @param file_name [String] the caller location this stack frame represents.
35
+ def initialize file_name
36
+ @file = file_name
50
37
  end
51
38
 
52
39
  # Convert the instance variables on the class, and other information, into the identifiers required for
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/agent/assess/tag'
5
+ require 'contrast/agent/reporting/reporting_events/finding_event_taint_range_tags'
5
6
  require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
@@ -2,13 +2,13 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Contrast
5
- module Api
6
- module Decorators
7
- # A holder for the valid tags that can be sent to the Service, and
8
- # ultimately TS, that we have to honor. Placed here so as not to clutter
9
- # other code.
10
- module TraceTaintRangeTags
5
+ module Agent
6
+ module Reporting
7
+ # A holder for the valid tags that can be sent to TeamServer that we have to honor. Placed here so as not to
8
+ # clutter other code.
9
+ module FindingEventTaintRangeTags
11
10
  # EventTagTypeDTM
11
+ # @return [Array<Symbol>]
12
12
  VALID_TAGS = %w[
13
13
  XML_ENCODED
14
14
  XML_DECODED
@@ -97,6 +97,7 @@ module Contrast
97
97
  DATABASE_WRITE
98
98
  ].cs__freeze
99
99
 
100
+ # @return [Array<Symbol>]
100
101
  VALID_SOURCE_TAGS = %w[NO_NEWLINES UNTRUSTED CROSS_SITE LIMITED_CHARS].cs__freeze
101
102
  end
102
103
  end
@@ -40,7 +40,7 @@ module Contrast
40
40
  # @return [Hash]
41
41
  attr_reader :cookies
42
42
  # REMOVE_DTM_REQUEST
43
- # @return [Contrast::Api::Dtm::RawRequest]
43
+ # @return [Contrast::Api::Dtm::HttpRequest]
44
44
  attr_reader :dtm
45
45
 
46
46
  class << self
@@ -11,7 +11,7 @@ module Contrast
11
11
  include Contrast::Components::Logger::InstanceMethods
12
12
 
13
13
  # @param [String] Sha256Sum of library as identified by the agent
14
- attr_accessor :id
14
+ attr_reader :id
15
15
  # @param [Array<String>] List of file paths that have been loaded out of or executed by the library
16
16
  attr_reader :names
17
17
 
@@ -24,7 +24,7 @@ module Contrast
24
24
  attr_accessor :url
25
25
  # @param [String] the HTTP Verb used to access the method in the route.
26
26
  attr_accessor :verb
27
- # @param [Array<Contrast::Agent::Reporting::TraceEventSource>] the sources of user input accessed during this
27
+ # @param [Array<Contrast::Agent::Reporting::FindingEventSource>] the sources of user input accessed during this
28
28
  # request. Used for remediation determinations in TeamServer.
29
29
  attr_reader :sources
30
30
 
@@ -56,7 +56,7 @@ module Contrast
56
56
 
57
57
  {
58
58
  session_id: ::Contrast::ASSESS.session_id,
59
- sources: @sources.map(&:to_controlled_hash),
59
+ sources: @sources.map(&:to_controlled_observation_hash),
60
60
  signature: @signature,
61
61
  verb: @verb,
62
62
  url: @url