lib/contrast/agent/protect/rule/input_classification/encoding.rb in contrast-agent-7.4.1 vs lib/contrast/agent/protect/rule/input_classification/encoding.rb in contrast-agent-7.5.0

- old
+ new

@@ -35,11 +35,11 @@ # 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 encodind the value, and then decoding it. If the value is already encoded + # 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. # # @param value [String] input to check for encoding status. # @param input_type [Symbol] input type. # @return [Boolean] true if value is base64 encoded, false otherwise. @@ -94,13 +94,45 @@ # @return [String] decoded or original value. # @raise [StandardError] def cs__decode64 value, input_type return value unless cs__base64?(value, input_type) - Base64.decode64(value) + 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.message, backtrace: e.backtrace) value + end + + private + + # Try and decode the value, do not use decoding if the value have zero bytes. + def try_base64_decode value + new_value = Base64.decode64(value) + # check for null bytes: + return new_value unless new_value.bytes.select(&:zero?).any? + + value + end + + # Detecting encoded Base64 is not perfect. In some cases it will detect certain inputs as + # encoded and will try to decode them. Even if the decoding is successful, the value may be + # encoded back to ASCII format. AgentLib will raise UTF-8 error in this case. + # This method will try to normalize the encoding to UTF-8. If the encoding fails, this means + # that the decoding was not successful and the value will be returned as is. Otherwise a + # base64 decoded string with ASCII-8BIT encoding will be parsed to UTF-8 without errors. + # + # @param value [String] input to normalize. + # @return [Array<String, Boolean>] normalized value and success flag. + def normalize_encoding value + new_value = value.dup.encode!('Windows-1252').force_encoding('UTF-8') + [new_value, true] + rescue StandardError + # encoding failed, or the decoding from base64 failed. + [nil, false] end end end end end