Skip to main content

Cross-Site Request Forgery

Need

Prevent attackers from tricking authenticated users into executing actions without their consent.

Context

  • Usage of Elixir 1.13.0 for functional programming and building scalable applications
  • Usage of Plug for request management
  • Usage of Plug.CSRFProtection for protecting against CSRF attacks
  • Usage of cookie-based sessions for application authentication and state management

Description

Non compliant code

defmodule VulnerableController do
use Plug.Router

plug :match
plug :dispatch

post "/change_password" do
# Change password logic here
User.change_password(conn.params["new_password"])
send_resp(conn, 200, "Password changed successfully")
end
end

The endpoint '/change_password' changes the password of a user based on the provided parameters. However, it does not validate the authenticity of the request, making it vulnerable to CSRF attacks. An attacker can create a malicious site that sends a POST request to this endpoint, changing the password without the user's knowledge or consent.

Steps

  • Import the Plug.CSRFProtection package in your controller.
  • Add a plug to the controller to use CSRF protection.
  • Ensure every form or action that modifies state on the server includes the CSRF token in the request.

Compliant code

defmodule SecureController do
use Plug.Router
use Plug.CSRFProtection

plug :match
plug :dispatch
plug :put_secure_browser_headers

post "/change_password" do
with :ok <- check_csrf_token(conn) do
User.change_password(conn.params["new_password"])
send_resp(conn, 200, "Password changed successfully")
else
_ -> send_resp(conn, 403, "Invalid CSRF token.")
end
end
end

This solution introduces CSRF protection by including Plug.CSRFProtection in the controller. This plug will automatically generate and validate CSRF tokens in the session. Any state-modifying operation will require a valid CSRF token, otherwise, a 'Invalid CSRF token.' message is returned to the client, thus preventing CSRF attacks.

References