View Source Sentry.PlugContext (Sentry v14.0.0)

A Plug for adding request context to Sentry events.

This module adds Sentry context metadata during the request in a Plug application. It includes defaults for scrubbing sensitive data, and options for customizing such behavior.

Usage

You can use this module in a Plug pipeline to add Sentry metadata:

plug Sentry.PlugContext

This plug will add context metadata to the request, which will be added to reported errors that happen during plug execution. For Cowboy applications, you will also need to use Sentry.PlugCapture.

Scrubbing POST Body Params

In order to send POST body parameters you should first scrub them of sensitive information. By default, they will be scrubbed with default_body_scrubber/1. This can be overridden by passing the :body_scrubber option, which accepts a Plug.Conn and returns a map to send. Setting :body_scrubber to nil will not send any data back. If you would like to make use of Sentry's default scrubber behavior in a custom scrubber, it can be called directly. An example configuration may look like the following:

defmodule MySentryScrubber do
  def scrub_params(conn) do
    # Makes use of the default body scrubbing to avoid sending password
    # and credit card information in plain text. To also prevent sending
    # our sensitive "my_secret_field" and "other_sensitive_data" fields,
    # we simply drop those keys.
    conn
    |> Sentry.PlugContext.default_body_scrubber()
    |> Map.drop(["my_secret_field", "other_sensitive_data"])
  end
end

Then pass it into Sentry.PlugContext:

plug Sentry.PlugContext, body_scrubber: &MySentryScrubber.scrub_params/1

You can also pass it in as a {module, fun}, like so:

plug Sentry.PlugContext, body_scrubber: {MySentryScrubber, :scrub_params}

Configuring Sensitive Parameter Keys

Available since 14.0.0.

If you only need to add key names to the SDK's denylist, you do not need a custom scrubber at all. The :scrubber configuration extends it globally, and applies to body params, query params, the query string, the request URL, and any map captured into a stacktrace frame variable:

config :sentry, scrubber: [param_keys: ["internal_ref"]]

Terms are matched as case-insensitive substrings of the key name. See Sentry.Scrubber.default_param_keys/0 for the built-in list.

Large Files

If you are sending large files in POST requests, we recommend you scrub them out through the :body_scrubber mechanism.

Scrubbing Headers

By default, Sentry uses default_header_scrubber/1 to scrub headers. This can be configured similarly to body params, through the :header_scrubber configuration option:

defmodule MySentryScrubber do
  def scrub_headers(conn) do
    # In this example, we do not want to include Content-Type or User-Agent
    # in reported headers, so we drop them. `default_header_scrubber/1`
    # takes the conn and returns a map of the retained headers, which we
    # then trim further.
    conn
    |> Sentry.PlugContext.default_header_scrubber()
    |> Map.drop(["content-type", "user-agent"])
  end
end

Then, pass it into Sentry.PlugContext:

plug Sentry.PlugContext, header_scrubber: &MySentryScrubber.scrub_headers/1

It can also be passed in as a {module, fun} like so:

plug Sentry.PlugContext, header_scrubber: {MySentryScrubber, :scrub_headers}

Scrubbing Cookies

By default Sentry will scrub all cookies before sending events (see scrub_cookies/1). It can be configured similarly to the headers and body scrubbers, but is configured via the :cookie_scrubber key.

For example:

plug Sentry.PlugContext, cookie_scrubber: &MySentryScrubber.scrub_cookies/1

Scrubbing URLs

Available since v10.2.0.

By default, Sentry.PlugContext scrubs sensitive query parameters (such as password, passwd, and secret) from the request URL before sending it to Sentry. To disable URL scrubbing entirely, set :url_scrubber to nil:

plug Sentry.PlugContext, url_scrubber: nil

If your URLs contain sensitive tokens or other data that the default scrubber does not cover, you can provide a custom scrubber via :url_scrubber. It should return a string. You can compose on top of the default behavior:

defmodule MySentryScrubber do
  def scrub_url(conn) do
    conn
    |> Sentry.PlugContext.default_url_scrubber()
    |> String.replace(~r/secret-token/w+/, "secret-token/****")
  end
end

Then pass it into Sentry.PlugContext:

plug Sentry.PlugContext, url_scrubber: &MySentryScrubber.scrub_url/1

You can also pass it in as a {module, fun}, like so:

plug Sentry.PlugContext, url_scrubber: {MySentryScrubber, :scrub_url}

The :url_scrubber governs more than the reported request URL: wherever the connection itself is reported — a %Plug.Conn{} inspected into a stacktrace frame variable, or a Phoenix.ActionClauseError captured by Sentry.PlugCapture — its request_path, path_info and query_string are derived from the scrubbed URL, so the example above redacts the token in all of them. Setting :url_scrubber to nil opts out; query_string is still scrubbed against the sensitive parameter keys.

Including Request Identifiers

If you're using Phoenix, Plug.RequestId, or any other method to set a request ID response header, and would like to include that information with errors reported by Sentry.PlugContext, use the :request_id_header option. It allows you to set which header key Sentry should check. It defaults to x-request-id, which Plug.RequestId (and therefore Phoenix) also default to.

plug Sentry.PlugContext, request_id_header: "application-request-id"

Remote Address Reader

Sentry.PlugContext includes a request's originating IP address under the REMOTE_ADDR environment key in Sentry. By default, we read it from the x-forwarded-for HTTP header, and if this header is not present, from conn.remote_ip.

If you wish to read this value differently (for example, from a different HTTP header), or modify it in some other way (such as by masking it), you can configure this behavior by passing the :remote_address_reader option:

plug Sentry.PlugContext, remote_address_reader: &MyModule.read_ip/1

The :remote_address_reader option must be a function that accepts a Plug.Conn returns a String.t/0 IP, or a {module, function} tuple, where module.function/1 takes a Plug.Conn and returns a String.t/0 IP.

Crashing Callbacks

Available since 14.0.0.

If a callback this plug accepts raises, throws, or exits, the request is still served and the event is still sent. Only the field that callback was responsible for falls back to the SDK's own default for that field:

OptionValue reported after a crash
:body_scrubberdefault_body_scrubber/1
:header_scrubberdefault_header_scrubber/1
:cookie_scrubberdefault_cookie_scrubber/1
:url_scrubberdefault_url_scrubber/1
:remote_address_readerthe x-forwarded-for header, falling back to conn.remote_ip

The other fields are still produced by their own callbacks. See the Crashing Callbacks section of the Sentry documentation for how the failure is logged and why a crashed scrubber sends data that only it was dropping.

Summary

Functions

Scrubs the body of a request.

Scrubs all cookies off of the request.

Scrubs the headers of a request.

Scrubs sensitive query parameters from the request URL.

Functions

Link to this function

default_body_scrubber(conn)

View Source
@spec default_body_scrubber(Plug.Conn.t()) :: map()

Scrubs the body of a request.

The default scrubbed keys are:

  • auth
  • token
  • secret
  • password
  • passwd
  • pwd
  • key
  • jwt
  • bearer
  • sso
  • saml
  • csrf
  • xsrf
  • credentials
  • session
  • sid
  • identity
Link to this function

default_header_scrubber(conn)

View Source
@spec default_header_scrubber(Plug.Conn.t()) :: map()

Scrubs the headers of a request.

The default scrubbed headers are:

  • authorization
  • authentication
  • cookie
Link to this function

default_url_scrubber(conn)

View Source
@spec default_url_scrubber(Plug.Conn.t()) :: String.t()

Scrubs sensitive query parameters from the request URL.

This is the default URL scrubber used by Sentry.PlugContext when no :url_scrubber option is configured. It delegates to Sentry.Scrubber.scrub_url/1. To compose on top of this default in a custom scrubber:

defmodule MySentryScrubber do
  def scrub_url(conn) do
    conn
    |> Sentry.PlugContext.default_url_scrubber()
    |> String.replace(~r/secret-token/w+/, "secret-token/****")
  end
end