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