View Source SafeURL (SafeURL v0.3.0)

SafeURL is library for mitigating Server Side Request Forgery vulnerabilities in Elixir. Private/reserved IP addresses are blocked by default, and users can add additional CIDR ranges to the blocklist, or alternatively allow specific CIDR ranges to which the application is allowed to make requests.

You can use allowed?/2 or validate/2 to check if a URL is safe to call. If the HTTPoison application is available, you can also call get/4 directly which will validate the host before making an HTTP request.

Examples

iex> SafeURL.allowed?("https://includesecurity.com")
true

iex> SafeURL.validate("http://google.com/", schemes: ~w[https])
{:error, :restricted}

iex> SafeURL.validate("http://230.10.10.10/")
{:error, :restricted}

iex> SafeURL.validate("http://230.10.10.10/", block_reserved: false)
:ok

# If HTTPoison is available:

iex> SafeURL.get("https://10.0.0.1/ssrf.txt")
{:error, :restricted}

iex> SafeURL.get("https://google.com/")
{:ok, %HTTPoison.Response{...}}

Options

SafeURL can be configured to customize and override validation behaviour by passing the following options:

  • :block_reserved - Block reserved/private IP ranges. Defaults to true.

  • :blocklist - List of CIDR ranges to block. This is additive with :block_reserved. Defaults to [].

  • :allowlist - List of CIDR ranges to allow. If specified, blocklist will be ignored. Defaults to [].

  • :schemes - List of allowed URL schemes. Defaults to ["http, "https"].

  • :dns_module - Any module that implements the SafeURL.DNSResolver behaviour. Defaults to DNS from the :dns package.

If :block_reserved is true and additional hosts/ranges are supplied with :blocklist, both of them are included in the final blocklist to validate the address. If allowed ranges are supplied with :allowlist, all blocklists are ignored and any hosts not explicitly declared in the allowlist are rejected.

These options can be set globally in your config.exs file:

config :safeurl,
  block_reserved: true,
  blocklist: ~w[100.0.0.0/16],
  schemes: ~w[https],
  dns_module: MyCustomDNSResolver

Or they can be passed to the function directly, overriding any global options if set:

iex> SafeURL.validate("http://10.0.0.1/", block_reserved: false)
:ok

iex> SafeURL.validate("https://app.service/", allowlist: ~w[170.0.0.0/24])
:ok

iex> SafeURL.validate("https://app.service/", blocklist: ~w[170.0.0.0/24])
{:error, :restricted}

Link to this section Summary

Functions

Validate a string URL against a blocklist or allowlist.

Validate a URL and execute a GET request using HTTPoison.

Alternative method of validating a URL, returning atoms instead of booleans.

Link to this section Functions

Link to this function

allowed?(url, opts \\ [])

View Source

Specs

allowed?(binary(), Keyword.t()) :: boolean()

Validate a string URL against a blocklist or allowlist.

This method checks if a URL is safe to be called by looking at its scheme and resolved IP address, and matching it against reserved CIDR ranges, and any provided allowlist/blocklist.

Returns true if the URL meets the requirements, false otherwise.

Examples

iex> SafeURL.allowed?("https://includesecurity.com")
true

iex> SafeURL.allowed?("http://10.0.0.1/")
false

iex> SafeURL.allowed?("http://10.0.0.1/", allowlist: ~w[10.0.0.0/8])
true

Options

See Options section above.

Link to this function

get(url, options \\ [], headers \\ [], httpoison_options \\ [])

View Source

Specs

get(binary(), Keyword.t(), HTTPoison.headers(), Keyword.t()) ::
  {:ok, HTTPoison.Response.t()} | {:error, :restricted} | no_return()

Validate a URL and execute a GET request using HTTPoison.

If the URL is safe, this function will execute the request using HTTPoison, returning the result directly. Otherwise, it will return {:error, :restricted}.

headers and httpoison_options will be passed directly to HTTPoison when the request is executed. This function will raise if HTTPoison if not available.

See allowed?/2 for more details on URL validation.

Examples

iex> SafeURL.get("https://10.0.0.1/ssrf.txt")
{:error, :restricted}

iex> SafeURL.get("https://google.com/")
{:ok, %HTTPoison.Response{...}}

iex> SafeURL.get("https://google.com/", schemes: ~w[ftp])
{:error, :restricted}

Options

See Options section above.

Link to this function

validate(url, opts \\ [])

View Source

Specs

validate(binary(), Keyword.t()) :: :ok | {:error, :restricted}

Alternative method of validating a URL, returning atoms instead of booleans.

This calls allowed?/2 underneath to check if a URL is safe to be called. If it is, it returns :ok, otherwise {:error, :restricted}.

Examples

iex> SafeURL.validate("https://includesecurity.com")
:ok

iex> SafeURL.validate("http://10.0.0.1/")
{:error, :restricted}

iex> SafeURL.validate("http://10.0.0.1/", allowlist: ~w[10.0.0.0/8])
:ok

Options

See Options section above.