README

Contents

Installation

Phx2Ban is a Premium library and requires that a license is purchased from EzSuite. This is a one time purchase and not a subscription.

Adding private Hex repository

After you have purchased a license, you will have access to your authentication key and a fetch public key. You can use these to add the EzSuite private Hex repository to your project by doing:

mix hex.repo add ezsuite https://ezsuite.dev/repo \
    --auth-key $EZ_SUITE_AUTH_KEY \
    --fetch-public-key $EZ_SUITE_PUBLIC_KEY

After you purchase a license and add the private Hex repository to your local Hex environment, you can add Phx2Ban to your poject by updating your mix.exs file:

defp deps do
  [
    ...
    {:phx_2_ban, "~> 0.2.2", repo: "ezsuite"}
  ]
end

Setting up Phx2Ban

After installing the Phx2Ban dependency from the EzSuite private Hex repository, setting up Phx2Ban in your application should only take a few minutes. Follow the steps below carefully and perform the actions needed depending on your needs.

Updating application.ex file

With that in place you can run mix deps.get and you can pull down Phx2Ban from the EzSuite private Hex repository! All that is left to do is update your application so that Phx2Ban can work its security magic. The first file that you will need to update is your project's application.ex file:

def start(type, args) do
  children = [
    ...

    # Start Phx2Ban before you start your Endpoint.
    {Phx2Ban, router: MyAppWeb.Router},
    # If you have multiple routers, use:
    # {Phx2Ban, router: [MyAppWeb.Router, MyOtherAppWeb.Router]

    MyAppWeb.Endpoint
  ]
end

By adding this line to your project's supervision tree you will start all of the necessary Phx2Ban components to secure your application from malicious requests. Now you just need to add a plug to your endpoint.ex file to handle inbound requests.

Updating endpoint.ex file

In your endpoint.ex file, add the following line after your plug Plug.Static calls or socket call:

defmodule MyAppWeb.Endpoint do
  ...

  plug Plug.Static,
    ...

  # ⚠️ If your app runs behind a Proxy, you must add this plug as well.
  # Otherwise, we'll block your Proxy and all incoming traffic
  # because Proxies usually override the request IP with their own.
  # plug RemoteIP

  # 👇 Add the Phx2Ban.Plug behind your Plug.Static
  plug Phx2Ban.Plug
end

By putting this plug at the top of your endpoint.ex file you ensure that malicious actors cannot access any part of your Phoenix application once malicious requests have been detected from an IP address.

Applications behind load balancers

If your application is behind a load balancer the IP address of the incoming request will be the load balancer's IP address. It would be really bad for your users if Phx2Ban blocked the IP address of the load balancer due to malicious users making requests. Luckily most load balancers have a way of attaching the IP address of the original request to inbound HTTP calls so your application knows where the requests originated from. If you need to support this kind of architecture there is an Elixir library that can make this very easy for you remote_ip. Make sure that you add the plug RemoteIp plug prior to the plug Phx2Ban.Plug call so that Phx2Ban will act on the client IP address and NOT the load balancer IP address.

With all that in place you are all set to go! Phx2Ban will now analyze incoming requests and block IP address that are making malicious calls to your application. We also provide a LiveDashboard plugin so that you can keep tabs on what Phx2Ban is doing. Follow the instructions in the next section if you are using Phoenix LiveDashboard in order to set that up.

Configuring Phx2Ban

We documented all configuration options in Phx2Ban.FirewallConfig. You can configure Phx2Ban either in your config.exs or when you start it in your supervision tree. Here's how to configure it in each:

# config/config.exs

config :phx_2_ban,
  router: MyAppWeb.Router,
  # Or, if you have multiple routers:
  # router: [MyAppWeb.Router, MyOtherAppWeb.Router],
  check_interval: 120_000,
  block_duration: 86_400

Or you can provide a list of options when starting Phx2Ban in your supervision tree:

# lib/my_app/application.ex

def start(type, args) do
  children = [
    # other children

    # Options provided here overwrite the options in `config.exs`.
    {Phx2Ban, router: MyAppWeb.Router, check_interval: 120_000, block_duration: 86_400},

    # Start Phx2Ban before you start the Endpoint.
    MyAppWeb.Endpoint
  ]
end

Adding Phoenix LiveDashboard plugin (optional)

Phoenix LiveDashboard allows you to add plugins to the dashboard so you can easily view internal application events and logs. Phx2Ban provides a LiveDashboard plugin so that you can keep tabs on unique IP addresses accessing your application, what IP address are in the blocklist and how they ended up there as well as some other handy metrics. In order to install this plugin into LiveDashboard you'll first have to install LiveDashboard and then you'll have to update your call to live_dashboard to include the Phx2Ban plugin:

live_dashboard "/dashboard",
  ...
  additional_pages: [
    route_name: Phx2Ban.LiveDashboardPlugin
  ]

If you have a Content-Security-Policy (CSP) in place, you need to assign the CSP nonces to the Conn and set the csp_nonce_assign_key option to tell LiveDashboard under which assign key it can find the CSP nonces.

Read more in this fabulous blog post: https://francis.chabouis.fr/posts/csp-nonce-with-phoenix/#phoenix-livedashboard

live_dashboard "/dashboard",
  ...
  additional_pages: [
    route_name: Phx2Ban.LiveDashboardPlugin
  ]
  csp_nonce_assign_key: :my_csp_assign

With that in place you should now have access to the Phx2Ban LiveDashboard plugin once you spin up your application!

LiveDashboard plugin

Make sure that your LiveDashboard route is behind some sort of authentication as outlined in the documentation so that it is not available on the public internet.

Performance concerns

Phx2Ban analyzes traffic out of band from the actual request and so the overhead involved with finding malicious IP addresses should have a negligible impact on the response times of requests. The only other overhead that is added to the request/response cycle is that of checking if the incoming request is on the blocklist. This action occurs via ETS and is performed in constant time. In other words, little to no overhead is added in validating requests either.

In addition, the traffic analysis portion of Phx2Ban takes place inside of a Partition supervisor which will replicate the traffic analysis process across all of your available schedulers:

Phx2Ban supervision tree