Module: Contrast::Agent::Protect::Rule::InputClassification::Encoding
- Includes:
- Components::Logger::InstanceMethods
- Included in:
- Base
- Defined in:
- lib/contrast/agent/protect/rule/input_classification/encoding.rb
Overview
Module to hold different encoding utils.
Constant Summary collapse
- KNOWN_DECODING_EXCEPTIONS =
Still a list is needed for this one, as it is not possible to determine if the value is encoded or not. As long as the list is short the method has a good percentage of success.
%w[cmd version if_modified_since].cs__freeze
Instance Method Summary collapse
-
#cs__base64?(value, input_type) ⇒ Boolean
This methods is not performant, but is more safe for false positive.
-
#cs__decode64(value, input_type) ⇒ String
This method will decode the value using Base64.decode64, only if value was encoded.
Methods included from Components::Logger::InstanceMethods
Instance Method Details
#cs__base64?(value, input_type) ⇒ Boolean
This methods is not performant, but is more safe for false positive. Base64 check is no trivial task. For example if one passes a value like ‘stringdw’ it will return true, or value ‘pass’, but it is indeed not encoded. using regexp like:
^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$
This will fail with any inputs from above, and this is because any characters with 4 bytes will be considered as base64 encoded, and without additional context it is impossible to determine if the value is encoded or not. Not to mention the above regexp will not detect empty spaces.
Alternative to the above regexp, acting the same way, could be this:
Base64.strict_encode64(Base64.decode64(value)) == value
Making an exception list is not a good idea, because it will be hard to maintain.
The Base64 method will return printable ascii characters, so we can use this to determine if the value is encoded or not.
The solution in this case is encoding the value, and then decoding it. If the value is already encoded it will not be eq to the original value. If the value is not encoded, it will be eq to the original value.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/contrast/agent/protect/rule/input_classification/encoding.rb', line 46 def cs__base64? value, input_type return false unless value.is_a?(String) return false if Contrast::Utils::DuckUtils.empty_duck?(value) # Encoded string levels of decoding example: # # Value encoded 'pass' => 'cGFzcw==' # decode level 0 => 'pass' # decode level 1 => '\xA5\xAB,' # decode level 2 => '' check_value = value.dup return false if KNOWN_DECODING_EXCEPTIONS.include?(check_value) level = 0 iteration = 0 until Contrast::Utils::DuckUtils.empty_duck?(Base64.decode64(check_value)) iteration += 1 # handle cases like 'command' or 'injection' which will check out as encoded regarding the level of # decoding, but will produce ascii escape characters on first iteration, rather than decoded value. level += 1 unless iteration == 2 && ::CGI.escape(check_value) != check_value check_value = Base64.decode64(check_value) end # if we have more than 2 levels the value is encoded. base64 = level > 1 # Call base64 statistics: if base64 Contrast::Agent::Protect::InputAnalyzer.base64_statistic.match!(input_type) else Contrast::Agent::Protect::InputAnalyzer.base64_statistic.mismatch!(input_type) end base64 rescue StandardError => e logger.error('Error while checking for base64 encoding', error: e, message: e., backtrace: e.backtrace) false end |
#cs__decode64(value, input_type) ⇒ String
This method will decode the value using Base64.decode64, only if value was encoded. If value is not encoded, it will return the original value.
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/contrast/agent/protect/rule/input_classification/encoding.rb', line 96 def cs__decode64 value, input_type return value unless cs__base64?(value, input_type) new_value = try_base64_decode(value) new_value, success = normalize_encoding(new_value) return new_value if success value rescue StandardError => e logger.error('Error while decoding base64', error: e, message: e., backtrace: e.backtrace) value end |