Host validation (again) (#1666)

* Revert "Revert "Validating Host headers in RPC requests" (#1663)"

This reverts commit 3cc3dbef66.

* Fixing binding on MacOS
This commit is contained in:
Tomasz Drwięga
2016-07-20 12:34:17 +02:00
committed by Gav Wood
parent 9c8b80f998
commit 0cba70fba3
11 changed files with 172 additions and 56 deletions

View File

@@ -107,6 +107,11 @@ API and Console Options:
name. Possible name are web3, eth, net, personal,
ethcore, ethcore_set, traces.
[default: web3,eth,net,ethcore,personal,traces].
--jsonrpc-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none",
[default: none].
--no-ipc Disable JSON-RPC over IPC service.
--ipc-path PATH Specify custom path for JSON-RPC over IPC service
@@ -118,8 +123,8 @@ API and Console Options:
--dapps-port PORT Specify the port portion of the Dapps server
[default: 8080].
--dapps-interface IP Specify the hostname portion of the Dapps
server, IP should be an interface's IP address, or
all (all interfaces) or local [default: local].
server, IP should be an interface's IP address,
or local [default: local].
--dapps-user USERNAME Specify username for Dapps server. It will be
used in HTTP Basic Authentication Scheme.
If --dapps-pass is not specified you will be
@@ -311,6 +316,7 @@ pub struct Args {
pub flag_jsonrpc_interface: String,
pub flag_jsonrpc_port: u16,
pub flag_jsonrpc_cors: Option<String>,
pub flag_jsonrpc_hosts: String,
pub flag_jsonrpc_apis: String,
pub flag_no_ipc: bool,
pub flag_ipc_path: String,

View File

@@ -424,9 +424,19 @@ impl Configuration {
self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone())
}
pub fn rpc_cors(&self) -> Vec<String> {
pub fn rpc_cors(&self) -> Option<Vec<String>> {
let cors = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone());
cors.map_or_else(Vec::new, |c| c.split(',').map(|s| s.to_owned()).collect())
cors.map(|c| c.split(',').map(|s| s.to_owned()).collect())
}
pub fn rpc_hosts(&self) -> Option<Vec<String>> {
match self.args.flag_jsonrpc_hosts.as_ref() {
"none" => return Some(Vec::new()),
"all" => return None,
_ => {}
}
let hosts = self.args.flag_jsonrpc_hosts.split(',').map(|h| h.into()).collect();
Some(hosts)
}
fn geth_ipc_path(&self) -> String {
@@ -541,7 +551,6 @@ impl Configuration {
pub fn dapps_interface(&self) -> String {
match self.args.flag_dapps_interface.as_str() {
"all" => "0.0.0.0",
"local" => "127.0.0.1",
x => x,
}.into()
@@ -597,7 +606,7 @@ mod tests {
assert_eq!(net.rpc_enabled, true);
assert_eq!(net.rpc_interface, "all".to_owned());
assert_eq!(net.rpc_port, 8000);
assert_eq!(conf.rpc_cors(), vec!["*".to_owned()]);
assert_eq!(conf.rpc_cors(), Some(vec!["*".to_owned()]));
assert_eq!(conf.rpc_apis(), "web3,eth".to_owned());
}
@@ -619,5 +628,22 @@ mod tests {
assert(conf1);
assert(conf2);
}
#[test]
fn should_parse_rpc_hosts() {
// given
// when
let conf0 = parse(&["parity"]);
let conf1 = parse(&["parity", "--jsonrpc-hosts", "none"]);
let conf2 = parse(&["parity", "--jsonrpc-hosts", "all"]);
let conf3 = parse(&["parity", "--jsonrpc-hosts", "ethcore.io,something.io"]);
// then
assert_eq!(conf0.rpc_hosts(), Some(Vec::new()));
assert_eq!(conf1.rpc_hosts(), Some(Vec::new()));
assert_eq!(conf2.rpc_hosts(), None);
assert_eq!(conf3.rpc_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
}
}

View File

@@ -280,6 +280,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig,
port: network_settings.rpc_port,
apis: conf.rpc_apis(),
cors: conf.rpc_cors(),
hosts: conf.rpc_hosts(),
}, &dependencies);
// setup ipc rpc

View File

@@ -32,7 +32,8 @@ pub struct HttpConfiguration {
pub interface: String,
pub port: u16,
pub apis: String,
pub cors: Vec<String>,
pub cors: Option<Vec<String>>,
pub hosts: Option<Vec<String>>,
}
pub struct IpcConfiguration {
@@ -66,7 +67,7 @@ pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Option<RpcServe
let url = format!("{}:{}", conf.interface, conf.port);
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
Some(setup_http_rpc_server(deps, &addr, conf.cors, apis))
Some(setup_http_rpc_server(deps, &addr, conf.cors, conf.hosts, apis))
}
fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server {
@@ -78,21 +79,17 @@ fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server {
pub fn setup_http_rpc_server(
dependencies: &Dependencies,
url: &SocketAddr,
cors_domains: Vec<String>,
cors_domains: Option<Vec<String>>,
allowed_hosts: Option<Vec<String>>,
apis: Vec<&str>,
) -> RpcServer {
let server = setup_rpc_server(apis, dependencies);
let start_result = server.start_http(url, cors_domains);
let ph = dependencies.panic_handler.clone();
let start_result = server.start_http(url, cors_domains, allowed_hosts, ph);
match start_result {
Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err),
Err(e) => die!("RPC: {:?}", e),
Ok(server) => {
server.set_panic_handler(move || {
ph.notify_all("Panic in RPC thread.".to_owned());
});
server
},
Ok(server) => server,
}
}