contrast-agent 7.3.2 → 7.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/contrast/agent/middleware/middleware.rb +1 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +9 -11
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +55 -20
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -4
- data/lib/contrast/agent/protect/rule/base.rb +61 -26
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +12 -4
- data/lib/contrast/agent/protect/rule/cmdi/cmd_injection.rb +19 -15
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +2 -4
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +2 -1
- data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +4 -4
- data/lib/contrast/agent/protect/rule/input_classification/base.rb +7 -2
- data/lib/contrast/agent/protect/rule/input_classification/encoding.rb +1 -1
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +5 -2
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal.rb +20 -8
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +2 -2
- data/lib/contrast/agent/protect/rule/sqli/sqli.rb +8 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +2 -3
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +3 -4
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload.rb +3 -0
- data/lib/contrast/agent/protect/rule/utils/builders.rb +3 -4
- data/lib/contrast/agent/protect/rule/utils/filters.rb +32 -16
- data/lib/contrast/agent/protect/rule/xss/xss.rb +80 -0
- data/lib/contrast/agent/protect/rule/xxe/xxe.rb +9 -2
- data/lib/contrast/agent/protect/state.rb +110 -0
- data/lib/contrast/agent/reporting/details/xss_match.rb +17 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +32 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +2 -0
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +2 -0
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +1 -4
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +4 -0
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +2 -0
- data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +2 -0
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +9 -8
- data/lib/contrast/agent/reporting/reporting_events/reportable_hash.rb +30 -6
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -5
- data/lib/contrast/agent/reporting/settings/protect.rb +3 -3
- data/lib/contrast/agent/reporting/settings/sampling.rb +5 -4
- data/lib/contrast/agent/request/request_context_extend.rb +0 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/agent.rb +3 -5
- data/lib/contrast/components/api.rb +3 -3
- data/lib/contrast/components/assess.rb +4 -0
- data/lib/contrast/components/assess_rules.rb +1 -2
- data/lib/contrast/components/base.rb +1 -2
- data/lib/contrast/components/config/sources.rb +23 -0
- data/lib/contrast/components/logger.rb +19 -0
- data/lib/contrast/components/protect.rb +55 -14
- data/lib/contrast/components/sampling.rb +5 -12
- data/lib/contrast/components/security_logger.rb +17 -0
- data/lib/contrast/components/settings.rb +110 -76
- data/lib/contrast/config/certification_configuration.rb +1 -1
- data/lib/contrast/config/configuration_files.rb +0 -2
- data/lib/contrast/config/diagnostics/config.rb +3 -3
- data/lib/contrast/config/diagnostics/effective_config.rb +1 -1
- data/lib/contrast/config/diagnostics/environment_variables.rb +21 -11
- data/lib/contrast/config/diagnostics/monitor.rb +1 -1
- data/lib/contrast/config/diagnostics/singleton_tools.rb +170 -0
- data/lib/contrast/config/diagnostics/source_config_value.rb +14 -9
- data/lib/contrast/config/diagnostics/tools.rb +23 -84
- data/lib/contrast/config/request_audit_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +3 -15
- data/lib/contrast/configuration.rb +5 -2
- data/lib/contrast/framework/manager.rb +4 -3
- data/lib/contrast/framework/manager_extend.rb +3 -1
- data/lib/contrast/framework/rack/support.rb +11 -2
- data/lib/contrast/framework/rails/support.rb +2 -2
- data/lib/contrast/logger/cef_log.rb +30 -4
- data/lib/contrast/utils/io_util.rb +3 -0
- data/lib/contrast/utils/log_utils.rb +22 -11
- data/lib/contrast/utils/request_utils.rb +1 -1
- data/lib/contrast/utils/timer.rb +1 -1
- metadata +4 -2
@@ -422,6 +422,8 @@ module Contrast
|
|
422
422
|
raise(ArgumentError, "#{ self } did not have a proper thread. Unable to continue.") unless thread
|
423
423
|
raise(ArgumentError, "#{ self } did not have a proper time. Unable to continue.") unless time
|
424
424
|
raise(ArgumentError, "#{ self } did not have a proper type. Unable to continue.") unless type
|
425
|
+
|
426
|
+
nil
|
425
427
|
end
|
426
428
|
|
427
429
|
# @raise [ArgumentError]
|
@@ -435,6 +437,8 @@ module Contrast
|
|
435
437
|
raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
|
436
438
|
raise(ArgumentError, "#{ self } did not have a proper stack. Unable to continue.") unless stack
|
437
439
|
raise(ArgumentError, "#{ self } did not have a proper tags. Unable to continue.") unless reportable_tags
|
440
|
+
|
441
|
+
nil
|
438
442
|
end
|
439
443
|
end
|
440
444
|
end
|
@@ -108,6 +108,8 @@ module Contrast
|
|
108
108
|
raise(ArgumentError, "#{ self } did not have a proper method. Unable to continue.")
|
109
109
|
end
|
110
110
|
raise(ArgumentError, "#{ self } did not have a proper uri. Unable to continue.") unless uri && !uri.empty?
|
111
|
+
|
112
|
+
nil
|
111
113
|
end
|
112
114
|
|
113
115
|
# @param request [Contrast::Agent::Request]
|
@@ -38,15 +38,16 @@ module Contrast
|
|
38
38
|
def to_controlled_hash
|
39
39
|
validate
|
40
40
|
{
|
41
|
+
appLanguage: Contrast::Utils::ObjectShare::RUBY,
|
42
|
+
appName: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
|
43
|
+
appPath: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
|
44
|
+
appVersion: ::Contrast::APP_CONTEXT.version,
|
41
45
|
code: CODE,
|
42
|
-
app_language: Contrast::Utils::ObjectShare::RUBY,
|
43
|
-
app_name: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
|
44
|
-
app_version: ::Contrast::APP_CONTEXT.version,
|
45
46
|
data: '',
|
46
47
|
key: 0,
|
47
|
-
|
48
|
-
|
49
|
-
}
|
48
|
+
session_id: ::Contrast::ASSESS.session_id,
|
49
|
+
routes: @routes.map(&:to_controlled_hash)
|
50
|
+
}.compact
|
50
51
|
end
|
51
52
|
|
52
53
|
# @raise [ArgumentError]
|
@@ -54,8 +55,8 @@ module Contrast
|
|
54
55
|
unless Contrast::Utils::StringUtils.present?(data)
|
55
56
|
raise(ArgumentError, "#{ cs__class } did not have a proper data. Unable to continue.")
|
56
57
|
end
|
57
|
-
unless
|
58
|
-
raise(ArgumentError, "#{ cs__class } did not have a proper
|
58
|
+
unless Contrast::APP_CONTEXT.name # rubocop:disable Security/Module/Name
|
59
|
+
raise(ArgumentError, "#{ cs__class } did not have a proper Application Name. Unable to continue.")
|
59
60
|
end
|
60
61
|
|
61
62
|
nil
|
@@ -28,12 +28,31 @@ module Contrast
|
|
28
28
|
#
|
29
29
|
# @return [String, nil] - JSON
|
30
30
|
def event_json
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
return unless valid?
|
32
|
+
|
33
|
+
to_controlled_hash.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check before building the json if the event is valid.
|
37
|
+
# This will also log the error if the event is invalid.
|
38
|
+
# This will save some object creation in the reporter
|
39
|
+
# in the case of an invalid event, and will stop the
|
40
|
+
# reporting of the event.
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
# @raise [ArgumentError]
|
44
|
+
def valid?
|
45
|
+
@_valid ||= begin
|
46
|
+
validate
|
47
|
+
# Some deeply nested validations only happens on
|
48
|
+
# the to_controlled_hash method, so we need to
|
49
|
+
# invoke it.
|
50
|
+
to_controlled_hash
|
51
|
+
true
|
52
|
+
rescue ArgumentError => e
|
53
|
+
handle_validation_error(e)
|
54
|
+
false
|
55
|
+
end
|
37
56
|
end
|
38
57
|
|
39
58
|
private
|
@@ -41,6 +60,11 @@ module Contrast
|
|
41
60
|
def validation_error_message
|
42
61
|
"#{ cs__class } failed validation with: "
|
43
62
|
end
|
63
|
+
|
64
|
+
# @param error [ArgumentError]
|
65
|
+
def handle_validation_error error
|
66
|
+
logger.error(validation_error_message, error)
|
67
|
+
end
|
44
68
|
end
|
45
69
|
end
|
46
70
|
end
|
@@ -72,8 +72,8 @@ module Contrast
|
|
72
72
|
# @return response [Net::HTTP::Response, nil] response from TS if no response
|
73
73
|
def send_event event, connection
|
74
74
|
return unless connection
|
75
|
+
return unless event.valid?
|
75
76
|
|
76
|
-
response = nil
|
77
77
|
logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
|
78
78
|
request = build_request(event)
|
79
79
|
response = connection.request(request)
|
@@ -12,7 +12,7 @@ module Contrast
|
|
12
12
|
RESCUE_ATTEMPTS = 3
|
13
13
|
TIMEOUT = 5
|
14
14
|
RETRY_ERRORS = [
|
15
|
-
Net::OpenTimeout, Net::ReadTimeout,
|
15
|
+
Net::OpenTimeout, Net::ReadTimeout, EOFError, OpenSSL::SSL::SSLError, Resolv::ResolvError,
|
16
16
|
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::ESHUTDOWN, Errno::EHOSTDOWN, NameError,
|
17
17
|
Errno::EHOSTUNREACH, Errno::EISCONN, Errno::ECONNABORTED, Errno::ENETRESET, Errno::ENETUNREACH, SocketError,
|
18
18
|
NameError, NoMethodError, Timeout::Error, RuntimeError
|
@@ -232,11 +232,7 @@ module Contrast
|
|
232
232
|
return unless ::Contrast::AGENT.enabled?
|
233
233
|
|
234
234
|
logger.trace_with_time('Rebuilding rule modes from TeamServer') do
|
235
|
-
|
236
|
-
::Contrast::AGENT.reset_ruleset
|
237
|
-
::Contrast::SETTINGS.build_protect_rules if ::Contrast::PROTECT.enabled?
|
238
|
-
logger.info('Current rule settings:')
|
239
|
-
::Contrast::PROTECT.defend_rules.each { |k, v| logger.info('Protect Rule mode set', rule: k, mode: v.mode) }
|
235
|
+
::Contrast::PROTECT.state.update if ::Contrast::PROTECT.enabled?
|
240
236
|
if ::Contrast::ASSESS.enabled?
|
241
237
|
logger.info('Disabled Assess Rules', rules: ::Contrast::ASSESS.disabled_rules)
|
242
238
|
end
|
@@ -121,10 +121,10 @@ module Contrast
|
|
121
121
|
# Returns list of actively used protection rules to be updated, or default list.
|
122
122
|
# This will be used to query the received settings for the ones used by the Agent.
|
123
123
|
def active_defend_rules
|
124
|
-
return ACTIVE_PROTECT_RULES_LIST unless defined?(Contrast::
|
124
|
+
return ACTIVE_PROTECT_RULES_LIST unless defined?(Contrast::PROTECT)
|
125
125
|
|
126
|
-
current_rules =
|
127
|
-
return current_rules unless current_rules
|
126
|
+
current_rules = Contrast::PROTECT.defend_rules.keys
|
127
|
+
return current_rules unless current_rules.empty?
|
128
128
|
|
129
129
|
ACTIVE_PROTECT_RULES_LIST
|
130
130
|
end
|
@@ -24,10 +24,11 @@ module Contrast
|
|
24
24
|
|
25
25
|
def initialize hsh
|
26
26
|
@baseline = hsh[:baseline]
|
27
|
-
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@
|
27
|
+
# NG endpoints vs non-ng
|
28
|
+
@enabled = hsh[:enabled] || hsh[:enable]
|
29
|
+
@request_frequency = hsh[:frequency] || hsh[:request_frequency]
|
30
|
+
@response_frequency = hsh[:responseFrequency] || hsh[:response_frequency]
|
31
|
+
@window_ms = hsh[:window] || hsh[:window_ms]
|
31
32
|
end
|
32
33
|
|
33
34
|
def to_controlled_hash
|
@@ -52,8 +52,6 @@ module Contrast
|
|
52
52
|
if (ia = Contrast::Agent::Protect::InputAnalyzer.analyse(request))
|
53
53
|
# Handle prefilter
|
54
54
|
Contrast::Agent::Protect::InputAnalyzer.input_classification(ia, prefilter: true)
|
55
|
-
# Reflected xss infilter
|
56
|
-
Contrast::Agent::Protect::InputAnalyzer.input_classification_for('reflected-xss', ia)
|
57
55
|
@agent_input_analysis = ia
|
58
56
|
else
|
59
57
|
logger.trace('Analysis from Agent was empty.')
|
@@ -26,6 +26,8 @@ module Contrast
|
|
26
26
|
attr_reader :config_values
|
27
27
|
# @return [Boolean]
|
28
28
|
attr_accessor :enable
|
29
|
+
# @return [Boolean]
|
30
|
+
attr_accessor :omit_body
|
29
31
|
|
30
32
|
CANON_NAME = 'agent'
|
31
33
|
CONFIG_VALUES = %w[enabled? omit_body?].cs__freeze
|
@@ -95,16 +97,12 @@ module Contrast
|
|
95
97
|
@_ruleset ||= Contrast::Agent::RuleSet.new(retrieve_protect_ruleset.values)
|
96
98
|
end
|
97
99
|
|
98
|
-
def reset_ruleset
|
99
|
-
@_ruleset = nil
|
100
|
-
end
|
101
|
-
|
102
100
|
def patch_yield?
|
103
101
|
!false?(ruby.propagate_yield)
|
104
102
|
end
|
105
103
|
|
106
104
|
def omit_body?
|
107
|
-
@_omit_body
|
105
|
+
true?(@_omit_body)
|
108
106
|
end
|
109
107
|
|
110
108
|
def disable_agent!
|
@@ -129,7 +129,7 @@ module Contrast
|
|
129
129
|
#
|
130
130
|
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
131
131
|
def to_effective_config effective_config
|
132
|
-
add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME,
|
132
|
+
add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CANON_NAME)
|
133
133
|
effective_proxy(effective_config)
|
134
134
|
request_audit&.to_effective_config(effective_config)
|
135
135
|
certificate&.to_effective_config(effective_config)
|
@@ -139,10 +139,10 @@ module Contrast
|
|
139
139
|
|
140
140
|
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
141
141
|
def effective_proxy effective_config
|
142
|
-
add_single_effective_value(effective_config, ENABLE, proxy_enable.to_s, PROXY_NAME
|
142
|
+
add_single_effective_value(effective_config, ENABLE, proxy_enable.to_s, PROXY_NAME)
|
143
143
|
return unless proxy_url && proxy_enable
|
144
144
|
|
145
|
-
add_single_effective_value(effective_config, 'url', proxy_url, PROXY_NAME
|
145
|
+
add_single_effective_value(effective_config, 'url', proxy_url, PROXY_NAME)
|
146
146
|
end
|
147
147
|
|
148
148
|
def certification_truly_enabled? config_path
|
@@ -237,6 +237,10 @@ module Contrast
|
|
237
237
|
|
238
238
|
# The id for this process, based on the session metadata or id provided by the user, as indicated in
|
239
239
|
# application startup.
|
240
|
+
#
|
241
|
+
# The ID of the current application run, as returned by the application settings endpoint or set by
|
242
|
+
# application.session_id. If there is no session associated with this run, this field should be omitted
|
243
|
+
# when reporting to TS.
|
240
244
|
def session_id
|
241
245
|
::Contrast::SETTINGS.assess_state.session_id
|
242
246
|
end
|
@@ -16,7 +16,6 @@ module Contrast
|
|
16
16
|
|
17
17
|
SPEC_KEY = :disabled_rules.cs__freeze
|
18
18
|
CANON_NAME = 'assess.rules'
|
19
|
-
NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }".cs__freeze
|
20
19
|
|
21
20
|
# @return [Array, nil] list of disabled assess rules
|
22
21
|
attr_accessor :disabled_rules
|
@@ -36,7 +35,7 @@ module Contrast
|
|
36
35
|
#
|
37
36
|
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
38
37
|
def to_effective_config effective_config
|
39
|
-
add_single_effective_value(effective_config, SPEC_KEY.to_s, disabled_rules, canon_name
|
38
|
+
add_single_effective_value(effective_config, SPEC_KEY.to_s, disabled_rules || [], canon_name)
|
40
39
|
end
|
41
40
|
|
42
41
|
private
|
@@ -12,7 +12,6 @@ module Contrast
|
|
12
12
|
module ComponentBase
|
13
13
|
include Contrast::Config::Diagnostics::Tools
|
14
14
|
|
15
|
-
CONTRAST = 'contrast'
|
16
15
|
ENABLE = 'enable'
|
17
16
|
|
18
17
|
# Used for config diagnostics. Override per rule.
|
@@ -87,7 +86,7 @@ module Contrast
|
|
87
86
|
#
|
88
87
|
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
89
88
|
def to_effective_config effective_config
|
90
|
-
add_effective_config_values(effective_config, config_values, canon_name
|
89
|
+
add_effective_config_values(effective_config, config_values, canon_name)
|
91
90
|
end
|
92
91
|
|
93
92
|
# attempts to stringify the config value if it is an array with the join char
|
@@ -11,6 +11,8 @@ module Contrast
|
|
11
11
|
# This component encapsulates storing the source for each entry in the config,
|
12
12
|
# so that we can report on where the value was set from.
|
13
13
|
class Sources
|
14
|
+
# [ CORPORATE_RULE, COMMAND_LINE, JAVA_SYSTEM_PROPERTY, ENVIRONMENT_VARIABLE, APP_CONFIGURATION_FILE,
|
15
|
+
# USER_CONFIGURATION_FILE, CONTRAST_UI, DEFAULT_VALUE ]
|
14
16
|
ENVIRONMENT_VARIABLE = 'ENVIRONMENT_VARIABLE'
|
15
17
|
COMMAND_LINE = 'COMMAND_LINE'
|
16
18
|
CONTRAST_UI = 'CONTRAST_UI'
|
@@ -57,6 +59,27 @@ module Contrast
|
|
57
59
|
deep_select(data.dup, type, [])
|
58
60
|
end
|
59
61
|
|
62
|
+
# @param path [String] the canonical name for the config entry (such as api.proxy.enable) or source
|
63
|
+
# if the source(CONTRAST_UI, ENVIRONMENT_VARIABLE...) flag is set true.
|
64
|
+
# @param source [Boolean] flag to specify we are passing in a source, no need to look for it.
|
65
|
+
# @return [Boolean] true if the entry is from a YAML file
|
66
|
+
def configuration_file_source? path, source: false
|
67
|
+
s = source ? path : Contrast::CONFIG.sources.get(path)
|
68
|
+
return true if s.include?(APP_CONFIGURATION_EXTENSIONS[0]) || s.include?(APP_CONFIGURATION_EXTENSIONS[1])
|
69
|
+
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
# Check to see whether the source has been overridden by local settings.
|
74
|
+
# @param path [String] the canonical name for the config entry (such as api.proxy.enable)
|
75
|
+
def source_overridden? path
|
76
|
+
source = Contrast::CONFIG.sources.get(path)
|
77
|
+
return true if [ENVIRONMENT_VARIABLE, COMMAND_LINE].include?(source)
|
78
|
+
return true if configuration_file_source?(source, source: true)
|
79
|
+
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
60
83
|
private
|
61
84
|
|
62
85
|
# @param path [String] the canonical name for a config entry (such as api.proxy.enable)
|
@@ -33,6 +33,8 @@ module Contrast
|
|
33
33
|
include InstanceMethods
|
34
34
|
include Contrast::Components::ComponentBase
|
35
35
|
|
36
|
+
DEFAULT_NAME = 'contrast.log'
|
37
|
+
DEFAULT_LEVEL = 'INFO'
|
36
38
|
CANON_NAME = 'agent.logger'
|
37
39
|
CONFIG_VALUES = %w[path level progname].cs__freeze
|
38
40
|
|
@@ -56,6 +58,23 @@ module Contrast
|
|
56
58
|
@level = hsh[:level]
|
57
59
|
@progname = hsh[:progname]
|
58
60
|
end
|
61
|
+
|
62
|
+
def to_effective_config effective_config
|
63
|
+
path_setting = nil
|
64
|
+
level_setting = nil
|
65
|
+
|
66
|
+
if defined?(Contrast::SETTINGS)
|
67
|
+
path_setting = Contrast::SETTINGS.agent_state.logger_path
|
68
|
+
level_setting = Contrast::SETTINGS.agent_state.logger_level
|
69
|
+
end
|
70
|
+
|
71
|
+
path_setting ||= DEFAULT_NAME
|
72
|
+
level_setting ||= DEFAULT_LEVEL
|
73
|
+
|
74
|
+
add_single_effective_value(effective_config, config_values[0], path || path_setting, CANON_NAME)
|
75
|
+
add_single_effective_value(effective_config, config_values[1], level || level_setting, CANON_NAME)
|
76
|
+
add_single_effective_value(effective_config, config_values[2], progname, CANON_NAME)
|
77
|
+
end
|
59
78
|
end
|
60
79
|
end
|
61
80
|
end
|
@@ -4,6 +4,8 @@
|
|
4
4
|
require 'contrast/components/base'
|
5
5
|
require 'contrast/config/exception_configuration'
|
6
6
|
require 'contrast/config/protect_rule_configuration'
|
7
|
+
require 'contrast/utils/object_share'
|
8
|
+
require 'contrast/agent/protect/state'
|
7
9
|
|
8
10
|
module Contrast
|
9
11
|
module Components
|
@@ -68,7 +70,7 @@ module Contrast
|
|
68
70
|
return false if forcibly_disabled?
|
69
71
|
return true if forcibly_enabled?
|
70
72
|
|
71
|
-
|
73
|
+
state.enabled?
|
72
74
|
end
|
73
75
|
|
74
76
|
# Check to determine if the base64 decoding is required for user inputs.
|
@@ -85,12 +87,19 @@ module Contrast
|
|
85
87
|
::Contrast::CONFIG.protect.rules
|
86
88
|
end
|
87
89
|
|
90
|
+
# Current Active Protect rules and the state/mode they are in.
|
91
|
+
#
|
92
|
+
# @return [Contrast::Agent::Protect::State]
|
93
|
+
def state
|
94
|
+
@_state ||= Contrast::Agent::Protect::State.new
|
95
|
+
end
|
96
|
+
|
88
97
|
# Returns Protect array of all initialized
|
89
98
|
# protect rules.
|
90
99
|
#
|
91
100
|
# @return defend_rules[Hash<Contrast::SETTINGS.protect_state.rules>]
|
92
101
|
def defend_rules
|
93
|
-
|
102
|
+
state.rules
|
94
103
|
end
|
95
104
|
|
96
105
|
# The Contrast::CONFIG.protect.rules is object so we need to check it's
|
@@ -102,16 +111,27 @@ module Contrast
|
|
102
111
|
# @return mode [Symbol]
|
103
112
|
def rule_mode rule_id
|
104
113
|
str = rule_id.tr('-', '_')
|
105
|
-
|
106
|
-
|
107
|
-
|
114
|
+
config_mode = Contrast::CONFIG.protect.rules[str]&.applicable_mode
|
115
|
+
settings_mode = ::Contrast::SETTINGS.application_state.modes_by_id[rule_id]
|
116
|
+
|
117
|
+
if config_mode
|
118
|
+
update_config_for_rule(rule_id, config_mode)
|
119
|
+
return config_mode
|
120
|
+
end
|
121
|
+
|
122
|
+
if settings_mode
|
123
|
+
update_config_for_rule(rule_id, settings_mode, ui_source: true)
|
124
|
+
return settings_mode
|
125
|
+
end
|
126
|
+
:NO_ACTION
|
108
127
|
end
|
109
128
|
|
110
129
|
# Name of the protect rule
|
111
130
|
#
|
112
|
-
# @
|
131
|
+
# @param name [String]
|
132
|
+
# @return [Contrast::Agent::Protect::Rule::Base]
|
113
133
|
def rule name
|
114
|
-
|
134
|
+
state.rules[name]
|
115
135
|
end
|
116
136
|
|
117
137
|
def report_any_command_execution?
|
@@ -124,7 +144,8 @@ module Contrast
|
|
124
144
|
|
125
145
|
def report_custom_code_sysfile_access?
|
126
146
|
if @_report_custom_code_sysfile_access.nil?
|
127
|
-
name_changed = Contrast::Agent::Protect::Rule::PathTraversal::NAME.
|
147
|
+
name_changed = Contrast::Agent::Protect::Rule::PathTraversal::NAME.
|
148
|
+
tr(Contrast::Utils::ObjectShare::DASH, Contrast::Utils::ObjectShare::UNDERSCORE)
|
128
149
|
ctrl = rule_config[name_changed]
|
129
150
|
@_report_custom_code_sysfile_access = ctrl && true?(ctrl.detect_custom_code_accessing_system_files)
|
130
151
|
end
|
@@ -150,16 +171,15 @@ module Contrast
|
|
150
171
|
|
151
172
|
# @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
|
152
173
|
def protect_rules_to_effective_config effective_config
|
153
|
-
|
154
|
-
|
155
|
-
defend_rules.each do |key, value|
|
174
|
+
state.rules.each do |key, value|
|
156
175
|
next unless key && value
|
157
176
|
|
158
177
|
config_prefix = "#{ CANON_NAME }.#{ RULES }.#{ key }"
|
159
|
-
|
160
|
-
add_single_effective_value(effective_config, ENABLE, value.enabled?, config_prefix, name_prefix)
|
178
|
+
add_single_effective_value(effective_config, ENABLE, value.enabled?, config_prefix)
|
161
179
|
# Get the mode by checking Current Configs or Settings received:
|
162
|
-
|
180
|
+
mode = rule_mode(key)
|
181
|
+
mode = :OFF if mode == :NO_ACTION
|
182
|
+
add_single_effective_value(effective_config, MODE, mode, config_prefix)
|
163
183
|
end
|
164
184
|
end
|
165
185
|
|
@@ -181,6 +201,27 @@ module Contrast
|
|
181
201
|
def report_custom_code_sysfile_access
|
182
202
|
report_custom_code_sysfile_access?
|
183
203
|
end
|
204
|
+
|
205
|
+
# @param rule_id [String] the canonical name for a config entry (such as api.proxy.enable).
|
206
|
+
# @param mode [Symbol] to set the value of the config entry.
|
207
|
+
# @param ui_source [Boolean] whether to se the source as contrast ui or not.
|
208
|
+
def update_config_for_rule rule_id, mode, ui_source: false
|
209
|
+
str = rule_id.tr('-', '_').to_sym
|
210
|
+
config = Contrast::CONFIG.config.loaded_config
|
211
|
+
return unless config
|
212
|
+
|
213
|
+
config[:protect] ||= {}
|
214
|
+
config[:protect][:rules] ||= {}
|
215
|
+
config[:protect][:rules][str] ||= {}
|
216
|
+
config[:protect][:rules][str][:mode] = mode
|
217
|
+
config[:protect][:rules][str][:enable] = (mode != :NO_ACTION)
|
218
|
+
return unless ui_source
|
219
|
+
|
220
|
+
Contrast::CONFIG.sources.set("#{ CANON_NAME }.#{ RULES }.#{ str }.mode",
|
221
|
+
Contrast::Components::Config::Sources::CONTRAST_UI)
|
222
|
+
Contrast::CONFIG.sources.set("#{ CANON_NAME }.#{ RULES }.#{ str }.enable",
|
223
|
+
Contrast::Components::Config::Sources::CONTRAST_UI)
|
224
|
+
end
|
184
225
|
end
|
185
226
|
end
|
186
227
|
end
|
@@ -111,7 +111,6 @@ module Contrast
|
|
111
111
|
include Contrast::Config::BaseConfiguration
|
112
112
|
|
113
113
|
CANON_NAME = 'assess.sampling'
|
114
|
-
NAME_PREFIX = "#{ CONTRAST }.#{ CANON_NAME }".cs__freeze
|
115
114
|
CONFIG_VALUES = %w[enable baseline request_frequency response_frequency window_ms].cs__freeze
|
116
115
|
|
117
116
|
# @return [Boolean, nil]
|
@@ -145,19 +144,13 @@ module Contrast
|
|
145
144
|
def to_effective_config effective_config
|
146
145
|
confirm_sources
|
147
146
|
|
148
|
-
add_single_effective_value(effective_config, 'enable', sampling_control[:enabled], canon_name
|
149
|
-
add_single_effective_value(effective_config, 'baseline', sampling_control[:baseline], canon_name
|
150
|
-
add_single_effective_value(effective_config, 'window_ms', sampling_control[:window], canon_name
|
147
|
+
add_single_effective_value(effective_config, 'enable', sampling_control[:enabled], canon_name)
|
148
|
+
add_single_effective_value(effective_config, 'baseline', sampling_control[:baseline], canon_name)
|
149
|
+
add_single_effective_value(effective_config, 'window_ms', sampling_control[:window], canon_name)
|
151
150
|
add_single_effective_value(effective_config,
|
152
|
-
'request_frequency',
|
153
|
-
sampling_control[:request_frequency],
|
154
|
-
canon_name,
|
155
|
-
NAME_PREFIX)
|
151
|
+
'request_frequency', sampling_control[:request_frequency], canon_name)
|
156
152
|
add_single_effective_value(effective_config,
|
157
|
-
'response_frequency',
|
158
|
-
sampling_control[:response_frequency],
|
159
|
-
canon_name,
|
160
|
-
NAME_PREFIX)
|
153
|
+
'response_frequency', sampling_control[:response_frequency], canon_name)
|
161
154
|
end
|
162
155
|
|
163
156
|
private
|
@@ -10,6 +10,7 @@ module Contrast
|
|
10
10
|
class Interface
|
11
11
|
include Contrast::Components::ComponentBase
|
12
12
|
|
13
|
+
DEFAULT_CEF_NAME = 'security.log'
|
13
14
|
CANON_NAME = 'agent.security_logger'
|
14
15
|
CONFIG_VALUES = %w[path level].cs__freeze
|
15
16
|
|
@@ -30,6 +31,22 @@ module Contrast
|
|
30
31
|
@path = hsh[:path]
|
31
32
|
@level = hsh[:level]
|
32
33
|
end
|
34
|
+
|
35
|
+
def to_effective_config effective_config
|
36
|
+
path_setting = nil
|
37
|
+
level_setting = nil
|
38
|
+
|
39
|
+
if defined?(Contrast::SETTINGS)
|
40
|
+
path_setting = Contrast::SETTINGS.agent_state.cef_logger_path
|
41
|
+
level_setting = Contrast::SETTINGS.agent_state.cef_logger_level
|
42
|
+
end
|
43
|
+
|
44
|
+
path_setting ||= DEFAULT_CEF_NAME
|
45
|
+
level_setting ||= Contrast::CONFIG.agent.logger.level
|
46
|
+
|
47
|
+
add_single_effective_value(effective_config, config_values[0], path || path_setting, CANON_NAME)
|
48
|
+
add_single_effective_value(effective_config, config_values[1], level || level_setting, CANON_NAME)
|
49
|
+
end
|
33
50
|
end
|
34
51
|
end
|
35
52
|
end
|