Class: Contrast::Agent::Protect::Rule::NoSqli

Inherits:
BaseService show all
Defined in:
lib/contrast/agent/protect/rule/no_sqli.rb,
lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb

Overview

The Ruby implementation of the Protect NoSQL Injection rule.

Defined Under Namespace

Classes: MongoNoSqlScanner

Constant Summary collapse

NAME =
'nosql-injection'
BLOCK_MESSAGE =
'NoSQLi rule triggered. Response blocked.'

Constants inherited from Base

Base::BLOCKING_MODES, Base::OFF, Base::POSTFILTER_MODES, Base::STACK_COLLECTION_RESULTS, Base::UNKNOWN_USER_INPUT

Instance Attribute Summary

Attributes inherited from Base

#mode

Instance Method Summary collapse

Methods inherited from BaseService

#infilter?, #postfilter

Methods inherited from Base

#append_to_activity, #build_attack_without_match, #enabled?, #excluded?, #infilter?, #initialize, #postfilter, #prefilter, #stream_safe?

Methods included from Components::Interface

included

Constructor Details

This class inherits a constructor from Contrast::Agent::Protect::Rule::Base

Instance Method Details

#block_messageObject



19
20
21
# File 'lib/contrast/agent/protect/rule/no_sqli.rb', line 19

def block_message
  BLOCK_MESSAGE
end

#build_attack_with_match(context, input_analysis_result, result, query_string, **kwargs) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/contrast/agent/protect/rule/no_sqli.rb', line 34

def build_attack_with_match context, input_analysis_result, result, query_string, **kwargs
  return result if mode == :NO_ACTION || mode == :PERMIT

  attack_string = input_analysis_result.value
  regexp = Regexp.new(Regexp.escape(attack_string), Regexp::IGNORECASE)
  return nil unless query_string.match?(regexp)

  scanner = select_scanner
  ss = StringScanner.new(query_string)
  length = attack_string.length
  while ss.scan_until(regexp)
    # the pos of StringScanner is at the end of the regexp (input string),
    # we need the beginning
    idx = ss.pos - attack_string.length
    last_boundary, boundary = scanner.crosses_boundary(query_string, idx, input_analysis_result.value)
    next unless last_boundary && boundary

    kwargs[:start_idx] = idx
    kwargs[:end_idx] = idx + length
    kwargs[:boundary_overrun_idx] = boundary
    kwargs[:input_boundary_idx] = last_boundary

    result ||= build_attack_result(context)
    update_successful_attack_response(context, input_analysis_result, result, query_string)
    append_sample(context, input_analysis_result, result, query_string, **kwargs)
  end

  result
end

#infilter(context, database, query_string) ⇒ Object



23
24
25
26
27
28
29
30
31
32
# File 'lib/contrast/agent/protect/rule/no_sqli.rb', line 23

def infilter context, database, query_string
  return nil unless infilter?(context)

  result = find_attacker(context, query_string, database: database)
  return nil unless result

  append_to_activity(context, result)

  raise Contrast::SecurityException.new(self, BLOCK_MESSAGE) if blocked?
end

#nameObject



15
16
17
# File 'lib/contrast/agent/protect/rule/no_sqli.rb', line 15

def name
  NAME
end