mirror of
https://github.com/lexmount/moli.git
synced 2026-10-03 08:00:49 +00:00
refactor(csp): unify navigation embedding checks
This commit is contained in:
@@ -84,8 +84,9 @@ pub(crate) use script_lifecycle::{
|
||||
};
|
||||
pub(crate) use security_policy::{
|
||||
DocumentConnectPolicySnapshot, DocumentContentSecurityPolicyCheck,
|
||||
DocumentContentSecurityPolicyViolation, DocumentSubresourceCspKind,
|
||||
create_content_security_policy_violation_event, document_content_security_policy_error_message,
|
||||
DocumentContentSecurityPolicyViolation, DocumentNavigationEmbeddingContext,
|
||||
DocumentSubresourceCspKind, create_content_security_policy_violation_event,
|
||||
document_content_security_policy_error_message,
|
||||
};
|
||||
pub(crate) use stylesheet_runtime::attribute_reprocesses_connected_stylesheet;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -7,7 +7,9 @@ use crate::content_security_policy::{
|
||||
ContentSecurityPolicyStyleElementRequest, ContentSecurityPolicyUrlViolation,
|
||||
ContentSecurityPolicyViolationEventFields, TrustedTypesForScriptRequirements,
|
||||
content_security_policy_allows_trusted_type_policy_name,
|
||||
content_security_policy_allows_trusted_types_eval, content_security_policy_headers,
|
||||
content_security_policy_allows_trusted_types_eval,
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints,
|
||||
content_security_policy_headers,
|
||||
content_security_policy_inline_script_element_violation_with_disposition_and_reporting_endpoints,
|
||||
content_security_policy_inline_source_violation_with_disposition_and_reporting_endpoints,
|
||||
content_security_policy_inline_style_element_violation_with_disposition_and_reporting_endpoints,
|
||||
@@ -48,6 +50,10 @@ pub(crate) struct DocumentContentSecurityPolicyCheck {
|
||||
}
|
||||
|
||||
impl DocumentContentSecurityPolicyCheck {
|
||||
pub(crate) fn has_no_violations(&self) -> bool {
|
||||
self.report_only_violation.is_none() && self.enforced_violation.is_none()
|
||||
}
|
||||
|
||||
pub(crate) fn into_violations(
|
||||
self,
|
||||
) -> (
|
||||
@@ -68,6 +74,12 @@ impl DocumentContentSecurityPolicyCheck {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum DocumentNavigationEmbeddingContext<'a> {
|
||||
TopLevel,
|
||||
Nested(&'a [Option<Url>]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct DocumentConnectPolicySnapshot {
|
||||
enforce_policies: Vec<String>,
|
||||
@@ -154,6 +166,37 @@ impl DocumentPolicyContainer {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn navigation_response_frame_ancestors_check(
|
||||
&self,
|
||||
protected_url: &Url,
|
||||
embedding_context: DocumentNavigationEmbeddingContext<'_>,
|
||||
) -> DocumentContentSecurityPolicyCheck {
|
||||
let DocumentNavigationEmbeddingContext::Nested(ancestor_origins) = embedding_context else {
|
||||
return DocumentContentSecurityPolicyCheck {
|
||||
report_only_violation: None,
|
||||
enforced_violation: None,
|
||||
};
|
||||
};
|
||||
DocumentContentSecurityPolicyCheck {
|
||||
report_only_violation:
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints(
|
||||
&self.response_content_security_report_only_policies,
|
||||
protected_url,
|
||||
ancestor_origins,
|
||||
ContentSecurityPolicyDisposition::Report,
|
||||
&self.content_security_reporting_endpoints,
|
||||
),
|
||||
enforced_violation:
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints(
|
||||
&self.response_content_security_policies,
|
||||
protected_url,
|
||||
ancestor_origins,
|
||||
ContentSecurityPolicyDisposition::Enforce,
|
||||
&self.content_security_reporting_endpoints,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clear_content_security_policy_for_bypass(&mut self) {
|
||||
self.document_content_security_policies.clear();
|
||||
self.response_content_security_policies.clear();
|
||||
@@ -3083,4 +3126,41 @@ mod tests {
|
||||
Some("https://example.test/reports/csp")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn navigation_response_frame_ancestors_check_distinguishes_top_level_and_nested() {
|
||||
let protected_url = Url::parse("https://child.test/frame.html").unwrap();
|
||||
let policy = DocumentPolicyContainer {
|
||||
response_content_security_policies: vec!["frame-ancestors 'self'".to_owned()],
|
||||
response_content_security_report_only_policies: vec![
|
||||
"frame-ancestors https://reported.test".to_owned(),
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert!(
|
||||
policy
|
||||
.navigation_response_frame_ancestors_check(
|
||||
&protected_url,
|
||||
DocumentNavigationEmbeddingContext::TopLevel,
|
||||
)
|
||||
.has_no_violations()
|
||||
);
|
||||
|
||||
let ancestors = [Some(Url::parse("https://embedder.test").unwrap())];
|
||||
let (report_only, enforced) = policy
|
||||
.navigation_response_frame_ancestors_check(
|
||||
&protected_url,
|
||||
DocumentNavigationEmbeddingContext::Nested(&ancestors),
|
||||
)
|
||||
.into_violations();
|
||||
assert_eq!(
|
||||
report_only.unwrap().disposition,
|
||||
ContentSecurityPolicyDisposition::Report
|
||||
);
|
||||
assert_eq!(
|
||||
enforced.unwrap().disposition,
|
||||
ContentSecurityPolicyDisposition::Enforce
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,9 @@ use super::{
|
||||
use crate::referrer_policy::response_referrer_policy_from_headers;
|
||||
use crate::{
|
||||
content_security_policy::{
|
||||
ContentSecurityPolicyDisposition, ContentSecurityPolicyViolationEventFields,
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints,
|
||||
send_content_security_policy_reports,
|
||||
ContentSecurityPolicyViolationEventFields, send_content_security_policy_reports,
|
||||
},
|
||||
document_runtime::{DocumentPolicyContainer, DomHandle},
|
||||
document_runtime::{DocumentNavigationEmbeddingContext, DocumentPolicyContainer, DomHandle},
|
||||
document_script_scheduler::FrameDocumentClassicScriptSchedulerWork,
|
||||
frame_owner_model::{
|
||||
ChildDocumentNavigationFetchTarget, DocumentCreationKind,
|
||||
@@ -411,26 +409,13 @@ impl JsContextHost {
|
||||
.clear_content_security_policy_for_bypass();
|
||||
}
|
||||
let ancestor_origins = self.child_document_frame_ancestor_origins(handle);
|
||||
let reporting_endpoints =
|
||||
&loaded.policy_container.content_security_reporting_endpoints;
|
||||
let report_only_violation =
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints(
|
||||
&loaded
|
||||
.policy_container
|
||||
.response_content_security_report_only_policies,
|
||||
let (report_only_violation, enforced_violation) = loaded
|
||||
.policy_container
|
||||
.navigation_response_frame_ancestors_check(
|
||||
&loaded.final_url,
|
||||
&ancestor_origins,
|
||||
ContentSecurityPolicyDisposition::Report,
|
||||
reporting_endpoints,
|
||||
);
|
||||
let enforced_violation =
|
||||
content_security_policy_frame_ancestors_violation_with_disposition_and_reporting_endpoints(
|
||||
&loaded.policy_container.response_content_security_policies,
|
||||
&loaded.final_url,
|
||||
&ancestor_origins,
|
||||
ContentSecurityPolicyDisposition::Enforce,
|
||||
reporting_endpoints,
|
||||
);
|
||||
DocumentNavigationEmbeddingContext::Nested(&ancestor_origins),
|
||||
)
|
||||
.into_violations();
|
||||
for violation in report_only_violation
|
||||
.iter()
|
||||
.chain(enforced_violation.iter())
|
||||
|
||||
@@ -1108,6 +1108,15 @@ impl PageVmEnvConfig {
|
||||
headers, final_url,
|
||||
)
|
||||
.with_content_security_policy_bypass(self.bypass_content_security_policy);
|
||||
debug_assert!(
|
||||
self.document_policy_container
|
||||
.navigation_response_frame_ancestors_check(
|
||||
final_url,
|
||||
crate::document_runtime::DocumentNavigationEmbeddingContext::TopLevel,
|
||||
)
|
||||
.has_no_violations(),
|
||||
"a top-level navigation response cannot violate frame-ancestors"
|
||||
);
|
||||
self.document_default_language =
|
||||
crate::document_language::document_default_language_from_headers(headers);
|
||||
self.document_last_modified =
|
||||
|
||||
Reference in New Issue
Block a user