Message flooding - Scala

Message flooding - Scala

Need

Mitigation of message flooding attacks

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework
  • Usage of play.api.libs.json for JSON parsing and manipulation in Play Framework

Description

Non compliant code

        import play.api.mvc._
import play.api.libs.json._

class MessageController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  def sendMassMessages = Action { request =>
    val json = request.body.asJson.get
    val emailList = (json \\ "emails").as[List[String]]
    val message = (json \\ "message").as[String]

    emailList.foreach { email =>
      // Sending email without any rate limiting or restrictions
      sendEmail(email, message)
    }

    Ok("Emails sent")
  }

  def sendEmail(email: String, message: String): Unit = {
    // Code to send email
  }
}
        
        

The above Scala code uses the Play framework to define a MessageController that has a sendMassMessages method. This method can be exploited to send mass messages to the phone numbers and emails of the victims, causing saturation of the inbox and consuming resources of the user.

The sendMassMessages method reads a JSON payload from the request body, which contains a list of emails and a message. It then sends the message to all the emails in the list without any restrictions or rate limiting.

This means that an attacker could potentially send a large number of requests with different email lists, causing a flood of messages to be sent. This could result in a Denial of Service (DoS) attack, where the victims' inboxes are saturated with messages, consuming their resources and potentially causing their email service to become unavailable.

Steps

  • Implement rate limiting to restrict the number of messages that can be sent within a certain time period.
  • Validate the input data to ensure that only valid email addresses and messages are accepted.
  • Consider implementing a CAPTCHA or other form of user verification to prevent automated flooding of messages.
  • Monitor and log the number of messages sent to detect any suspicious activity.
  • Consider implementing a queue system to handle the sending of mass messages, ensuring that resources are not overwhelmed.
  • Regularly review and update the code to address any new vulnerabilities or best practices in message sending.

Compliant code

        import play.api.mvc._
import play.api.libs.json._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

class MessageController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

  private val MAX_EMAILS_PER_MINUTE = 100
  private var emailsSentLastMinute = 0

  def sendMassMessages = Action.async { request =>
    val json = request.body.asJson.get
    val emailList = (json \\ "emails").as[List[String]]
    val message = (json \\ "message").as[String]

    if (emailsSentLastMinute + emailList.size > MAX_EMAILS_PER_MINUTE) {
      Future.successful(TooManyRequests("Too many emails sent. Please try again later."))
    } else {
      emailsSentLastMinute += emailList.size

      Future.sequence(emailList.map { email =>
        // Sending email with rate limiting
        sendEmail(email, message)
      }).map { _ =>
        Ok("Emails sent")
      }
    }
  }

  def sendEmail(email: String, message: String): Future[Unit] = {
    // Code to send email
    Future.successful(())
  }
}
        
        

The updated code includes a rate limiting mechanism to prevent message flooding. The MAX_EMAILS_PER_MINUTE constant defines the maximum number of emails that can be sent per minute. The emailsSentLastMinute variable keeps track of how many emails have been sent in the last minute.

Before sending the emails, the code checks if the number of emails to be sent plus the number of emails already sent in the last minute exceeds the maximum limit. If it does, a TooManyRequests response is returned, indicating that the user should try again later.

If the limit is not exceeded, the emails are sent and the emailsSentLastMinute counter is updated.

The sendEmail function now returns a Future, allowing the emails to be sent asynchronously. This prevents the server from being blocked while the emails are being sent.

The Action.async and Future.sequence functions are used to handle the asynchronous operations. The Future.sequence function transforms a list of futures into a single future that will be completed when all the futures in the list are completed.

This solution not only prevents message flooding but also improves the performance of the server by sending the emails asynchronously.

References