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:
parent
ecd880c8e7
commit
65482c5e9d
@ -67,10 +67,20 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
|||||||
// Allow fonts from data: and HTTPS.
|
// Allow fonts from data: and HTTPS.
|
||||||
b"font-src 'self' data: https:;".to_vec(),
|
b"font-src 'self' data: https:;".to_vec(),
|
||||||
// Allow inline scripts and scripts eval (webpack/jsconsole)
|
// 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)
|
// 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.
|
// Restrict everything else to the same origin.
|
||||||
b"default-src 'self';".to_vec(),
|
b"default-src 'self';".to_vec(),
|
||||||
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
|
// 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()
|
.into_iter()
|
||||||
.chain(embed.extra_embed_on
|
.chain(embed.extra_embed_on
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(ref host, port)| format!("{}:{}", host, port))
|
.map(|&(ref host, port)| address(host, port))
|
||||||
);
|
);
|
||||||
|
|
||||||
let ancestors = if embed.host == "127.0.0.1" {
|
let ancestors = if embed.host == "127.0.0.1" {
|
||||||
|
@ -201,6 +201,7 @@ impl Middleware {
|
|||||||
remote: Remote,
|
remote: Remote,
|
||||||
ui_address: Option<(String, u16)>,
|
ui_address: Option<(String, u16)>,
|
||||||
extra_embed_on: Vec<(String, u16)>,
|
extra_embed_on: Vec<(String, u16)>,
|
||||||
|
extra_script_src: Vec<(String, u16)>,
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
dapps_domain: &str,
|
dapps_domain: &str,
|
||||||
@ -209,7 +210,7 @@ impl Middleware {
|
|||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Self {
|
) -> 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(
|
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
|
||||||
hash_fetch::urlhint::URLHintContract::new(registrar),
|
hash_fetch::urlhint::URLHintContract::new(registrar),
|
||||||
sync_status.clone(),
|
sync_status.clone(),
|
||||||
@ -294,12 +295,14 @@ fn address(host: &str, port: u16) -> String {
|
|||||||
fn as_embeddable(
|
fn as_embeddable(
|
||||||
ui_address: Option<(String, u16)>,
|
ui_address: Option<(String, u16)>,
|
||||||
extra_embed_on: Vec<(String, u16)>,
|
extra_embed_on: Vec<(String, u16)>,
|
||||||
|
extra_script_src: Vec<(String, u16)>,
|
||||||
dapps_domain: &str,
|
dapps_domain: &str,
|
||||||
) -> Option<ParentFrameSettings> {
|
) -> Option<ParentFrameSettings> {
|
||||||
ui_address.map(|(host, port)| ParentFrameSettings {
|
ui_address.map(|(host, port)| ParentFrameSettings {
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
extra_embed_on,
|
extra_embed_on,
|
||||||
|
extra_script_src,
|
||||||
dapps_domain: dapps_domain.to_owned(),
|
dapps_domain: dapps_domain.to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -320,8 +323,10 @@ pub struct ParentFrameSettings {
|
|||||||
pub host: String,
|
pub host: String,
|
||||||
/// Port
|
/// Port
|
||||||
pub port: u16,
|
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)>,
|
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)
|
/// Dapps Domain (web3.site)
|
||||||
pub dapps_domain: String,
|
pub dapps_domain: String,
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,7 @@ impl Server {
|
|||||||
remote,
|
remote,
|
||||||
signer_address,
|
signer_address,
|
||||||
vec![],
|
vec![],
|
||||||
|
vec![],
|
||||||
dapps_path,
|
dapps_path,
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
DAPPS_DOMAIN.into(),
|
DAPPS_DOMAIN.into(),
|
||||||
|
@ -20,6 +20,7 @@ use std::net::SocketAddr;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
use std::str::FromStr;
|
||||||
use cli::{Args, ArgsError};
|
use cli::{Args, ArgsError};
|
||||||
use util::{Hashable, H256, U256, Bytes, version_data, Address};
|
use util::{Hashable, H256, U256, Bytes, version_data, Address};
|
||||||
use util::journaldb::Algorithm;
|
use util::journaldb::Algorithm;
|
||||||
@ -551,6 +552,10 @@ impl Configuration {
|
|||||||
Ok(options)
|
Ok(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ui_port(&self) -> u16 {
|
||||||
|
self.args.flag_ports_shift + self.args.flag_ui_port
|
||||||
|
}
|
||||||
|
|
||||||
fn ntp_servers(&self) -> Vec<String> {
|
fn ntp_servers(&self) -> Vec<String> {
|
||||||
self.args.flag_ntp_servers.split(",").map(str::to_owned).collect()
|
self.args.flag_ntp_servers.split(",").map(str::to_owned).collect()
|
||||||
}
|
}
|
||||||
@ -560,12 +565,15 @@ impl Configuration {
|
|||||||
enabled: self.ui_enabled(),
|
enabled: self.ui_enabled(),
|
||||||
ntp_servers: self.ntp_servers(),
|
ntp_servers: self.ntp_servers(),
|
||||||
interface: self.ui_interface(),
|
interface: self.ui_interface(),
|
||||||
port: self.args.flag_ports_shift + self.args.flag_ui_port,
|
port: self.ui_port(),
|
||||||
hosts: self.ui_hosts(),
|
hosts: self.ui_hosts(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dapps_config(&self) -> DappsConfiguration {
|
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 {
|
DappsConfiguration {
|
||||||
enabled: self.dapps_enabled(),
|
enabled: self.dapps_enabled(),
|
||||||
ntp_servers: self.ntp_servers(),
|
ntp_servers: self.ntp_servers(),
|
||||||
@ -575,11 +583,26 @@ impl Configuration {
|
|||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
},
|
},
|
||||||
extra_embed_on: if self.args.flag_ui_no_validation {
|
extra_embed_on: {
|
||||||
vec![("localhost".to_owned(), 3000)]
|
let mut extra_embed = dev_ui.clone();
|
||||||
} else {
|
match self.ui_hosts() {
|
||||||
vec![]
|
// 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ pub struct Configuration {
|
|||||||
pub dapps_path: PathBuf,
|
pub dapps_path: PathBuf,
|
||||||
pub extra_dapps: Vec<PathBuf>,
|
pub extra_dapps: Vec<PathBuf>,
|
||||||
pub extra_embed_on: Vec<(String, u16)>,
|
pub extra_embed_on: Vec<(String, u16)>,
|
||||||
|
pub extra_script_src: Vec<(String, u16)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Configuration {
|
impl Default for Configuration {
|
||||||
@ -56,6 +57,7 @@ impl Default for Configuration {
|
|||||||
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
||||||
extra_dapps: vec![],
|
extra_dapps: vec![],
|
||||||
extra_embed_on: 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,
|
configuration.extra_dapps,
|
||||||
rpc::DAPPS_DOMAIN,
|
rpc::DAPPS_DOMAIN,
|
||||||
configuration.extra_embed_on,
|
configuration.extra_embed_on,
|
||||||
|
configuration.extra_script_src,
|
||||||
).map(Some)
|
).map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +217,7 @@ mod server {
|
|||||||
_extra_dapps: Vec<PathBuf>,
|
_extra_dapps: Vec<PathBuf>,
|
||||||
_dapps_domain: &str,
|
_dapps_domain: &str,
|
||||||
_extra_embed_on: Vec<(String, u16)>,
|
_extra_embed_on: Vec<(String, u16)>,
|
||||||
|
_extra_script_src: Vec<(String, u16)>,
|
||||||
) -> Result<Middleware, String> {
|
) -> Result<Middleware, String> {
|
||||||
Err("Your Parity version has been compiled without WebApps support.".into())
|
Err("Your Parity version has been compiled without WebApps support.".into())
|
||||||
}
|
}
|
||||||
@ -251,6 +255,7 @@ mod server {
|
|||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
dapps_domain: &str,
|
dapps_domain: &str,
|
||||||
extra_embed_on: Vec<(String, u16)>,
|
extra_embed_on: Vec<(String, u16)>,
|
||||||
|
extra_script_src: Vec<(String, u16)>,
|
||||||
) -> Result<Middleware, String> {
|
) -> Result<Middleware, String> {
|
||||||
let signer = deps.signer;
|
let signer = deps.signer;
|
||||||
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
|
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
|
||||||
@ -262,6 +267,7 @@ mod server {
|
|||||||
parity_remote,
|
parity_remote,
|
||||||
deps.ui_address,
|
deps.ui_address,
|
||||||
extra_embed_on,
|
extra_embed_on,
|
||||||
|
extra_script_src,
|
||||||
dapps_path,
|
dapps_path,
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
dapps_domain,
|
dapps_domain,
|
||||||
|
Loading…
Reference in New Issue
Block a user