fix(security): stop trusting client-supplied forwarded headers in rate limiting
extract_client_ip took X-Real-IP/X-Forwarded-For from any request, so a client talking to the backend directly (the FIPS peer listener, or any non-proxy path) could rotate a fake IP per request and never trip the login rate limiter. The accept loop now records the TCP peer address in request extensions, and forwarded headers are honored only when the connection itself is from loopback — where nginx overwrites X-Real-IP with the real client address. Direct connections bucket under their socket IP. §C of the 1.8.0 hardening plan; 3 new unit tests cover the loopback/direct/no-header matrix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
bd7edb4376
commit
9020b8526c
@@ -1034,9 +1034,13 @@ async fn accept_loop(
|
||||
let permit = active_connections.clone().acquire_owned().await;
|
||||
tokio::spawn(async move {
|
||||
let _permit = permit;
|
||||
let service = service_fn(move |req: hyper::Request<hyper::Body>| {
|
||||
let service = service_fn(move |mut req: hyper::Request<hyper::Body>| {
|
||||
let handler = handler.clone();
|
||||
async move {
|
||||
// Record the TCP peer so rate limiting only trusts
|
||||
// forwarded headers on loopback (nginx) connections.
|
||||
req.extensions_mut()
|
||||
.insert(crate::api::rpc::PeerAddr(peer_addr));
|
||||
if peer_only && !is_peer_allowed_path(req.uri().path()) {
|
||||
let resp = hyper::Response::builder()
|
||||
.status(hyper::StatusCode::NOT_FOUND)
|
||||
|
||||
Reference in New Issue
Block a user