Skip to main content

Insecure Authentication Method - Basic

Need

Securely authenticate user requests

Context

  • Usage of Elixir (1.10 and above) for building scalable and fault-tolerant applications
  • Usage of Phoenix Framework for building web applications
  • Usage of Guardian library for JWT authentication

Description

Non compliant code

def login(conn, %{"username" => username, "password" => password}) do
user = Repo.get_by(User, username: username)
if user && Bcrypt.checkpw(password, user.password_hash) do
{:ok, token, _claims} = BasicAuthToken.encode_and_sign(user.username)
conn
|> put_resp_header("authorization", "Basic #{token}")
|> send_resp(:ok, "Logged in")
else
send_resp(conn, :unauthorized, "Incorrect username or password")
end
end

In the insecure code example, the server uses Basic Authentication, where the user credentials are Base64-encoded but not encrypted, and transmitted over the network. This can be easily decoded and allows an attacker to intercept the user's credentials.

Steps

  • Implement Bearer authentication using hashed tokens instead of transmitting sensitive user credentials.
  • Use HTTPS for all sensitive communications to prevent the interception of data.
  • Consider other authentication mechanisms like OAuth or JWT for even better security.

Compliant code

def login(conn, %{"username" => username, "password" => password}) do
user = Repo.get_by(User, username: username)
if user && Bcrypt.checkpw(password, user.password_hash) do
{:ok, jwt, _full_claims} = Guardian.encode_and_sign(user, :token)
conn
|> put_resp_header("authorization", "Bearer #{jwt}")
|> send_resp(:ok, "Logged in")
else
send_resp(conn, :unauthorized, "Incorrect username or password")
end
end

In the secure code example, the server uses Bearer Authentication with a hashed token. The server generates a JWT token for the authenticated user and returns it in the Authorization header. This ensures the user's sensitive credentials are not transmitted over the network.

References