Skip to content

Commit 037090c

Browse files
authored
Add url_scrubber for redacting URLs (#687)
1 parent 175cfad commit 037090c

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

lib/sentry/plug_context.ex

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ defmodule Sentry.PlugContext do
4444
4545
You can also pass it in as a `{module, fun}`, like so:
4646
47-
plug Sentry.PlugContext, body_scrubber: {MyModule, :scrub_params}
47+
plug Sentry.PlugContext, body_scrubber: {MySentryScrubber, :scrub_params}
4848
4949
> #### Large Files {: .tip}
5050
>
@@ -57,7 +57,7 @@ defmodule Sentry.PlugContext do
5757
configured similarly to body params, through the `:header_scrubber` configuration
5858
option:
5959
60-
defmodule MyHeaderScrubber do
60+
defmodule MySentryScrubber do
6161
def scrub_headers(conn) do
6262
# In this example, we do not want to include Content-Type or User-Agent
6363
# in reported headers, so we drop them.
@@ -70,11 +70,11 @@ defmodule Sentry.PlugContext do
7070
7171
Then, pass it into `Sentry.PlugContext`:
7272
73-
plug Sentry.PlugContext, header_scrubber: &MyHeaderScrubber.scrub_headers/1
73+
plug Sentry.PlugContext, header_scrubber: &MySentryScrubber.scrub_headers/1
7474
7575
It can also be passed in as a `{module, fun}` like so:
7676
77-
plug Sentry.PlugContext, header_scrubber: {MyModule, :scrub_headers}
77+
plug Sentry.PlugContext, header_scrubber: {MySentryScrubber, :scrub_headers}
7878
7979
### Scrubbing Cookies
8080
@@ -84,7 +84,31 @@ defmodule Sentry.PlugContext do
8484
8585
For example:
8686
87-
plug Sentry.PlugContext, cookie_scrubber: &MyCookieScrubber.scrub_cookies/1
87+
plug Sentry.PlugContext, cookie_scrubber: &MySentryScrubber.scrub_cookies/1
88+
89+
### Scrubbing URLs
90+
91+
*Available since v10.2.0.*
92+
93+
If any of your URLs contain sensitive tokens or other data, you should scrub them
94+
to remove the sensitive data. This can be configured similarly to body params,
95+
through the `:url_scrubber` configuration option. It should return a string:
96+
97+
defmodule MySentryScrubber do
98+
def scrub_url(conn) do
99+
conn
100+
|> Plug.Conn.request_url()
101+
|> String.replace(~r/secret-token\/\w+/, "secret-token/****")
102+
end
103+
end
104+
105+
Then pass it into `Sentry.PlugContext`:
106+
107+
plug Sentry.PlugContext, url_scrubber: &MySentryScrubber.scrub_url/1
108+
109+
You can also pass it in as a `{module, fun}`, like so:
110+
111+
plug Sentry.PlugContext, url_scrubber: {MySentryScrubber, :scrub_url}
88112
89113
## Including Request Identifiers
90114
@@ -141,6 +165,7 @@ defmodule Sentry.PlugContext do
141165
body_scrubber = Keyword.get(opts, :body_scrubber, {__MODULE__, :default_body_scrubber})
142166
header_scrubber = Keyword.get(opts, :header_scrubber, {__MODULE__, :default_header_scrubber})
143167
cookie_scrubber = Keyword.get(opts, :cookie_scrubber, {__MODULE__, :default_cookie_scrubber})
168+
url_scrubber = Keyword.get(opts, :url_scrubber, {__MODULE__, :default_url_scrubber})
144169

145170
remote_address_reader =
146171
Keyword.get(opts, :remote_address_reader, {__MODULE__, :default_remote_address_reader})
@@ -152,14 +177,14 @@ defmodule Sentry.PlugContext do
152177
|> Plug.Conn.fetch_query_params()
153178

154179
%{
155-
url: Plug.Conn.request_url(conn),
180+
url: apply_fun_with_conn(conn, url_scrubber, Plug.Conn.request_url(conn)),
156181
method: conn.method,
157-
data: apply_fun_with_conn(conn, body_scrubber),
182+
data: apply_fun_with_conn(conn, body_scrubber, %{}),
158183
query_string: conn.query_string,
159-
cookies: apply_fun_with_conn(conn, cookie_scrubber),
160-
headers: apply_fun_with_conn(conn, header_scrubber),
184+
cookies: apply_fun_with_conn(conn, cookie_scrubber, %{}),
185+
headers: apply_fun_with_conn(conn, header_scrubber, %{}),
161186
env: %{
162-
"REMOTE_ADDR" => apply_fun_with_conn(conn, remote_address_reader),
187+
"REMOTE_ADDR" => apply_fun_with_conn(conn, remote_address_reader, %{}),
163188
"REMOTE_PORT" => remote_port(conn),
164189
"SERVER_NAME" => conn.host,
165190
"SERVER_PORT" => conn.port,
@@ -191,9 +216,9 @@ defmodule Sentry.PlugContext do
191216
end
192217
end
193218

194-
defp apply_fun_with_conn(_conn, _function = nil), do: %{}
195-
defp apply_fun_with_conn(conn, {module, fun}), do: apply(module, fun, [conn])
196-
defp apply_fun_with_conn(conn, fun) when is_function(fun, 1), do: fun.(conn)
219+
defp apply_fun_with_conn(_conn, _function = nil, default), do: default
220+
defp apply_fun_with_conn(conn, {module, fun}, _default), do: apply(module, fun, [conn])
221+
defp apply_fun_with_conn(conn, fun, _default) when is_function(fun, 1), do: fun.(conn)
197222

198223
@doc """
199224
Scrubs **all** cookies off of the request.
@@ -203,6 +228,14 @@ defmodule Sentry.PlugContext do
203228
%{}
204229
end
205230

231+
@doc """
232+
Returns the request URL without modifying it.
233+
"""
234+
@spec default_url_scrubber(Plug.Conn.t()) :: String.t()
235+
def default_url_scrubber(conn) do
236+
Plug.Conn.request_url(conn)
237+
end
238+
206239
@doc """
207240
Scrubs the headers of a request.
208241

test/sentry/plug_context_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ defmodule Sentry.PlugContextTest do
1818
conn.cookies |> Map.new() |> Map.take(["not-secret"])
1919
end
2020

21+
def url_scrubber(conn) do
22+
conn |> Plug.Conn.request_url() |> String.replace(~r/secret-token\/\w+/, "secret-token/****")
23+
end
24+
2125
def remote_address_reader(conn) do
2226
case get_req_header(conn, "cf-connecting-ip") do
2327
[remote_ip | _] -> remote_ip
@@ -105,6 +109,13 @@ defmodule Sentry.PlugContextTest do
105109
assert %{"not-secret" => "not-secret"} == Sentry.Context.get_all().request.cookies
106110
end
107111

112+
test "allows configuring URL scrubber" do
113+
conn = conn(:get, "/secret-token/secret")
114+
call(conn, url_scrubber: {__MODULE__, :url_scrubber})
115+
116+
assert "http://www.example.com/secret-token/****" == Sentry.Context.get_all().request.url
117+
end
118+
108119
test "allows configuring request id header", %{conn: conn} do
109120
conn
110121
|> put_resp_header("my-request-id", "abc123")

0 commit comments

Comments
 (0)