Skip to main content

Email uniqueness not properly verified

Need

Enforce email uniqueness during registration process

Context

  • Usage of Scala for building scalable and functional applications
  • Usage of play.api.data for handling form data in Play Framework
  • Usage of play.api.data.Forms for handling form data in Play Framework

Description

Non compliant code

import play.api.data._
import play.api.data.Forms._

val userForm = Form(
mapping(
"email" -> email,
"password" -> nonEmptyText
)(User.apply)(User.unapply)
)

In the above code, the form mapping function is used to map the form fields to the User case class. The "email" field is validated using the built-in email constraint which simply checks if the provided string is a valid email. However, this validation does not account for the plus character (+) in the email address.

Email providers like Gmail ignore any characters after the plus symbol in the email address. This means that [email protected] and [email protected] are treated as the same email address [email protected] by Gmail.

An attacker can exploit this feature to register multiple accounts with the same email address. For example, an attacker could register [email protected], [email protected], [email protected], etc., and all these accounts would point to the same email address [email protected].

This could lead to various security issues, such as account enumeration, spamming, and potentially bypassing some access controls if the application uses email addresses as a unique identifier for users.

Steps

  • Validate the uniqueness of the email address during the registration process.
  • Implement a check to ensure that the email address does not already exist in the system before creating a new user account.
  • Consider using a database query or an ORM (Object-Relational Mapping) tool to check for existing email addresses.
  • If the email address already exists, display an error message to the user and prevent the account creation process.
  • Ensure that the email address validation is performed on the server-side to prevent any client-side manipulation.
  • Consider implementing additional security measures, such as rate limiting or CAPTCHA, to prevent abuse of the registration process.

Compliant code

import play.api.data._
import play.api.data.Forms._
import play.api.db.slick.DatabaseConfigProvider
import slick.jdbc.JdbcProfile

import scala.concurrent.{ExecutionContext, Future}

class UserController @Inject() (protected val dbConfigProvider: DatabaseConfigProvider)(implicit ec: ExecutionContext) {
val dbConfig = dbConfigProvider.get[JdbcProfile]

import dbConfig._
import profile.api._

val userForm = Form(
mapping(
"email" -> email.verifying("This email is already registered", email => !isEmailExists(email)),
"password" -> nonEmptyText
)(User.apply)(User.unapply)
)

def isEmailExists(email: String): Future[Boolean] = {
db.run(users.filter(_.email === email).exists.result)
}
}

The code above is a Scala Play Framework controller that handles user registration. It uses Slick, a Functional Relational Mapping (FRM) library for Scala that makes it easy to work with relational databases.

The userForm is a Play Framework form that maps the form fields to a User case class. The form includes a verifying method on the email field to check if the email is already registered in the database. The verifying method takes a string error message and a function that returns a boolean. If the function returns false, the form will be invalid and the error message will be displayed.

The isEmailExists method checks if an email already exists in the database. It uses Slick's filter method to find users with the same email, and the exists method to check if there are any results. The result method returns a Future[Boolean] indicating whether the email exists.

This code ensures that the email address is unique and prevents an attacker from creating multiple accounts with the same email address. It also performs the validation on the server-side, preventing client-side manipulation.

References