logo

Database

Email Uniqueness Not Properly Verified

Need

To prevent multiple account creation with the same email address

Context

• Usage of Elixir for building scalable and fault-tolerant applications

• Usage of Elixir Phoenix Ecto for building web applications with a functional programming language and a reliable database layer

• User registration with email verification

Description

1. Non compliant code

defmodule VulnerableApp.UserController do
  use VulnerableApp.Web, :controller

  def register(conn, %{"email" => email, "password" => password}) do
    User.changeset(%User{}, %{email: email, password: password}) |> Repo.insert()
    send_resp(conn, 200, "User registered successfully")
  end
end

The following Elixir code accepts the email from an untrusted source and creates a user account without properly validating the uniqueness of the email address. This allows an attacker to create multiple accounts with the same email.

2. Steps

• Use Ecto's `unique_constraint` function in the changeset to enforce uniqueness at the database level.

• Normalize the email address before saving it to the database. Remove any characters after and including the '+' sign in the local part of the email address.

3. Secure code example

defmodule SecureApp.UserController do
  use SecureApp.Web, :controller

  def register(conn, %{"email" => email, "password" => password}) do
    normalized_email = normalize_email(email)
    changeset = User.changeset(%User{}, %{email: normalized_email, password: password}) |> Ecto.Changeset.unique_constraint(:email)
    case Repo.insert(changeset) do
      {:error, _} -> send_resp(conn, 400, "Email already registered")...

The following Elixir code normalizes the email address by removing any characters after and including the '+' sign in the local part, and then checks the uniqueness of the email address before creating a user account. This prevents an attacker from creating multiple accounts with the same email.