To prevent unauthorized access and control over a user account.
defmodule MyAppWeb.PasswordResetController do
use MyAppWeb, :controller
def create(conn, %{'email' => email}) do
user = Accounts.get_user_by_email(email)
Accounts.deliver_password_reset_instructions(user, conn)
send_resp(conn, :ok, "")
end
end
defmodule MyApp.Accounts do
def deliver_password_reset_instructions(%User{} = user, conn) do
url = MyAppWeb.Router.Helpers.password_reset_url(conn, :edit, user.reset_password_token)
MyApp.Mailer.deliver_password_reset_instructions(user.email, url)
end
end
The code implements a password reset functionality. However, it does not validate whether the requester is indeed the owner of the account. This allows an attacker to request a password reset for any account and receive the reset link, allowing them to takeover that account.
defmodule MyAppWeb.PasswordResetController do
use MyAppWeb, :controller
def create(conn, %{'email' => email}) do
user = Accounts.get_user_by_email(email)
verification_code = Accounts.generate_verification_code(user)
MyApp.Mailer.deliver_verification_code(user.email, verification_code)
send_resp(conn, :ok, "")
end
def update(conn, %{'email' => email, 'verification_code' => verification_code, 'new_password' => new_password}) do
user = Accounts.get_user_by_email(email)
if Accounts.verify(user, verification_code) do
Accounts.reset_password(user, new_password)
send_resp(conn, :ok, "")
else
send_resp(conn, :bad_request, "")
end
end
end
The code now first sends a verification code to the user's registered email when a password reset is requested. The password reset process only proceeds if the correct verification code is provided, thereby validating that the requester is indeed the owner of the account.