Skip to content

Commit 6f56832

Browse files
authored
refactor: honor send_default_pii in sentry-actix and sentry-tower (#771)
* refactor: honor `send-default-pii` in `sentry-actix` and `sentry-tower` * also actix request body * improve * deprecate instead of removing * improve * improve
1 parent 2f9d247 commit 6f56832

File tree

6 files changed

+74
-19
lines changed

6 files changed

+74
-19
lines changed

sentry-actix/src/lib.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ use futures_util::future::{ok, Future, Ready};
8888
use futures_util::{FutureExt as _, TryStreamExt as _};
8989

9090
use sentry_core::protocol::{self, ClientSdkPackage, Event, Request};
91+
use sentry_core::utils::is_sensitive_header;
9192
use sentry_core::MaxRequestBodySize;
9293
use sentry_core::{Hub, SentryFutureExt};
9394

@@ -212,6 +213,7 @@ pub struct SentryMiddleware<S> {
212213

213214
fn should_capture_request_body(
214215
headers: &HeaderMap,
216+
with_pii: bool,
215217
max_request_body_size: MaxRequestBodySize,
216218
) -> bool {
217219
let is_chunked = headers
@@ -220,15 +222,16 @@ fn should_capture_request_body(
220222
.map(|transfer_encoding| transfer_encoding.contains("chunked"))
221223
.unwrap_or(false);
222224

223-
let is_valid_content_type = headers
224-
.get(header::CONTENT_TYPE)
225-
.and_then(|h| h.to_str().ok())
226-
.is_some_and(|content_type| {
227-
matches!(
228-
content_type,
229-
"application/json" | "application/x-www-form-urlencoded"
230-
)
231-
});
225+
let is_valid_content_type = with_pii
226+
|| headers
227+
.get(header::CONTENT_TYPE)
228+
.and_then(|h| h.to_str().ok())
229+
.is_some_and(|content_type| {
230+
matches!(
231+
content_type,
232+
"application/json" | "application/x-www-form-urlencoded"
233+
)
234+
});
232235

233236
let is_within_size_limit = headers
234237
.get(header::CONTENT_LENGTH)
@@ -322,7 +325,7 @@ where
322325
async move {
323326
let mut req = req;
324327

325-
if should_capture_request_body(req.headers(), max_request_body_size) {
328+
if should_capture_request_body(req.headers(), with_pii, max_request_body_size) {
326329
sentry_req.data = Some(capture_request_body(&mut req).await);
327330
}
328331

@@ -424,6 +427,7 @@ fn sentry_request_from_http(request: &ServiceRequest, with_pii: bool) -> Request
424427
.headers()
425428
.iter()
426429
.filter(|(_, v)| !v.is_sensitive())
430+
.filter(|(k, _)| with_pii || !is_sensitive_header(k.as_str()))
427431
.map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
428432
.collect(),
429433
..Default::default()

sentry-core/src/clientoptions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub struct ClientOptions {
120120
pub max_breadcrumbs: usize,
121121
/// Attaches stacktraces to messages.
122122
pub attach_stacktrace: bool,
123-
/// If turned on some default PII informat is attached.
123+
/// If turned on, some information that can be considered PII is captured, such as potentially sensitive HTTP headers and user IP address in HTTP server integrations.
124124
pub send_default_pii: bool,
125125
/// The server name to be reported.
126126
pub server_name: Option<Cow<'static, str>>,

sentry-core/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,6 @@ pub mod test;
159159
pub use sentry_types as types;
160160
pub use sentry_types::protocol::v7 as protocol;
161161
pub use sentry_types::protocol::v7::{Breadcrumb, Envelope, Level, User};
162+
163+
// utilities reused across integrations
164+
pub mod utils;

sentry-core/src/utils.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//! Utilities reused across dependant crates and integrations.
2+
3+
const SENSITIVE_HEADERS_UPPERCASE: &[&str] = &[
4+
"AUTHORIZATION",
5+
"PROXY_AUTHORIZATION",
6+
"COOKIE",
7+
"SET_COOKIE",
8+
"X_FORWARDED_FOR",
9+
"X_REAL_IP",
10+
"X_API_KEY",
11+
];
12+
13+
/// Determines if the HTTP header with the given name shall be considered as potentially carrying
14+
/// sensitive data.
15+
pub fn is_sensitive_header(name: &str) -> bool {
16+
SENSITIVE_HEADERS_UPPERCASE.contains(&name.to_ascii_uppercase().replace("-", "_").as_str())
17+
}

sentry-tower/src/http.rs

+38-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use std::task::{Context, Poll};
55

66
use http::{header, uri, Request, Response, StatusCode};
77
use pin_project::pinned_drop;
8-
use sentry_core::protocol;
8+
use sentry_core::utils::is_sensitive_header;
9+
use sentry_core::{protocol, Hub};
910
use tower_layer::Layer;
1011
use tower_service::Service;
1112

12-
/// Tower Layer that logs Http Request Headers.
13+
/// Tower Layer that captures Http Request information.
1314
///
14-
/// The Service created by this Layer can also optionally start a new
15+
/// The Service created by this Layer can optionally start a new
1516
/// performance monitoring transaction for each incoming request,
1617
/// continuing the trace based on incoming distributed tracing headers.
1718
///
@@ -20,35 +21,63 @@ use tower_service::Service;
2021
/// or similar. In this case, users should manually override the transaction name
2122
/// in the request handler using the [`Scope::set_transaction`](sentry_core::Scope::set_transaction)
2223
/// method.
24+
///
25+
/// By default, the service will filter out potentially sensitive headers from the captured
26+
/// requests. By enabling `with_pii`, you can opt in to capturing all headers instead.
2327
#[derive(Clone, Default)]
2428
pub struct SentryHttpLayer {
2529
start_transaction: bool,
30+
with_pii: bool,
2631
}
2732

2833
impl SentryHttpLayer {
29-
/// Creates a new Layer that only logs Request Headers.
34+
/// Creates a new Layer that only captures request information.
35+
/// If a client is bound to the main Hub (i.e. the SDK has already been initialized), set `with_pii` based on the `send_default_pii` client option.
3036
pub fn new() -> Self {
31-
Self::default()
37+
let mut slf = Self::default();
38+
Hub::main()
39+
.client()
40+
.inspect(|client| slf.with_pii = client.options().send_default_pii);
41+
slf
3242
}
3343

3444
/// Creates a new Layer which starts a new performance monitoring transaction
3545
/// for each incoming request.
46+
#[deprecated(since = "0.38.0", note = "please use `enable_transaction` instead")]
3647
pub fn with_transaction() -> Self {
3748
Self {
3849
start_transaction: true,
50+
with_pii: false,
3951
}
4052
}
53+
54+
/// Enable starting a new performance monitoring transaction for each incoming request.
55+
#[must_use]
56+
pub fn enable_transaction(mut self) -> Self {
57+
self.start_transaction = true;
58+
self
59+
}
60+
61+
/// Include PII in captured requests. Potentially sensitive headers are not filtered out.
62+
#[must_use]
63+
pub fn enable_pii(mut self) -> Self {
64+
self.with_pii = true;
65+
self
66+
}
4167
}
4268

43-
/// Tower Service that logs Http Request Headers.
69+
/// Tower Service that captures Http Request information.
4470
///
45-
/// The Service can also optionally start a new performance monitoring transaction
71+
/// The Service can optionally start a new performance monitoring transaction
4672
/// for each incoming request, continuing the trace based on incoming
4773
/// distributed tracing headers.
74+
///
75+
/// If `with_pii` is disabled, sensitive headers will be filtered out.
4876
#[derive(Clone)]
4977
pub struct SentryHttpService<S> {
5078
service: S,
5179
start_transaction: bool,
80+
with_pii: bool,
5281
}
5382

5483
impl<S> Layer<S> for SentryHttpLayer {
@@ -58,6 +87,7 @@ impl<S> Layer<S> for SentryHttpLayer {
5887
Self::Service {
5988
service,
6089
start_transaction: self.start_transaction,
90+
with_pii: self.with_pii,
6191
}
6292
}
6393
}
@@ -161,6 +191,7 @@ where
161191
.headers()
162192
.into_iter()
163193
.filter(|(_, value)| !value.is_sensitive())
194+
.filter(|(header, _)| self.with_pii || !is_sensitive_header(header.as_str()))
164195
.map(|(header, value)| {
165196
(
166197
header.to_string(),

sentry-tower/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@
126126
//! # type Request = http::Request<String>;
127127
//! let layer = tower::ServiceBuilder::new()
128128
//! .layer(sentry_tower::NewSentryLayer::<Request>::new_from_top())
129-
//! .layer(sentry_tower::SentryHttpLayer::with_transaction());
129+
//! .layer(sentry_tower::SentryHttpLayer::new().enable_transaction());
130130
//! # }
131131
//! ```
132132
//!

0 commit comments

Comments
 (0)