diff --git a/ostp-core/src/protocol.rs b/ostp-core/src/protocol.rs index 92bee13..98b9717 100644 --- a/ostp-core/src/protocol.rs +++ b/ostp-core/src/protocol.rs @@ -236,7 +236,9 @@ impl ProtocolMachine { let session_id = u32::from_be_bytes([raw_vec[0], raw_vec[1], raw_vec[2], raw_vec[3]]); if session_id != self.session_id { - tracing::error!("session id mismatch! expected={:#010x}, got={:#010x}, is_handshake={}, raw_len={}", self.session_id, session_id, is_handshake, raw_vec.len()); + // Per-packet, attacker-triggerable event: keep at debug and don't + // dump internal session ids (log-flood + info-leak surface). + tracing::debug!("session id mismatch (is_handshake={})", is_handshake); return Err(ProtocolError::State("session id mismatch".to_string())); } @@ -262,8 +264,7 @@ impl ProtocolMachine { noise_len, raw_vec.len() - 6 ))); } - tracing::info!("handle_inbound: raw_vec.len()={}, noise_len={}, raw_vec[0..6]={:?}", raw_vec.len(), noise_len, &raw_vec[0..6]); - + let mut read_out = vec![0_u8; 1024]; let n = self.noise.read_handshake(&raw_vec[6..6 + noise_len], &mut read_out).map_err(|e| { ProtocolError::Crypto(format!("noise-read: {:?} (raw_len={}, noise_len={})", e, raw_vec.len(), noise_len)) @@ -362,11 +363,11 @@ impl ProtocolMachine { } FrameKind::Resume => { // 0-RTT: treat early data as application data - tracing::info!("0-RTT Resume frame received, processing early data"); + tracing::debug!("0-RTT Resume frame received, processing early data"); ProtocolAction::DeliverApp(packet.header.stream_id, packet.payload) } FrameKind::Close => { - tracing::info!("Received Close frame, terminating session"); + tracing::debug!("Received Close frame, terminating session"); self.state = OstpState::Closed; ProtocolAction::Noop } diff --git a/ostp-server/src/api.rs b/ostp-server/src/api.rs index 5d38ffd..229c5be 100644 --- a/ostp-server/src/api.rs +++ b/ostp-server/src/api.rs @@ -633,7 +633,7 @@ async fn handle_create_user( return api_error::("failed to save configuration"); } - tracing::info!("API: created user key {}", &key[..8.min(key.len())]); + tracing::info!("API: created user key (fp={})", crate::dispatcher::key_fp(&key)); (StatusCode::OK, ApiResponse::success(key)) } diff --git a/ostp-server/src/dispatcher.rs b/ostp-server/src/dispatcher.rs index 0d69b39..8316ab4 100644 --- a/ostp-server/src/dispatcher.rs +++ b/ostp-server/src/dispatcher.rs @@ -106,6 +106,15 @@ pub struct Dispatcher { /// capping flood-driven trial work at TRIAL_RATE × num_keys crypto ops/sec. const TRIAL_RATE: f64 = 100.0; +/// Short, non-reversible fingerprint of an access key for logs. The access key +/// is a shared secret, so it must never be written to logs verbatim; this lets +/// an operator correlate events without exposing the key itself. +pub(crate) fn key_fp(access_key: &str) -> String { + use sha2::{Digest, Sha256}; + let h = Sha256::digest(access_key.as_bytes()); + format!("{:02x}{:02x}{:02x}", h[0], h[1], h[2]) +} + #[allow(dead_code)] impl Dispatcher { pub fn new(machine_config: ProtocolConfig, access_keys: Arc>>) -> Self { @@ -289,7 +298,7 @@ impl Dispatcher { let user_stats = self.get_or_create_user_stats(&access_key); if !key_valid || user_stats.is_over_limit() { tracing::info!("Dropping session {} for key {} (valid={}, over_limit={})", - session_id, access_key, key_valid, user_stats.is_over_limit()); + session_id, key_fp(&access_key), key_valid, user_stats.is_over_limit()); self.drop_session(session_id); return Ok(DispatchOutcome::Unauthorized); } @@ -467,7 +476,7 @@ impl Dispatcher { // Check traffic limit before accepting if user_stats.is_over_limit() { - tracing::warn!("User {} exceeded traffic limit, rejecting handshake from {}", candidate_key, peer); + tracing::warn!("User {} exceeded traffic limit, rejecting handshake from {}", key_fp(&candidate_key), peer); return Ok(DispatchOutcome::Unauthorized); } diff --git a/ostp-server/src/lib.rs b/ostp-server/src/lib.rs index 2177eb9..f3ff586 100644 --- a/ostp-server/src/lib.rs +++ b/ostp-server/src/lib.rs @@ -303,7 +303,8 @@ pub async fn run_server( } } UiEvent::KeyCreated { key } => { - tracing::info!("Access key created: {key}"); + // Never log the access key verbatim — it's a shared secret. + tracing::info!("Access key created (fp={})", crate::dispatcher::key_fp(&key)); } UiEvent::UnauthorizedProbe { peer, bytes } => { if debug {