diff options
author | Tim van der Lippe <TimvdLippe@users.noreply.github.com> | 2025-05-03 10:47:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-03 08:47:40 +0000 |
commit | 539ca272843bd0937bc7ed48d6103a6338d2a3c9 (patch) | |
tree | 3b0b98de94c8d4a66ff8d0f420a94bed5c4d9eb5 /components/script | |
parent | 4164f76769db21103ee3c46d6d669a03310f2717 (diff) | |
download | servo-539ca272843bd0937bc7ed48d6103a6338d2a3c9.tar.gz servo-539ca272843bd0937bc7ed48d6103a6338d2a3c9.zip |
Propagate parent policy container to local iframes (#36710)
This follows the rules as defined in
https://w3c.github.io/webappsec-csp/#security-inherit-csp
where local iframes (about:blank and about:srcdoc) should
initially start with the CSP rules of the parent. After
that, all new CSP headers should only be set on the
policy container of the iframe.
Part of #36437
Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 10 | ||||
-rw-r--r-- | components/script/dom/servoparser/mod.rs | 22 | ||||
-rw-r--r-- | components/script/script_thread.rs | 4 |
3 files changed, 34 insertions, 2 deletions
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index da7a53bbf0b..0fbff86e44a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -279,6 +279,7 @@ impl HTMLIFrameElement { Some(document.insecure_requests_policy()), document.has_trustworthy_ancestor_or_current_origin(), ); + load_data.policy_container = Some(window.as_global_scope().policy_container()); let element = self.upcast::<Element>(); load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc"))); self.navigate_or_reload_child_browsing_context( @@ -361,7 +362,7 @@ impl HTMLIFrameElement { None }; - let load_data = LoadData::new( + let mut load_data = LoadData::new( LoadOrigin::Script(document.origin().immutable().clone()), url, creator_pipeline_id, @@ -378,6 +379,10 @@ impl HTMLIFrameElement { let is_about_blank = pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get(); + if is_about_blank { + load_data.policy_container = Some(window.as_global_scope().policy_container()); + } + let history_handling = if is_about_blank { NavigationHistoryBehavior::Replace } else { @@ -407,7 +412,7 @@ impl HTMLIFrameElement { let document = self.owner_document(); let window = self.owner_window(); let pipeline_id = Some(window.pipeline_id()); - let load_data = LoadData::new( + let mut load_data = LoadData::new( LoadOrigin::Script(document.origin().immutable().clone()), url, pipeline_id, @@ -417,6 +422,7 @@ impl HTMLIFrameElement { Some(document.insecure_requests_policy()), document.has_trustworthy_ancestor_or_current_origin(), ); + load_data.policy_container = Some(window.as_global_scope().policy_container()); let browsing_context_id = BrowsingContextId::new(); let webview_id = window.window_proxy().webview_id(); self.pipeline_id.set(None); diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 0650fde676e..5878573d552 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -21,6 +21,7 @@ use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns}; use hyper_serde::Serde; use markup5ever::TokenizerResult; use mime::{self, Mime}; +use net_traits::policy_container::PolicyContainer; use net_traits::request::RequestId; use net_traits::{ FetchMetadata, FetchResponseListener, Metadata, NetworkError, ResourceFetchTiming, @@ -813,6 +814,27 @@ impl ParserContext { pushed_entry_index: None, } } + + pub(crate) fn append_parent_to_csp_list(&self, policy_container: Option<&PolicyContainer>) { + let Some(policy_container) = policy_container else { + return; + }; + let Some(parent_csp_list) = &policy_container.csp_list else { + return; + }; + let Some(parser) = self.parser.as_ref().map(|p| p.root()) else { + return; + }; + let new_csp_list = match parser.document.get_csp_list() { + None => parent_csp_list.clone(), + Some(original_csp_list) => { + let mut appended_csp_list = original_csp_list.clone(); + appended_csp_list.append(parent_csp_list.clone()); + appended_csp_list.to_owned() + }, + }; + parser.document.set_csp_list(Some(new_csp_list)); + } } impl FetchResponseListener for ParserContext { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index bd4de9d893b..7241c115a2a 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -3674,10 +3674,12 @@ impl ScriptThread { None => vec![], }; + let policy_container = incomplete.load_data.policy_container.clone(); self.incomplete_loads.borrow_mut().push(incomplete); let dummy_request_id = RequestId::default(); context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta))); + context.append_parent_to_csp_list(policy_container.as_ref()); context.process_response_chunk(dummy_request_id, chunk); context.process_response_eof( dummy_request_id, @@ -3697,12 +3699,14 @@ impl ScriptThread { let srcdoc = std::mem::take(&mut incomplete.load_data.srcdoc); let chunk = srcdoc.into_bytes(); + let policy_container = incomplete.load_data.policy_container.clone(); self.incomplete_loads.borrow_mut().push(incomplete); let mut context = ParserContext::new(id, url); let dummy_request_id = RequestId::default(); context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta))); + context.append_parent_to_csp_list(policy_container.as_ref()); context.process_response_chunk(dummy_request_id, chunk); context.process_response_eof( dummy_request_id, |