Module: Contrast::Agent::Assess::Policy::TriggerMethod

Extended by:
Components::Logger::InstanceMethods, Utils::Assess::EventLimitUtils, Utils::Assess::TriggerMethodUtils
Included in:
Patching::Policy::Patch
Defined in:
lib/contrast/agent/assess/policy/trigger_method.rb

Overview

A trigger method is one which can perform a dangerous action, as described by the Contrast::Agent::Assess::Policy::TriggerNode class. Each such method will call to this module just after invocation in order to determine if the call was done safely. In those cases where it was not, a Finding report is issued to TeamServer.

Constant Summary collapse

NON_REQUEST_RULES =

Rules that always exists outside of Request Context

[
  'hardcoded-password', # Contrast::Agent::Assess::Rule::Provider::HardcodedPassword.NAME,
  'hardcoded-key' # Contrast::Agent::Assess::Rule::Provider::HardcodedKey.NAME
].cs__freeze

Class Method Summary collapse

Methods included from Components::Logger::InstanceMethods

cef_logger, logger

Methods included from Utils::Assess::TriggerMethodUtils

apply_dataflow_rule, apply_regexp_rule, apply_trigger, find_event_request, find_request, reportable?

Methods included from Utils::Assess::EventLimitUtils

event_limit?, event_limit_for_rule?, increment_event_count

Class Method Details

.apply_eval_trigger(trigger_node, source, object, ret, *args) ⇒ Object



73
74
75
# File 'lib/contrast/agent/assess/policy/trigger_method.rb', line 73

def apply_eval_trigger trigger_node, source, object, ret, *args
  apply_trigger(trigger_node, source, object, ret, *args)
end

.apply_trigger_rule(trigger_node, object, ret, args) ⇒ Object

This is called from within our woven proc. It will be called as if it were inline in the Rack application.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/contrast/agent/assess/policy/trigger_method.rb', line 49

def apply_trigger_rule trigger_node, object, ret, args
  return if trigger_node.nil?
  return if event_limit_for_rule?(trigger_node.rule_id)

  context = Contrast::Agent::REQUEST_TRACKER.current
  # return if there is no context and the flag is set to default => false
  # we need to have request if the flag is default
  # else proceed, if the flag is true we don't need to check for context we
  # go as currently.
  # When outside of a request, only track when the feature is enabled
  return unless context ||
      Contrast::ASSESS.non_request_tracking? ||
      NON_REQUEST_RULES.include?(trigger_node.rule_id)

  if trigger_node.sources&.any?
    trigger_node.sources.each do |marker|
      source = determine_source(marker, object, ret, args)
      apply_trigger(trigger_node, source, object, ret, *args)
    end
  else
    apply_trigger(trigger_node, nil, object, ret, *args)
  end
end

.build_finding(trigger_node, source, object, ret, *args) ⇒ Contrast::Agent::Reporting::Finding?

This converts the source of the finding, and the events leading up to it into a Finding



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/contrast/agent/assess/policy/trigger_method.rb', line 86

def build_finding trigger_node, source, object, ret, *args
  content_type = Contrast::Agent::REQUEST_TRACKER.current&.response&.content_type
  if content_type.nil? && trigger_node.collectable?
    Contrast::Agent::FINDINGS.collect_finding(trigger_node, source, object, ret, *args)
    return
  end
  return unless Contrast::Agent::Assess::Policy::TriggerValidation.valid?(trigger_node, object, ret, args)

  request = find_request(source)
  return unless reportable?(request&.env)
  return if excluded_by_url_and_rule?(trigger_node.rule_id)

  finding = Contrast::Agent::Reporting::Finding.new(trigger_node.rule_id)
  finding.attach_data(trigger_node, source, object, ret, request, *args)
  return if excluded_by_input_and_rule?(finding, trigger_node.rule_id)

  finding.hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source, request)
  check_for_stored_xss(finding)
  finding
rescue StandardError => e
  logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id)
  nil
end

.report_finding(finding) ⇒ Object

Given a finding, append it to an activity message and send it to the TeamServer for processing. If an activity message does not exist, b/c we’re invoked outside of a request context, build an activity and immediately report it with the finding.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/contrast/agent/assess/policy/trigger_method.rb', line 115

def report_finding finding
  return unless finding

  preflight = Contrast::Agent::Reporting::BuildPreflight.generate(finding)
  return unless preflight

  preflight_data = preflight.messages[0].data
  return if Contrast::Agent::REQUEST_TRACKER.current&.reported_findings&.include?(preflight_data)

  Contrast::Agent::Reporting::ReportingStorage[preflight.messages[0].data] = finding
  if Contrast::Agent::REQUEST_TRACKER.current
    Contrast::Agent::REQUEST_TRACKER.current.reported_findings << preflight_data
  end
  Contrast::Agent.reporter&.send_event(preflight)
end