Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion lib/sentry/scrubber.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ defmodule Sentry.Scrubber do

#{Enum.map_join(@default_scrubbed_header_keys, "\n", &" * `\"#{&1}\"`")}

The `"referer"` header is kept, but its value is scrubbed as a URL: it names
the page a request came from, so a secret in that page's query string would
otherwise be reported next to a request URL that was already redacted.

Values matching a credit-card-like pattern (13–16 digits, optionally
separated by spaces or dashes) are also replaced with the placeholder.

Expand Down Expand Up @@ -641,20 +645,31 @@ defmodule Sentry.Scrubber do
do: scrub_params_value(conn.params)

def scrub(conn, :headers) when is_struct(conn, Plug.Conn) do
Enum.reject(conn.req_headers, fn
conn.req_headers
|> Enum.reject(fn
{name, _value} when is_binary(name) ->
String.downcase(name) in @default_scrubbed_header_keys

_ ->
false
end)
|> Enum.map(&scrub_header/1)
end

def scrub(conn, :cookies) when is_struct(conn, Plug.Conn), do: %{}

def scrub(conn, :url) when is_struct(conn, Plug.Conn),
do: scrub_url(Plug.Conn.request_url(conn))

# A referer is the full URL of the page the request came from, so a secret in
# that page's query string rides along with every request made from it — next
# to a request URL this same scrubbing has already redacted.
defp scrub_header({name, value}) when is_binary(name) and is_binary(value) do
if String.downcase(name) == "referer", do: {name, scrub_url(value)}, else: {name, value}
end

defp scrub_header(header), do: header

# Resolves a single conn field's strategy (from `@scrubbable_conn_fields` or a
# `scrub(conn, overrides)` override) to its scrubbed value:
#
Expand Down
32 changes: 32 additions & 0 deletions test/sentry/scrubber_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,38 @@ defmodule Sentry.ScrubberTest do
end

describe "scrub/2 with a Plug.Conn field" do
test ":headers redacts sensitive query params carried by the referer" do
conn = %Plug.Conn{
req_headers: [
{"referer", "http://example.com/reset?token=hunter2&page=2"},
{"user-agent", "a browser"}
]
}

assert [{"referer", referer}, {"user-agent", "a browser"}] =
Scrubber.scrub(conn, :headers)

refute referer =~ "hunter2"
assert referer == "http://example.com/reset?token=#{Scrubber.scrubbed_value()}&page=2"
end

test ":headers leaves a referer without a query string alone" do
conn = %Plug.Conn{req_headers: [{"referer", "http://example.com/reset"}]}

assert [{"referer", "http://example.com/reset"}] = Scrubber.scrub(conn, :headers)
end

test ":headers still drops the sensitive header list" do
conn = %Plug.Conn{
req_headers: [
{"authorization", "Bearer hunter2"},
{"referer", "http://example.com/ok"}
]
}

assert [{"referer", "http://example.com/ok"}] = Scrubber.scrub(conn, :headers)
end

test ":url scrubs sensitive query parameters" do
conn = %Plug.Conn{
scheme: :http,
Expand Down
Loading