View Source Paraxial.io Elixir Agent

introduction

Introduction

The Paraxial agent provides developers with several Plugs for use in the defense of their application from malicious bots. These Plugs enable the following key features:

  1. Classification and blocking of IP addresses from cloud providers, a strong signal the traffic is from a bot and not a real user.

  2. Blocking clients that violate some user defined rule, for example, If an IP sends > 3 login requests in a 1 second period, create an alert and ban the IP.

  3. Custom block and allow lists, as defined in your site's Paraxial.io account.


requirements-and-installation

Requirements and Installation

optional-install-remote_ip-in-your-application

(Optional) Install remote_ip in your application

If your application is showing a different conn.remote_ip than expected, it is probably behind a proxy. Install the remote_ip library to fix this.

install-paraxial-in-your-application-s-mix-exs-file

Install :paraxial in your application's mix.exs file:

def deps do
  [
    {:paraxial, "~> 0.1.0"}
  ]
end

use-plug-plug-requestid-in-your-application-s-endpoint-ex-file

Use plug Plug.RequestId in your application's endpoint.ex file:

The majority of Phoenix applications do this by default. Check your endpoint.ex file for the line:

  plug Plug.RequestId

This plug sets x-request-id, which is required for the Paraxial agent to work correctly.


application-configuration-example

Application Configuration Example:

In your Paraxial.io account, we recommend creating two different sites for your application. One site for development/testing, and one site for production. For your local environment, edit your application's config/dev.exs:

config :paraxial,
  paraxial_api_key: System.get_env("PARAXIAL_API_KEY"),
  paraxial_url: "https://app.paraxial.io",
  fetch_cloud_ips: true,
  bulk: %{email: %{trusted: 100, untrusted: 3}},
  trusted_domains: MapSet.new(["paraxial.io", "blackcatprojects.xyz"])

Configuration keys and values:

  1. paraxial_api_key - Found in your site's settings page. Required for secure communication between the agent and Paraxial.io backend service.

  2. paraxial_url - This is most likely https://app.paraxial.io for your configuration.

  3. fetch_cloud_ips - By default, Paraxial.io will sent HTTP requests to retrieve the public IP ranges of several cloud providers. If you wish to disable this, set fetch_cloud_ips to false. When disabled, matching incoming requests against cloud IP addresses will not work.


check-configuration-settings

Check Configuration Settings

It is highly recommend you stop here and check that your application is configured correctly for your development environment before preceding.

  1. Set your application's local logging level to debug. This will allow you to see debug messages from the Paraxial agent. Example config/dev.exs:
config :logger, level: :debug
  1. Check the Paraxial lines in config/dev.exs are similar to:
config :paraxial,
  paraxial_api_key: System.get_env("PARAXIAL_API_KEY"),
  paraxial_url: "https://app.paraxial.io",
  fetch_cloud_ips: true,
  bulk: %{email: %{trusted: 100, untrusted: 3}},
  trusted_domains: MapSet.new(["paraxial.io", "blackcatprojects.xyz"])
  1. Start your application locally, read the debug lines from Paraxial.

Bad start:

@ house % mix phx.server
[warning] Paraxial API key not found.

This warning means your application is not configured correctly. Check your config files.

Bad start:

[error] Task #PID<0.764.0> started from Paraxial.Crow terminating
** (Protocol.UndefinedError) protocol Enumerable not implemented for nil of type Atom. Thi

This warning means you have an api_key and url defined, but at least one of them is incorrect. Check both.

Good start:

@ house % mix phx.server
[debug] [Paraxial] :fetch_cloud_ips set to true, fetching...
[debug] [Paraxial] Prefixes downloaded for aws: 7981
[debug] [Paraxial] Prefixes downloaded for azure: 59042
[debug] [Paraxial] Prefixes downloaded for digital_ocean: 1640
[debug] [Paraxial] Prefixes downloaded for gcp: 531
[debug] [Paraxial] Prefixes downloaded for oracle: 490
[debug] [Paraxial] Prefixes length with duplicates: 69684
[debug] [Paraxial] Iptrie count - 41834
[debug] [Paraxial] Iptrie size in MB: 1.299092
[debug] [Paraxial] Agent start success
[info] Running HouseWeb.Endpoint with cowboy 2.9.0 at 127.0.0.1:4002 (http)
[info] Access HouseWeb.Endpoint at http://localhost:4002
[watch] build finished, watching for changes...

Now that the Paraxial agent is running in your application, it is time to configure the Paraxial Plugs.

paraxial-api-functions

Paraxial API Functions

Paraxial.bulk_allowed?(email, bulk_action, count)

Input: An application user's email address, the name of a bulk action, and the count for the action.

Return value: True if the user is allowed to perform the action, false otherwise.

Example config:

config :paraxial,
  # ...
  bulk: %{email: %{trusted: 100, untrusted: 3}},
  trusted_domains: MapSet.new(["paraxial.io", "blackcatprojects.xyz"])
> Paraxial.bulk_allowed?("mike@blackcatprojects.xyz", :email, 3)
> true

> Paraxial.bulk_allowed?("mike@blackcatprojects.xyz", :email, 100)
> true

> Paraxial.bulk_allowed?("mike@test.xyz", :email, 4)
> false

paraxial-plug-configuration

Paraxial Plug Configuration

The Paraxial.io Agent provides several Plugs to be used in your application code:

  1. Paraxial.AllowedPlug - Required, this Plug determines if an incoming requests matches your allow/block lists. If a request is halted by this Plug, internally Paraxial will still record it.

  2. Paraxial.RecordPlug - Required, records incoming HTTP requests into a local buffer, then sends them to the Paraxial.io backend.

  3. Paraxial.AssignCloudIP - Optional, if the remote_ip of an incoming request matching a cloud provider IP address, this plug will add metadata to the conn via an assigns. For example, if a conn's remote_ip matches aws, this plug will do assigns(conn, :paraxial_cloud_ip, :aws).

  4. Paraxial.BlockCloudIP - Optional, similar to AssignCloudIP. When a conn matches a cloud provider IP, the assign is updated and the conn is halted, with a 404 response sent to the client.

plug-installation

Plug Installation

To install Paraxial's plugs, open your application's endpoint.ex file and add the following before and after your Router:

plug Paraxial.AllowedPlug
plug Paraxial.RecordPlug
plug ExampleApp.Router
plug Paraxial.RecordPlug

When a request comes in, it first goes through the AllowedPlug. If it matches an IP on the ban list, it is blocked and the conn is halted. Requests that are halted in the AllowedPlug are still recorded, even though they never reach RecordPlug.

If a request passes AllowedPlug, un-halted, it has not been recorded yet, so it goes into the RecordPlug. The reason for putting a RecordPlug before the Router is to record requests that fail to match a path in the Router.

In your application you have the ability to define certain assigns, such as :paraxial_login_user_name, to map IP addresses to login attempts. After the Router, the request conn passes through RecordPlug again, with updated information (such as new assigns). If a request passes through both RecordPlugs, only the conn from the second one is recorded.

faq

FAQ

Q: Phoenix applications send a response in the Router, why do you have a plug after the router?

A: It is still possible to read values off a conn that has been sent back to the user. RecordPlug is read-only, it never sends a response based on the conn, so it is okay to have one after the Router.

paraxial-conn-assigns-index

Paraxial Conn Assigns Index

This is a table of every assigns value Paraxial may set on an incoming conn. To avoid conflict with assigns in your application code, each assigns is prefixed with paraxial.

KeySet ByType
:paraxial_login_successUser ApplicationBoolean
:paraxial_login_user_nameUser ApplicationString
:paraxial_current_userUser ApplicationString
:paraxial_cloud_ipParaxial AgentString (aws, azure, etc.)

how-to-use-assigns-in-your-application

How to Use Assigns in your Application

To monitor login attempts, use:

assign(conn, :paraxial_login_success, true/false)

in your Phoenix application's authentication system.

If you want to keep track of user names, use:

assign(conn, :paraxial_login_user_name, "userNameHere")

installation

Installation

def deps do
  [
    {:paraxial, "~> 0.0.2"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/paraxial.

Mix deps versions, https://hexdocs.pm/elixir/Version.html