# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true cs__scoped_require 'contrast/components/interface' module Contrast module CoreExtensions module Protect # This Module is how we apply the NoSQL Injection rule. It is called from # our patches of the targeted methods in which the execution of String # based NoSQL queries occur. It is responsible for deciding if the # infilter methods of the rule should be invoked. module AppliesNoSqliRule DATABASE_MONGO = 'MongoDB' ACTION_DISPATCH = 'dispatch' ACTION_READ = 'read' ACTION_WRITE = 'write' ACTION_PROCESS = 'process' class << self include Contrast::Components::Interface access_component :logging, :analysis def apply_nosql_rule method, _exception, properties, _object, args return unless valid_input?(args) return if skip_analysis? database = properties['database'] operations = args[0] context = Contrast::Agent::REQUEST_TRACKER.current if operations.is_a?(Array) operations.each do |m| handle_operation(context, database, method, m) end else handle_operation(context, database, method, operations) end rescue Contrast::SecurityException => e raise e rescue StandardError => e logger.error(e, "Error running NoSQLi rule in #{ properties['database'] }") end private def rule PROTECT.rule Contrast::Agent::Protect::Rule::NoSqli::NAME end def valid_input? args return false unless args&.any? args[0] end def skip_analysis? context = Contrast::Agent::REQUEST_TRACKER.current return true unless context&.app_loaded? return true unless rule&.enabled? false end def handle_operation context, database, action, operation data = extract_mongo_data(operation) return unless data && !data.empty? logger.debug(nil, "applying nosqli rule #{ database }##{ action }") rule.infilter(context, database, data) end def extract_mongo_data operation if operation.cs__respond_to? :selector operation.selector elsif operation.cs__respond_to? :documents operation.documents end end end end end end end