Email Uniqueness Not Properly Verified - Elixir

Email Uniqueness Not Properly Verified - Elixir

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

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.

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.

Compliant code

        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
      {:ok, _} -> send_resp(conn, 200, "User registered successfully")
      {:error, _} -> send_resp(conn, 400, "Email already registered")
    end
  end

  defp normalize_email(email) do
    [local, domain] = String.split(email, "@")
    local = String.split(local, "+") |> List.first()
    local <> "@" <> domain
  end
end
        
        

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.

References