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:
Classification and blocking of IP addresses from cloud providers, a strong signal the traffic is from a bot and not a real user.
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
.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:
paraxial_api_key
- Found in your site's settings page. Required for secure communication between the agent and Paraxial.io backend service.paraxial_url
- This is most likelyhttps://app.paraxial.io
for your configuration.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, setfetch_cloud_ips
tofalse
. 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.
- 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
- 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"])
- 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:
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.Paraxial.RecordPlug
- Required, records incoming HTTP requests into a local buffer, then sends them to the Paraxial.io backend.Paraxial.AssignCloudIP
- Optional, if theremote_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 doassigns(conn, :paraxial_cloud_ip, :aws)
.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
.
Key | Set By | Type |
---|---|---|
:paraxial_login_success | User Application | Boolean |
:paraxial_login_user_name | User Application | String |
:paraxial_current_user | User Application | String |
:paraxial_cloud_ip | Paraxial Agent | String (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