Class: Contrast::Agent::Assess::Policy::TriggerNode
- Inherits:
-
PolicyNode
- Object
- Patching::Policy::PolicyNode
- PolicyNode
- Contrast::Agent::Assess::Policy::TriggerNode
- Defined in:
- lib/contrast/agent/assess/policy/trigger_node.rb
Overview
This class functions to translate our policy.json into an actionable Ruby object, allowing for dynamic patching over hardcoded patching, specifically for those methods which result in the trigger of a vulnerability (indicate points in the application where uncontrolled user input can do damage).
Constant Summary collapse
- JSON_BAD_VALUE =
'bad_value'- JSON_GOOD_VALUE =
'good_value'- JSON_DISALLOWED_TAGS =
'disallowed_tags'- JSON_REQUIRED_TAGS =
'required_tags'- JSON_RULE_NAME =
'name'- JSON_CUSTOM_PATCH =
'custom_patch'- TRIGGER =
'Trigger'
Constants inherited from PolicyNode
PolicyNode::ALL_TYPE, PolicyNode::JSON_DATAFLOW, PolicyNode::JSON_SOURCE, PolicyNode::JSON_TAGS, PolicyNode::JSON_TARGET, PolicyNode::TO_MARKER
Instance Attribute Summary collapse
-
#bad_value ⇒ Object
readonly
Returns the value of attribute bad_value.
-
#disallowed_tags ⇒ Object
readonly
Returns the value of attribute disallowed_tags.
-
#good_value ⇒ Object
readonly
Returns the value of attribute good_value.
-
#required_tags ⇒ Object
readonly
Returns the value of attribute required_tags.
-
#rule_id ⇒ Object
readonly
Returns the value of attribute rule_id.
Attributes inherited from PolicyNode
#source_string, #sources, #tags, #target_string, #targets, #type
Attributes inherited from Patching::Policy::PolicyNode
#class_name, #instance_method, #method_name, #method_scope, #method_visibility, #properties
Instance Method Summary collapse
- #apply_custom_trigger(context, trigger_node, source, object, ret, *args) ⇒ Object
- #custom_patch? ⇒ Boolean
- #custom_trigger? ⇒ Boolean
- #custom_trigger_class ⇒ Object
-
#dataflow? ⇒ Boolean
Indicate if this is a dataflow based trigger, meaning it has a proper synch that requires a tainted source to reach it.
-
#initialize(trigger_hash = {}, rule_hash = {}) ⇒ TriggerNode
constructor
A new instance of TriggerNode.
-
#loud_name ⇒ Object
the name of the rule, in capital & underscore format used to make it match enum things in TeamServer.
- #node_class ⇒ Object
- #node_type ⇒ Object
-
#regexp_rule? ⇒ Boolean
Indicate if this is a regexp based trigger, meaning it has a proper synch that requires a source to reach it.
- #rule_disabled? ⇒ Boolean
-
#validate ⇒ Object
Standard validation + TS trace version two rules: Must have source.
-
#violated?(source) ⇒ Boolean
Determine if a dataflow rule violation has occurred.
Methods inherited from PolicyNode
#add_property, #build_action, #feature, #generate_sources, #generate_targets, #get_property, #target, #validate_tags
Methods inherited from Patching::Policy::PolicyNode
#feature, #id, #instance_method?
Methods included from Components::Interface
Constructor Details
#initialize(trigger_hash = {}, rule_hash = {}) ⇒ TriggerNode
Returns a new instance of TriggerNode.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 27 def initialize trigger_hash = {}, rule_hash = {} super(trigger_hash) good_value = trigger_hash[JSON_GOOD_VALUE] bad_value = trigger_hash[JSON_BAD_VALUE] @good_value = Regexp.new(good_value, true) if good_value @bad_value = Regexp.new(bad_value, true) if bad_value @regexp = !@dataflow && (@good_value || @bad_value) @custom_patch = trigger_hash.fetch(JSON_CUSTOM_PATCH, false) @rule_id = rule_hash.fetch(JSON_RULE_NAME) # raises KeyError exception if not found @dataflow = rule_hash.fetch(JSON_DATAFLOW, true) = (rule_hash[JSON_REQUIRED_TAGS]) = populate_disallowed(rule_hash[JSON_DISALLOWED_TAGS]) @trigger_class = trigger_hash['trigger_class'] @trigger_method = trigger_hash['trigger_method'] @trigger_method = @trigger_method.to_sym if @trigger_method validate end |
Instance Attribute Details
#bad_value ⇒ Object (readonly)
Returns the value of attribute bad_value.
25 26 27 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 25 def bad_value @bad_value end |
#disallowed_tags ⇒ Object (readonly)
Returns the value of attribute disallowed_tags.
25 26 27 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 25 def end |
#good_value ⇒ Object (readonly)
Returns the value of attribute good_value.
25 26 27 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 25 def good_value @good_value end |
#required_tags ⇒ Object (readonly)
Returns the value of attribute required_tags.
25 26 27 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 25 def end |
#rule_id ⇒ Object (readonly)
Returns the value of attribute rule_id.
25 26 27 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 25 def rule_id @rule_id end |
Instance Method Details
#apply_custom_trigger(context, trigger_node, source, object, ret, *args) ⇒ Object
50 51 52 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 50 def apply_custom_trigger context, trigger_node, source, object, ret, *args custom_trigger_class.send(@trigger_method, context, trigger_node, source, object, ret, *args) end |
#custom_patch? ⇒ Boolean
62 63 64 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 62 def custom_patch? @custom_patch end |
#custom_trigger? ⇒ Boolean
58 59 60 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 58 def custom_trigger? @trigger_class && @trigger_method end |
#custom_trigger_class ⇒ Object
54 55 56 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 54 def custom_trigger_class @_custom_trigger_class ||= Object.cs__const_get(@trigger_class) end |
#dataflow? ⇒ Boolean
Indicate if this is a dataflow based trigger, meaning it has a proper synch that requires a tainted source to reach it. If this returns false, this rule is for method validation, ensuring that an insecure method, such as a non-cryptographically secure random, is not invoked
78 79 80 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 78 def dataflow? @dataflow end |
#loud_name ⇒ Object
the name of the rule, in capital & underscore format used to make it match enum things in TeamServer
93 94 95 96 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 93 def loud_name @_loud_name ||= rule_id.upcase.gsub(Contrast::Utils::ObjectShare::DASH, Contrast::Utils::ObjectShare::UNDERSCORE) end |
#node_class ⇒ Object
46 47 48 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 46 def node_class TRIGGER end |
#node_type ⇒ Object
66 67 68 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 66 def node_type :TYPE_METHOD end |
#regexp_rule? ⇒ Boolean
Indicate if this is a regexp based trigger, meaning it has a proper synch that requires a source to reach it. While this type of rule does not require the source to be tainted, it does validate it with a regular expression to determine if the method is being invoked safely.
87 88 89 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 87 def regexp_rule? @regexp end |
#rule_disabled? ⇒ Boolean
70 71 72 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 70 def rule_disabled? ASSESS.rule_disabled?(rule_id) end |
#validate ⇒ Object
Standard validation + TS trace version two rules: Must have source
124 125 126 127 128 129 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 124 def validate super # If this isn't a dataflow rule, it can't have a source return unless dataflow? raise(ArgumentError, "Trigger #{ id } did not have a proper source. Unable to create.") unless sources&.any? end |
#violated?(source) ⇒ Boolean
Determine if a dataflow rule violation has occurred
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/contrast/agent/assess/policy/trigger_node.rb', line 99 def violated? source # if the source isn't tracked, there can't be a violation # this condition may not hold true forever, but for now it's # a nice optimization return false unless Contrast::Agent::Assess::Tracker.tracked?(source) properties = Contrast::Agent::Assess::Tracker.properties(source) # find the ranges that violate the rule (untrusted, etc) vulnerable_ranges = (Contrast::Utils::StringUtils.ret_length(source), properties, ) # if there aren't any vulnerable ranges, nope out return false if vulnerable_ranges.empty? # find the ranges that are exempt from the rule # (validated, sanitized, etc) secure_ranges = ranges_with_any_tag(properties, ) # if there are vulnerable ranges and no secure, report return true if secure_ranges.empty? # figure out if there are any vulnerable ranges that aren't # covered by a secure one. if there are, the rule was violated !Contrast::Utils::TagUtil.covered?(vulnerable_ranges, secure_ranges) end |