To prevent multiple account creation with the same email address
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.
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.