Asymmetric denial of service - ReDoS - Ruby

Asymmetric denial of service - ReDoS - Ruby

Need

Prevention of Regular Expression Denial of Service (ReDoS)

Context

  • Usage of Ruby for building web applications and scripting
  • Usage of Ruby for building dynamic and object-oriented applications

Description

Non compliant code

        # This is a simple function that checks if a given string is a valid email.
def is_valid_email?(email)
  # This is the dangerous regular expression. It's trying to match a string
  # that looks like an email address.
  regex = /\\A([\\w+\\-].?)+@[a-z\\d\\-]+(\\.[a-z]+)*\\.[a-z]+\\z/i

  email =~ regex
end
        
        

This function is_valid_email? is designed to check if a given string is a valid email address. It does this by using a regular expression to match the string against a pattern that resembles an email address.

The regular expression is as follows:

                regex = /\\A([\\w+\\-].?)+@[a-z\\d\\-]+(\\.[a-z]+)*\\.[a-z]+\\z/i

            


This regular expression is quite complex and uses several operations to find matches. For instance, it uses the + operator, which means "one or more", and the * operator, which means "zero or more". These operators can lead to a large number of ways to match a string, which can cause the regular expression engine to take a long time to evaluate certain strings.

If an attacker knows that this regular expression is being used, they can craft a string that will take a long time to evaluate. This is known as a ReDoS (Regular expression Denial of Service) attack. By sending such a string to the server, they could cause the server to become unresponsive, effectively causing a denial of service.

Steps

  • Replace the dangerous regular expression with a safer and more efficient one.
  • Use a well-tested and widely-used regular expression library or function to validate email addresses.
  • Avoid using complex operations or excessive backtracking in regular expressions.
  • Consider using a whitelist approach to validate email addresses, rather than trying to match all possible variations.
  • Implement input validation and sanitization to prevent malicious input from reaching the regular expression evaluation.
  • Regularly update and patch the regular expression library or function to ensure it is not vulnerable to known issues.
  • Perform thorough testing and validation of the regular expression to ensure it does not cause performance issues or allow for denial of service attacks.

Compliant code

        require 'uri'

def is_valid_email?(email)
  # Use the URI library to parse the email address
  begin
    parsed = URI::MailTo::EMAIL_REGEXP.match?(email)
  rescue URI::InvalidURIError
    return false
  end

  # If the email address is valid, return true
  return parsed
end
        
        

The updated code uses the URI::MailTo::EMAIL_REGEXP from the URI library to validate the email address. This is a safer and more efficient approach than using a custom regular expression.

The URI::MailTo::EMAIL_REGEXP is a well-tested and widely-used regular expression for validating email addresses. It avoids the use of complex operations or excessive backtracking that can lead to ReDoS vulnerabilities.

The match? method is used to check if the email address matches the regular expression. If the email address is valid, match? returns true. If the email address is invalid or if an error occurs during parsing, the method returns false.

This approach also implements input validation and sanitization, as the URI::MailTo::EMAIL_REGEXP regular expression only matches valid email addresses. This prevents malicious input from reaching the regular expression evaluation.

Finally, the URI library is regularly updated and patched to ensure it is not vulnerable to known issues. This makes it a reliable choice for validating email addresses.

References