Fix dapps CSP when UI is exposed externally (#6178)

* Allow embeding on any page when ui-hosts=all and fix dev_ui

* Fix tests.
This commit is contained in:
Tomasz Drwięga 2017-08-10 18:32:10 +02:00 committed by Gav Wood
parent ecd880c8e7
commit 65482c5e9d
5 changed files with 56 additions and 11 deletions

View File

@ -67,10 +67,20 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
// Allow fonts from data: and HTTPS.
b"font-src 'self' data: https:;".to_vec(),
// Allow inline scripts and scripts eval (webpack/jsconsole)
b"script-src 'self' 'unsafe-inline' 'unsafe-eval';".to_vec(),
// Same restrictions as script-src (fallback) with additional
{
let script_src = embeddable_on.as_ref()
.map(|e| e.extra_script_src.iter()
.map(|&(ref host, port)| address(host, port))
.join(" ")
).unwrap_or_default();
format!(
"script-src 'self' 'unsafe-inline' 'unsafe-eval' {};",
script_src
).into_bytes()
},
// Same restrictions as script-src with additional
// blob: that is required for camera access (worker)
b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' blob: ;".to_vec(),
b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' https: blob:;".to_vec(),
// Restrict everything else to the same origin.
b"default-src 'self';".to_vec(),
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
@ -90,7 +100,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
.into_iter()
.chain(embed.extra_embed_on
.iter()
.map(|&(ref host, port)| format!("{}:{}", host, port))
.map(|&(ref host, port)| address(host, port))
);
let ancestors = if embed.host == "127.0.0.1" {

View File

@ -201,6 +201,7 @@ impl Middleware {
remote: Remote,
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>,
dapps_domain: &str,
@ -209,7 +210,7 @@ impl Middleware {
web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F,
) -> Self {
let embeddable = as_embeddable(ui_address, extra_embed_on, dapps_domain);
let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain);
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status.clone(),
@ -294,12 +295,14 @@ fn address(host: &str, port: u16) -> String {
fn as_embeddable(
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
dapps_domain: &str,
) -> Option<ParentFrameSettings> {
ui_address.map(|(host, port)| ParentFrameSettings {
host,
port,
extra_embed_on,
extra_script_src,
dapps_domain: dapps_domain.to_owned(),
})
}
@ -320,8 +323,10 @@ pub struct ParentFrameSettings {
pub host: String,
/// Port
pub port: u16,
/// Additional pages the pages can be embedded on.
/// Additional URLs the dapps can be embedded on.
pub extra_embed_on: Vec<(String, u16)>,
/// Additional URLs the dapp scripts can be loaded from.
pub extra_script_src: Vec<(String, u16)>,
/// Dapps Domain (web3.site)
pub dapps_domain: String,
}

View File

@ -260,6 +260,7 @@ impl Server {
remote,
signer_address,
vec![],
vec![],
dapps_path,
extra_dapps,
DAPPS_DOMAIN.into(),

View File

@ -20,6 +20,7 @@ use std::net::SocketAddr;
use std::path::{Path, PathBuf};
use std::collections::BTreeMap;
use std::cmp::max;
use std::str::FromStr;
use cli::{Args, ArgsError};
use util::{Hashable, H256, U256, Bytes, version_data, Address};
use util::journaldb::Algorithm;
@ -551,6 +552,10 @@ impl Configuration {
Ok(options)
}
fn ui_port(&self) -> u16 {
self.args.flag_ports_shift + self.args.flag_ui_port
}
fn ntp_servers(&self) -> Vec<String> {
self.args.flag_ntp_servers.split(",").map(str::to_owned).collect()
}
@ -560,12 +565,15 @@ impl Configuration {
enabled: self.ui_enabled(),
ntp_servers: self.ntp_servers(),
interface: self.ui_interface(),
port: self.args.flag_ports_shift + self.args.flag_ui_port,
port: self.ui_port(),
hosts: self.ui_hosts(),
}
}
fn dapps_config(&self) -> DappsConfiguration {
let dev_ui = if self.args.flag_ui_no_validation { vec![("localhost".to_owned(), 3000)] } else { vec![] };
let ui_port = self.ui_port();
DappsConfiguration {
enabled: self.dapps_enabled(),
ntp_servers: self.ntp_servers(),
@ -575,11 +583,26 @@ impl Configuration {
} else {
vec![]
},
extra_embed_on: if self.args.flag_ui_no_validation {
vec![("localhost".to_owned(), 3000)]
} else {
vec![]
extra_embed_on: {
let mut extra_embed = dev_ui.clone();
match self.ui_hosts() {
// In case host validation is disabled allow all frame ancestors
None => extra_embed.push(("*".to_owned(), ui_port)),
Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| {
let mut it = host.split(":");
let host = it.next();
let port = it.next().and_then(|v| u16::from_str(v).ok());
match (host, port) {
(Some(host), Some(port)) => Some((host.into(), port)),
(Some(host), None) => Some((host.into(), ui_port)),
_ => None,
}
})),
}
extra_embed
},
extra_script_src: dev_ui,
}
}

View File

@ -40,6 +40,7 @@ pub struct Configuration {
pub dapps_path: PathBuf,
pub extra_dapps: Vec<PathBuf>,
pub extra_embed_on: Vec<(String, u16)>,
pub extra_script_src: Vec<(String, u16)>,
}
impl Default for Configuration {
@ -56,6 +57,7 @@ impl Default for Configuration {
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
extra_dapps: vec![],
extra_embed_on: vec![],
extra_script_src: vec![],
}
}
}
@ -168,6 +170,7 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
configuration.extra_dapps,
rpc::DAPPS_DOMAIN,
configuration.extra_embed_on,
configuration.extra_script_src,
).map(Some)
}
@ -214,6 +217,7 @@ mod server {
_extra_dapps: Vec<PathBuf>,
_dapps_domain: &str,
_extra_embed_on: Vec<(String, u16)>,
_extra_script_src: Vec<(String, u16)>,
) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without WebApps support.".into())
}
@ -251,6 +255,7 @@ mod server {
extra_dapps: Vec<PathBuf>,
dapps_domain: &str,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
) -> Result<Middleware, String> {
let signer = deps.signer;
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
@ -262,6 +267,7 @@ mod server {
parity_remote,
deps.ui_address,
extra_embed_on,
extra_script_src,
dapps_path,
extra_dapps,
dapps_domain,