Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(server): host filter via URI read authority #1178

Merged
merged 1 commit into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use std::time::Duration;

use crate::future::{ConnectionGuard, ServerHandle, StopHandle};
use crate::logger::{Logger, TransportProtocol};
use crate::transport::http::fetch_authority;
use crate::transport::{http, ws};

use futures_util::future::{self, Either, FutureExt};
Expand All @@ -44,7 +45,7 @@ use jsonrpsee_core::id_providers::RandomIntegerIdProvider;

use jsonrpsee_core::server::{AllowHosts, Authority, AuthorityError, Methods, WhitelistedHosts};
use jsonrpsee_core::traits::IdProvider;
use jsonrpsee_core::{http_helpers, Error, TEN_MB_SIZE_BYTES};
use jsonrpsee_core::{Error, TEN_MB_SIZE_BYTES};

use soketto::handshake::http::is_upgrade_request;
use tokio::net::{TcpListener, TcpStream, ToSocketAddrs};
Expand Down Expand Up @@ -651,16 +652,11 @@ impl<L: Logger> hyper::service::Service<hyper::Request<hyper::Body>> for TowerSe
fn call(&mut self, request: hyper::Request<hyper::Body>) -> Self::Future {
tracing::trace!("{:?}", request);

let host = match http_helpers::read_header_value(request.headers(), hyper::header::HOST) {
Some(host) => host,
None if request.version() == hyper::Version::HTTP_2 => match request.uri().host() {
Some(host) => host,
None => return async move { Ok(http::response::malformed()) }.boxed(),
},
None => return async move { Ok(http::response::malformed()) }.boxed(),
let Some(authority) = fetch_authority(&request) else {
return async { Ok(http::response::malformed()) }.boxed();
};

if let Err(e) = self.inner.allow_hosts.verify(host) {
if let Err(e) = self.inner.allow_hosts.verify(authority) {
tracing::debug!("Denied request: {}", e);
return async { Ok(http::response::host_not_allowed()) }.boxed();
}
Expand Down
16 changes: 15 additions & 1 deletion server/src/transport/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use futures_util::future::Either;
use futures_util::stream::{FuturesOrdered, StreamExt};
use hyper::Method;
use jsonrpsee_core::error::GenericTransportError;
use jsonrpsee_core::http_helpers::read_body;
use jsonrpsee_core::http_helpers::{self, read_body};
use jsonrpsee_core::server::helpers::{
batch_response_error, prepare_error, BatchResponseBuilder, MethodResponse, MethodResponseResult,
};
Expand Down Expand Up @@ -50,6 +50,20 @@ pub(crate) async fn reject_connection(socket: tokio::net::TcpStream) {
}
}

/// The `Authority` can be sent by the client in the `Host header` or in the `URI`
/// such that we must check both.
pub(crate) fn fetch_authority(request: &hyper::Request<hyper::Body>) -> Option<&str> {
let host_header = http_helpers::read_header_value(request.headers(), hyper::header::HOST);
let uri = request.uri().authority();
Copy link
Member Author

@niklasad1 niklasad1 Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fix and mainly regards HTTP2 but could be some other edge-case as well.

Thus, if one would enable a filter for port X and the request is targets port X but it's not read and would regarded as the default port if just the host is read i.e, not the port


match (host_header, uri) {
(Some(a1), Some(a2)) if a1 == a2.as_str() => Some(a1),
(Some(a), None) => Some(a),
(None, Some(a)) => Some(a.as_str()),
_ => None,
}
}

#[derive(Debug)]
pub(crate) struct ProcessValidatedRequest<'a, L: Logger> {
pub(crate) request: hyper::Request<hyper::Body>,
Expand Down