Skip to main content

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

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