feat: add logging of real remote ip in case of proxies (#138)
* Simplify code
* Header parsing and documentation
* Fixed code formatting
Co-authored-by: Jose Quintana <1700322+joseluisq@users.noreply.github.com>
Diff
docs/content/features/logging.md | 32 ++++++++++++++++++++++++++++++++
src/handler.rs | 12 +++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)
@@ -47,3 +47,35 @@ static-web-server -a "0.0.0.0" -p 8080 -d docker/public/ -g info --log-remote-ad
# 2022-05-23T22:24:50.519540Z INFO static_web_server::handler: incoming request: method=GET uri=/ remote_addr=192.168.1.126:57625
# 2022-05-23T22:25:26.516841Z INFO static_web_server::handler: incoming request: method=GET uri=/favicon.ico remote_addr=192.168.1.126:57625
```
## Log Real Remote IP
When used behind reverse proxy, reported `remote_addr` indicate proxy internal IP address and port, and not client real remote IP.
Proxy server can be configured to provide [X-Forwarded-For header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For), containing comma-separated list of IP addresses, starting with *client real remote IP*, and all following intermediate proxies (if any).
When *Remote Address (IP) logging* [is enabled](#log-remote-addresses), and `X-Forwarded-For` header is present and correctly formated, then log entries for requests will contain a `real_remote_ip` section with IP of remote client, **as reported by this header**.
We can simulate request as from behind reverse proxy with additional intermediate-proxy with following command:
```sh
curl --header "X-Forwarded-For: 203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348" http://0.0.0.0:8080
```
Log entry for such case will look like:
```log
2022-05-23T22:24:50.519540Z INFO static_web_server::handler: incoming request: method=GET uri=/ remote_addr=192.168.1.126:57625 real_remote_ip=203.0.113.195
```
**`SWS`** will parse `X-Forwarded-For` header, and if format of provided IP is invalid - it will be ignored to prevent log poisoning attacks. In such case `real_remote_ip` section will not be added.
Example from above, but with invalid header:
```sh
curl --header "X-Forwarded-For: <iframe src=//malware.attack>" http://0.0.0.0:8080
```
```log
2022-05-23T22:24:50.519540Z INFO static_web_server::handler: incoming request: method=GET uri=/ remote_addr=192.168.1.126:57625
```
Be aware, that contents of `X-Forwarded-For` header can be augumented by all proxies in the chain, and as such - remote IP address reported by it may not be trusted.
\ No newline at end of file
@@ -1,6 +1,6 @@
use headers::HeaderValue;
use hyper::{header::WWW_AUTHENTICATE, Body, Method, Request, Response, StatusCode};
use std::{future::Future, net::SocketAddr, path::PathBuf, sync::Arc};
use std::{future::Future, net::IpAddr, net::SocketAddr, path::PathBuf, sync::Arc};
use crate::{
basic_auth, compression, control_headers, cors, custom_headers, error_page, fallback_page,
@@ -62,6 +62,16 @@ impl RequestHandler {
if log_remote_addr {
remote_addr_str.push_str(" remote_addr=");
remote_addr_str.push_str(&remote_addr.map_or("".to_owned(), |v| v.to_string()));
if let Some(client_ip_address) = headers
.get("X-Forwarded-For")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.split(',').next())
.and_then(|s| s.trim().parse::<IpAddr>().ok())
{
remote_addr_str.push_str(" real_remote_ip=");
remote_addr_str.push_str(&client_ip_address.to_string())
}
}
tracing::info!(
"incoming request: method={} uri={}{}",