contrast-agent 7.6.0 → 7.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '089a689fce3dfbc204455c12d29788d316553aa3ff6738fcf515e9f90730a7ae'
4
- data.tar.gz: 5fc2d10ffc084070fc3c268a9cb05d1f479b48cb16974b2501887cb1b762d6f6
3
+ metadata.gz: 8363c48e9a12500ea45f3d40389d6bf29d7931e01599a577dfb4026c9cedc260
4
+ data.tar.gz: 1c21202db2612d8715f1658fa9818442e16a5a51f613143a3c3c6b69c0a0fabf
5
5
  SHA512:
6
- metadata.gz: d13b3205d1e0cb67c8974fdf6d12f78e5a95f2886c59a14439ddc59b9dd8a3b0d0ebd23c5ebfe687d02cf1a12c9b17b127d821ea8131f0876ab284dac62c8b1b
7
- data.tar.gz: 73932d309fafe50ab5bc962655b58306cd5fae6a64729be1a4159274fe39c55c2138027c30525d07f773966476991685ba9b36cd0820527557d417324225af0d
6
+ metadata.gz: 4f5fe5203e78e7ea7c6e996c32367c340704f3d1544890b64ed856d3554ef53f3006cc948fab0f3d36108e1577d19196249c10ee8f0fcee95c8677115b7a4a64
7
+ data.tar.gz: 7a1d876e9c49940daf97589adaaf5d2550fdbd51bd2216f44a28bf4f97ab9431a5b5db200035089a76bfbe66bf8849aed58f382ee99e7e681e555b8da5097af5
@@ -73,7 +73,8 @@ module Contrast
73
73
  finding.routes << context.discovered_route if context&.discovered_route
74
74
  build_evidence(evidence, finding)
75
75
  finding.request = Contrast::Agent::Reporting::FindingRequest.convert(context.request) if context&.request
76
- hash = Contrast::Utils::HashDigest.generate_config_hash(finding)
76
+ # Hash must be built last so that finding has full context.
77
+ hash = Contrast::Utils::HashDigest.generate_response_hash(finding, context&.request)
77
78
  finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash)
78
79
  finding
79
80
  end
@@ -69,21 +69,46 @@ module Contrast
69
69
  # @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
70
70
  # child of the ReportingEvent rather than a literal one.
71
71
  # @param connection [Net::HTTP] open connection
72
- # @return response [Net::HTTPResponse, nil] response from TS if no response
73
72
  def send_event event, connection
74
73
  return unless connection
75
74
  return unless event.valid?
76
75
 
77
76
  logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
78
77
  request = build_request(event)
79
- response = connection.request(request)
78
+ begin
79
+ response = connection.request(request)
80
+ rescue StandardError => e
81
+ handle_response_error(event, connection, e)
82
+ return
83
+ end
80
84
  audit.audit_event(event, response) if ::Contrast::API.request_audit_enable
81
- process_settings_response(response, event)
82
- process_preflight_response(event, response, connection)
83
- report_configuration(response, event)
85
+ process_event_response(event, response, connection)
84
86
  response
85
87
  rescue StandardError => e
86
- handle_response_error(event, connection, e)
88
+ logger.error('[Reporter] Error while processing event sent to TeamServer',
89
+ error: e,
90
+ event_type: event&.cs__class)
91
+ end
92
+
93
+ # Only two types of events require processing when returned from TeamServer; preflight and settings.
94
+ # For Settings, we want to update internally and then report the resulting configuration.
95
+ # For preflight, we want to process the response and send findings if requested.
96
+ #
97
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] The event sent to TeamServer
98
+ # @param response [Net::HTTPResponse] the response from TeamServer
99
+ # @param connection [Net::HTTP] open connection
100
+ def process_event_response event, response, connection
101
+ case event
102
+ when Contrast::Agent::Reporting::Preflight
103
+ process_preflight_response(event, response, connection)
104
+ when Contrast::Agent::Reporting::AgentStartup,
105
+ Contrast::Agent::Reporting::ApplicationStartup,
106
+ Contrast::Agent::Reporting::ApplicationSettings,
107
+ Contrast::Agent::Reporting::ServerSettings
108
+
109
+ process_settings_response(response, event)
110
+ report_configuration(response, event)
111
+ end
87
112
  end
88
113
 
89
114
  # Write effective config to file:
@@ -91,7 +116,7 @@ module Contrast
91
116
  # 200 or 304. In case of 304 there will be no new settings and we can write current ones.
92
117
  # This is done on every settings request.
93
118
  #
94
- # @param response [Contrast::Agent::Reporting::Response, nil]
119
+ # @param response [Net::HTTPResponse, nil]
95
120
  # @param event [Contrast::Agent::Reporting::ReportingEvent]
96
121
  def report_configuration response, event
97
122
  return unless response
@@ -109,14 +134,17 @@ module Contrast
109
134
  logger.error('[Reporter] Error while reporting configuration', error: e, event_type: event&.cs__class)
110
135
  end
111
136
 
137
+ # @return [Contrast::Agent::Reporting::ConnectionStatus]
112
138
  def status
113
139
  @_status ||= Contrast::Agent::Reporting::ConnectionStatus.new
114
140
  end
115
141
 
142
+ # @return [Contrast::Agent::Reporting::ResponseHandler]
116
143
  def response_handler
117
144
  @_response_handler ||= Contrast::Agent::Reporting::ResponseHandler.new
118
145
  end
119
146
 
147
+ # @return [Contrast::Config::Diagnostics::Monitor]
120
148
  def diagnostics
121
149
  @_diagnostics ||= Contrast::Config::Diagnostics::Monitor.new(Contrast::LOGGER.path)
122
150
  end
@@ -91,6 +91,7 @@ module Contrast
91
91
  #
92
92
  # @param event [Contrast::Agent::Reporting::ReportingEvent] The event sent to TeamServer.
93
93
  # @param response [Net::HTTPResponse]
94
+ # @return [Contrast::Agent::Reporting::Response]
94
95
  def process_settings_response response, event
95
96
  res = response_handler.process(response, event)
96
97
  if res
@@ -115,7 +116,6 @@ module Contrast
115
116
  return unless response&.body && connection
116
117
 
117
118
  findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
118
- mode.resend.reset_rescue_attempts
119
119
  findings_to_return.each do |index|
120
120
  preflight_message = event.messages[index.to_i]
121
121
  preflight_data = preflight_message&.data
@@ -127,6 +127,12 @@ module Contrast
127
127
 
128
128
  send_event(corresponding_finding, connection)
129
129
  end
130
+
131
+ # Event rejected traces should be removed from the set.
132
+ # We could clean this up to know if the message was already deleted by the loop above.
133
+ event.messages&.each do |preflight_message|
134
+ Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message&.data)
135
+ end
130
136
  rescue StandardError => e
131
137
  logger.error('[Reporter] Unable to handle preflight response', e)
132
138
  end
@@ -44,12 +44,7 @@ module Contrast
44
44
  def delete key
45
45
  return unless key
46
46
 
47
- logger.debug('Starting deleting value for', key: key)
48
-
49
- deleted_value = collection.delete(key)
50
- logger.debug('Key wasn\'t found') unless deleted_value
51
-
52
- deleted_value
47
+ collection.delete(key)
53
48
  end
54
49
 
55
50
  # @param rule_id [String] the rule_id
@@ -25,6 +25,7 @@ module Contrast
25
25
  # @return response [Net::HTTPResponse, nil]
26
26
  def process response, event
27
27
  logger.debug('[Reporter] Received a response')
28
+ return if event&.cs__is_a?(Contrast::Agent::Reporting::Finding)
28
29
  return unless analyze_response?(response)
29
30
 
30
31
  # Handle the response body and obtain server_features or app_settings
@@ -14,7 +14,6 @@ module Contrast
14
14
  include Contrast::Agent::Reporting::NgResponseExtractor
15
15
  include Contrast::Agent::Reporting::ResponseExtractor
16
16
 
17
- ANALYZE_WHEN = %w[200 204].cs__freeze
18
17
  ERROR_CODES = {
19
18
  message_not_sent: '400',
20
19
  access_forbidden: '401',
@@ -112,11 +111,10 @@ module Contrast
112
111
  # used for in observed routes message.
113
112
  return false unless response && (response_code = response&.code)
114
113
 
115
- # We still need to check the response code even if we are not analyzing it, since the 304 code does not
116
- # contain settings to be extracted but we still need to know for the diagnostics. Do not move this bellow
117
- # the ANALYZE_WHEN check.
118
114
  @_last_response_code = response_code
119
- return true if ANALYZE_WHEN.include?(response_code)
115
+ return true if response_code == '200'
116
+ return false if response_code == '204'
117
+ return false if response_code == '304'
120
118
 
121
119
  handle_error(response) if ERROR_CODES.value?(response_code) && response&.body
122
120
  # There was error, so analyze the Error and nothing more.
@@ -267,7 +265,7 @@ module Contrast
267
265
  # @return response [Contrast::Agent::Reporting::Response]
268
266
  def convert_response response, event
269
267
  response_body = response&.body
270
- return unless response_body
268
+ return unless response_body && !response_body.blank?
271
269
 
272
270
  response_data = Contrast::Utils::Json.parse(response_body, deep_symbolize: true)
273
271
  return unless response_data.cs__is_a?(Hash)
@@ -180,7 +180,7 @@ module Contrast
180
180
  end
181
181
  end
182
182
 
183
- # returns or fenerates the hash checksum for the request
183
+ # returns or generates the hash checksum for the request
184
184
  #
185
185
  # @return @_hash_id [String] Contrast::Utils::HashDigest generated string checksum
186
186
  def hash_id
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '7.6.0'
6
+ VERSION = '7.6.1'
7
7
  end
8
8
  end
@@ -15,7 +15,6 @@ module Contrast
15
15
  class HashDigest < Digest::Class
16
16
  include Digest::Instance
17
17
  extend Contrast::Utils::HashDigestExtend
18
- CONTENT_LENGTH_HEADER = 'Content-Length'
19
18
  CHARS = %w[a b c d e f g].cs__freeze
20
19
  CRYPTO_RULES = %w[crypto-bad-ciphers crypto-bad-mac].cs__freeze
21
20
  CONFIG_PATH_KEY = 'path'
@@ -34,8 +33,6 @@ module Contrast
34
33
  #
35
34
  # @param finding [Contrast::Agent::Reporting::Finding] finding to be reported
36
35
  # @param request [Contrast::Agent::Request] our wrapper around the Rack::Request.
37
- # @return checksum [Integer, nil] returns nil if there is no request context or tracking
38
- # is disabled.
39
36
  def update_on_request finding, request
40
37
  context = Contrast::Agent::REQUEST_TRACKER.current
41
38
  return unless context || ::Contrast::ASSESS.non_request_tracking?
@@ -58,7 +55,6 @@ module Contrast
58
55
  # Update to CRC checksum the event source name and source type.
59
56
  #
60
57
  # @param events [Array<Contrast::Agent::Reporting::FindingEvent>]
61
- # @return checksum [Integer, nil] returns nil if there is no events
62
58
  def update_on_sources events
63
59
  events.each do |event|
64
60
  event.event_sources.each do |source|
@@ -68,22 +64,12 @@ module Contrast
68
64
  end
69
65
  end
70
66
 
71
- # This method converts and integer value for length into a string value
72
- # that we can hash on, based on the logarithmic value of the length, and
73
- # updates the current hash with that value.
74
- # @param chr [Numeric] the length to translate
75
- def update_on_content_length chr
76
- update(CHARS[Math.log10(chr.to_s.length).to_i] || CHARS[-1])
77
- end
78
-
79
67
  # Converts given string to CRC checksum. CRC32 checksum ensures that If error
80
68
  # of a single bit occurs, the CRC checksum will fail, regardless of any other
81
69
  # property of the transmitted data, including its length. Called several times
82
70
  # with previous CRC to recalculate the new output.
83
71
  #
84
72
  # @param str [String]
85
- # @return @crc32 [Integer, nil] updated value of crc 32 bit integer checksum or
86
- # nil if passed string is nil or empty
87
73
  def update str
88
74
  return unless str
89
75
 
@@ -17,7 +17,7 @@ module Contrast
17
17
  # param names and content length to CRC checksum and returns string representation
18
18
  #
19
19
  # @param request [Contrast::Agent::Request] our wrapper around the Rack::Request.
20
- # @return checksum [String] String representation of CRC32 checksum
20
+ # @return [String] String representation of CRC32 checksum
21
21
  def generate_request_hash request
22
22
  hash = new
23
23
  hash.update(request.request_method)
@@ -25,8 +25,6 @@ module Contrast
25
25
  request.parameters.each_key do |name|
26
26
  hash.update(name)
27
27
  end
28
- cl = request.headers[Contrast::Utils::HashDigest::CONTENT_LENGTH_HEADER]
29
- hash.update_on_content_length(cl) if cl
30
28
  hash.finish
31
29
  end
32
30
 
@@ -37,7 +35,7 @@ module Contrast
37
35
  # @param finding [Contrast::Agent::Reporting::Finding] to be reported
38
36
  # @param source [Object] the source of the Trigger Event
39
37
  # @param request [Contrast::Agent::Request] our wrapper around the Rack::Request.
40
- # @return checksum [String] String representation of CRC32 checksum
38
+ # @return [String] String representation of CRC32 checksum
41
39
  def generate_event_hash finding, source, request
42
40
  return generate_dataflow_hash(finding, request) if finding.events.length.to_i > 1
43
41
 
@@ -51,7 +49,7 @@ module Contrast
51
49
  # to CRC32 checksum and returns string representation to be appended to Contrast::Api::Dtm::Finding
52
50
  #
53
51
  # @param finding [Contrast::Agent::Reporting::Finding] to be reported
54
- # @return checksum [String] String representation of CRC32 checksum.
52
+ # @return [String] String representation of CRC32 checksum.
55
53
  def generate_config_hash finding
56
54
  hash = new
57
55
  hash.update(finding.rule_id)
@@ -80,6 +78,19 @@ module Contrast
80
78
  hash.finish
81
79
  end
82
80
 
81
+ # Generates the hash checksum for response scanning. Converts the rule_id and request to CRC32 checksum and
82
+ # returns string representation.
83
+ #
84
+ # @param finding [Contrast::Agent::Reporting::Finding] to be reported
85
+ # # @param request [Contrast::Agent::Request]
86
+ # @return [String] String representation of CRC32 checksum.
87
+ def generate_response_hash finding, request
88
+ hash = new
89
+ hash.update(finding.rule_id)
90
+ hash.update_on_request(finding, request)
91
+ hash.finish
92
+ end
93
+
83
94
  private
84
95
 
85
96
  # Generates the hash checksum for crypto(crypto-bad-ciphers, crypto-bad-mac) rules.
@@ -14,7 +14,7 @@ module Contrast
14
14
 
15
15
  # Add any known cases where parsing error might arise from older json parser:
16
16
  # @return [Array<String>]
17
- SPECIAL_CASES = ["\"\"", "\"0\""].cs__freeze # rubocop:disable Style/StringLiterals
17
+ SPECIAL_CASES = [nil, "", "\"\"", "\"0\""].cs__freeze # rubocop:disable Style/StringLiterals
18
18
 
19
19
  # Parses a string using JSON.parser. This method is used instead of standard JSON.parse to
20
20
  # support older versions of json gem => not supporting key-value second parameter, which is
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrast-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.6.0
4
+ version: 7.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ruby@contrastsecurity.com
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-11 00:00:00.000000000 Z
11
+ date: 2024-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -1395,7 +1395,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1395
1395
  - !ruby/object:Gem::Version
1396
1396
  version: '0'
1397
1397
  requirements: []
1398
- rubygems_version: 3.3.26
1398
+ rubygems_version: 3.3.27
1399
1399
  signing_key:
1400
1400
  specification_version: 4
1401
1401
  summary: Contrast Security's agent for rack-based applications.