# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/protect/rule/cmd_injection' require 'contrast/agent/protect/rule/deserialization' require 'contrast/agent/protect/rule/no_sqli' require 'contrast/agent/reporting/attack_result/user_input' require 'contrast/agent/reporting/attack_result/response_type' require 'contrast/components/logger' module Contrast module Agent module Reporting # This is the new ApplicationDefendAttackSample class which includes a samples of an attack for the given rule of # the given result observed in the activity period. class ApplicationDefendAttackSample include Contrast::Agent::Reporting::InputType # @return [Contrast::Agent::Reporting::UserInput] attr_accessor :user_input # @return [Array] attr_reader :stack # Details are per rule specific and should be set when the sample is build # # @return [Contrast::Agent::Reporting::Details::ProtectRuleDetails, {}] attr_accessor :details # @return [Integer] time in ms attr_accessor :time_stamp class << self # @param attack_result [Contrast::Agent::Reporting::AttackResult] # @param attack_sample [Contrast::Agent::Reporting::ApplicationDefendAttackSample] def convert attack_result, attack_sample activity = new activity.attach_data(attack_result, attack_sample) activity end end def initialize @time_stamp = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 # in ms @blocked = false @event_type = :application_defend_attack_sample @user_input = Contrast::Agent::Reporting::UserInput.new @request = Contrast::Agent::REQUEST_TRACKER.current&.activity&.request @stack = Contrast::Utils::StackTraceUtils.build_protect_report_stack_array @details = {} end def to_controlled_hash { blocked: @blocked, input: build_input(@user_input), details: @details&.to_controlled_hash, request: @request&.to_controlled_hash, stack: @stack&.map(&:to_controlled_hash), timestamp: build_time_stamp } end # @param response_type [Contrast::Agent::Reporting::ResponseType] # @return [Boolean] check if response type is blocked def blocked? response_type @blocked = response_type == Contrast::Agent::Reporting::ResponseType::BLOCKED end # @param user_input [Contrast::Agent::Reporting::UserInput] def build_input user_input { documentPath: user_input.path, documentType: user_input.document_type.to_s, filters: user_input.matcher_ids, name: user_input.key, time: time_stamp, type: user_input.input_type.to_s, value: user_input.value } end # @param attack_result [Contrast::Agent::Reporting::AttackResult] # @param attack_sample [Contrast::Agent::Reporting::RaspRuleSample] def attach_data attack_result, attack_sample @blocked = attack_result.response == ::Contrast::Agent::Reporting::ResponseType::BLOCKED @user_input = attack_sample.user_input @details = attack_sample.details @time_stamp = attack_sample.time_stamp @request = FindingRequest.convert(Contrast::Agent::REQUEST_TRACKER.current&.request) @stack = Contrast::Utils::StackTraceUtils.build_protect_report_stack_array end # @return [Hash] def build_time_stamp { start: time_stamp, elapsed: Contrast::Utils::Timer.now_ms - time_stamp } end end end end end