Server-side Request Forgery (SSRF) - Elixir

Server-side Request Forgery (SSRF) - Elixir

Need

To prevent unauthorized network requests performed by the server due to user input manipulation

Context

  • Usage of Elixir (v1.11+) for building scalable and fault-tolerant applications
  • Usage of Plug.Adapters.Cowboy2.Http module for handling HTTP requests in Elixir
  • Usage of httpc module for making HTTP requests

Description

Non compliant code

        defmodule MyAppWeb.PageController do
  use MyAppWeb, :controller

  def external_request(conn, %{"url" => url} = _params) do
    {:ok, response} = :httpc.request(url)
    text(response)
  end
end
        
        

In this insecure code, the Elixir/Phoenix application accepts a URL from user input and makes a HTTP request to it using the :httpc.request function. This is a server-side request forgery (SSRF) vulnerability, as a malicious user could manipulate the input to make the server perform unauthorized requests.

Steps

  • Don't allow user input to dictate the server's network requests directly.
  • If user input must be used to make network requests, implement strict input validation and only allow requests to approved domains.
  • Consider using a safe-list of approved domains that the server can make requests to.

Compliant code

        defmodule MyAppWeb.PageController do
  use MyAppWeb, :controller

  def external_request(conn, %{"url" => url} = _params) do
    if validate_url(url) do
      {:ok, response} = :httpc.request(url)
      text(response)
    else
      send_resp(conn, 400, "Invalid URL")
    end
  end

  defp validate_url(url), do: Enum.member?(["http://approved1.com", "http://approved2.com"], url)
end
        
        

In this secure code, the application still accepts a URL from user input. However, it now validates the input with a validate_url function, which checks if the input is part of a list of approved domains. This mitigates the SSRF vulnerability by preventing the server from making requests to unapproved domains.

References