diff --git a/Cargo.toml b/Cargo.toml index 162194b6b..8ae1b7510 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,8 @@ default = ["ui", "use-precompiled-js"] ui = ["dapps", "ethcore-signer/ui"] use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"] dapps = ["ethcore-dapps"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"] ipc = ["ethcore/ipc"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"] json-tests = ["ethcore/json-tests"] [[bin]] diff --git a/parity/cli.rs b/parity/cli.rs index d3627fda2..b76bf9d5d 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -74,6 +74,9 @@ Account Options: [default: 8180]. --signer-path PATH Specify directory where Signer UIs tokens should be stored. [default: $HOME/.parity/signer] + --signer-no-validation Disable Origin and Host headers validation for + Trusted Signer. WARNING: INSECURE. Used only for + development. Networking Options: --no-network Disable p2p networking. @@ -212,7 +215,7 @@ Footprint Options: the entire system, overrides other cache and queue options. --fast-and-loose Disables DB WAL, which gives a significant speed up - but means an unclean exit is unrecoverable. + but means an unclean exit is unrecoverable. --db-compaction TYPE Database compaction type. TYPE may be one of: ssd - suitable for SSDs and fast HDDs; hdd - suitable for slow HDDs [default: ssd]. @@ -337,6 +340,7 @@ pub struct Args { pub flag_no_signer: bool, pub flag_signer_port: u16, pub flag_signer_path: String, + pub flag_signer_no_validation: bool, pub flag_force_sealing: bool, pub flag_reseal_on_txs: String, pub flag_reseal_min_period: u64, diff --git a/parity/configuration.rs b/parity/configuration.rs index 81b3cb6c6..7ffdaa6c9 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -303,6 +303,7 @@ impl Configuration { enabled: self.signer_enabled(), port: self.args.flag_signer_port, signer_path: self.directories().signer, + skip_origin_validation: self.args.flag_signer_no_validation, } } @@ -789,6 +790,19 @@ mod tests { assert_eq!(conf0.signer_enabled(), false); } + #[test] + fn should_parse_signer_allow_all_flag() { + // given + + // when + let conf0 = parse(&["parity", "--signer-no-validation"]); + let conf1 = parse(&["parity"]); + + // then + assert_eq!(conf0.args.flag_signer_no_validation, true); + assert_eq!(conf1.args.flag_signer_no_validation, false); + } + #[test] fn should_not_bail_on_empty_line_in_reserved_peers() { let temp = RandomTempPath::new(); diff --git a/parity/signer.rs b/parity/signer.rs index d85e6e3e3..f6b2c3ef9 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -32,6 +32,7 @@ pub struct Configuration { pub enabled: bool, pub port: u16, pub signer_path: String, + pub skip_origin_validation: bool, } impl Default for Configuration { @@ -40,6 +41,7 @@ impl Default for Configuration { enabled: true, port: 8180, signer_path: replace_home("$HOME/.parity/signer"), + skip_origin_validation: false, } } } @@ -89,6 +91,11 @@ fn do_start(conf: Configuration, deps: Dependencies) -> Result, handler: Arc, authcodes_path: PathBuf, + skip_origin_validation: bool, } impl Extendable for ServerBuilder { @@ -68,13 +69,21 @@ impl ServerBuilder { queue: queue, handler: Arc::new(IoHandler::new()), authcodes_path: authcodes_path, + skip_origin_validation: false, } } + /// If set to `true` server will not verify Origin of incoming requests. + /// Not recommended. Use only for development. + pub fn skip_origin_validation(mut self, skip: bool) -> Self { + self.skip_origin_validation = skip; + self + } + /// Starts a new `WebSocket` server in separate thread. /// Returns a `Server` handle which closes the server when droped. pub fn start(self, addr: SocketAddr) -> Result { - Server::start(addr, self.handler, self.queue, self.authcodes_path) + Server::start(addr, self.handler, self.queue, self.authcodes_path, self.skip_origin_validation) } } @@ -89,10 +98,10 @@ pub struct Server { impl Server { /// Starts a new `WebSocket` server in separate thread. /// Returns a `Server` handle which closes the server when droped. - fn start(addr: SocketAddr, handler: Arc, queue: Arc, authcodes_path: PathBuf) -> Result { + fn start(addr: SocketAddr, handler: Arc, queue: Arc, authcodes_path: PathBuf, skip_origin_validation: bool) -> Result { let config = { let mut config = ws::Settings::default(); - // It's also used for handling min-sysui requests (browser can make many of them in paralel) + // accept only handshakes beginning with GET config.method_strict = true; // Was shutting down server when suspending on linux: config.shutdown_on_interrupt = false; @@ -101,7 +110,9 @@ impl Server { // Create WebSocket let origin = format!("{}", addr); - let ws = try!(ws::Builder::new().with_settings(config).build(session::Factory::new(handler, origin, authcodes_path))); + let ws = try!(ws::Builder::new().with_settings(config).build( + session::Factory::new(handler, origin, authcodes_path, skip_origin_validation) + )); let panic_handler = PanicHandler::new_in_arc(); let ph = panic_handler.clone(); diff --git a/signer/src/ws_server/session.rs b/signer/src/ws_server/session.rs index dd54baf30..af3e03bd1 100644 --- a/signer/src/ws_server/session.rs +++ b/signer/src/ws_server/session.rs @@ -96,6 +96,7 @@ fn add_headers(mut response: ws::Response, mime: &str) -> ws::Response { pub struct Session { out: ws::Sender, + skip_origin_validation: bool, self_origin: String, authcodes_path: PathBuf, handler: Arc, @@ -107,9 +108,11 @@ impl ws::Handler for Session { let host = req.header("host").or_else(|| req.header("Host")).map(|x| &x[..]); // Check request origin and host header. - if !origin_is_allowed(&self.self_origin, origin) && !(origin.is_none() && origin_is_allowed(&self.self_origin, host)) { - warn!(target: "signer", "Blocked connection to Signer API from untrusted origin."); - return Ok(ws::Response::forbidden(format!("You are not allowed to access system ui. Use: http://{}", self.self_origin))); + if !self.skip_origin_validation { + if !origin_is_allowed(&self.self_origin, origin) && !(origin.is_none() && origin_is_allowed(&self.self_origin, host)) { + warn!(target: "signer", "Blocked connection to Signer API from untrusted origin."); + return Ok(ws::Response::forbidden(format!("You are not allowed to access system ui. Use: http://{}", self.self_origin))); + } } // Detect if it's a websocket request. @@ -150,14 +153,16 @@ impl ws::Handler for Session { pub struct Factory { handler: Arc, + skip_origin_validation: bool, self_origin: String, authcodes_path: PathBuf, } impl Factory { - pub fn new(handler: Arc, self_origin: String, authcodes_path: PathBuf) -> Self { + pub fn new(handler: Arc, self_origin: String, authcodes_path: PathBuf, skip_origin_validation: bool) -> Self { Factory { handler: handler, + skip_origin_validation: skip_origin_validation, self_origin: self_origin, authcodes_path: authcodes_path, } @@ -171,6 +176,7 @@ impl ws::Factory for Factory { Session { out: sender, handler: self.handler.clone(), + skip_origin_validation: self.skip_origin_validation, self_origin: self.self_origin.clone(), authcodes_path: self.authcodes_path.clone(), }