From 328eaeda153ef0ff91274a3b7246f52ad5998014 Mon Sep 17 00:00:00 2001 From: bc <9028220+bc-universe@users.noreply.github.com> Date: Wed, 15 Nov 2023 21:58:47 +0100 Subject: [PATCH 1/2] Add updated logic for policy violation Latest spec added more information for policy violaton, specially related to resource hint. --- src/lib.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9c0b043..0cd0ba8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,6 +130,10 @@ impl Policy { } /// https://www.w3.org/TR/CSP/#does-request-violate-policy pub fn does_request_violate_policy(&self, request: &Request) -> Violates { + if request.initiator == Initiator::Prefetch { + return self.does_resource_hint_violate_policy(request); + } + let mut violates = Violates::DoesNotViolate; for directive in &self.directive_set { let result = directive.pre_request_check(request, self); @@ -139,6 +143,25 @@ impl Policy { } violates } + + /// https://www.w3.org/TR/CSP/#does-resource-hint-violate-policy + pub fn does_resource_hint_violate_policy(&self, request: &Request) -> Violates { + let default_directive = &self.directive_set.iter() + .find(|x| x.name == "default-src"); + + if default_directive.is_none() { + return Violates::DoesNotViolate; + } + + for directive in &self.directive_set { + let result = directive.pre_request_check(request, self); + if result == CheckResult::Allowed { + return Violates::DoesNotViolate; + } + } + + return Violates::Directive(default_directive.unwrap().clone()); + } } #[derive(Clone, Debug)] From 58b8ad1d2140f146baa965b3b05031ff0cb412f0 Mon Sep 17 00:00:00 2001 From: bc-universe <9028220+bc-universe@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:54:34 +0100 Subject: [PATCH 2/2] Add unit tests for prefetch requests --- src/lib.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0cd0ba8..23e36aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1621,4 +1621,66 @@ mod test { }; assert!(!p.is_valid()); } + + #[test] + pub fn prefetch_request_does_not_violate_policy() { + let request = Request { + url: Url::parse("https://www.notriddle.com/script.js").unwrap(), + origin: Origin::Tuple("https".to_string(), url::Host::Domain("notriddle.com".to_owned()), 443), + redirect_count: 0, + destination: Destination::Script, + initiator: Initiator::Prefetch, + nonce: String::new(), + integrity_metadata: String::new(), + parser_metadata: ParserMetadata::None, + }; + + let p = Policy::parse("child-src 'self'", PolicySource::Header, PolicyDisposition::Enforce); + + let violation_result = p.does_request_violate_policy(&request); + + assert!(violation_result == Violates::DoesNotViolate); + } + + #[test] + pub fn prefetch_request_violates_policy() { + let request = Request { + url: Url::parse("https://www.notriddle.com/script.js").unwrap(), + origin: Origin::Tuple("https".to_string(), url::Host::Domain("notriddle.com".to_owned()), 443), + redirect_count: 0, + destination: Destination::Script, + initiator: Initiator::Prefetch, + nonce: String::new(), + integrity_metadata: String::new(), + parser_metadata: ParserMetadata::None, + }; + + let p = Policy::parse("default-src 'none' ", PolicySource::Header, PolicyDisposition::Enforce); + + let violation_result = p.does_request_violate_policy(&request); + + let expected_result = Violates::Directive(Directive { name: String::from("default-src"), value: vec![String::from("'none'")] }); + + assert!(violation_result == expected_result); + } + + #[test] + pub fn prefetch_request_is_allowed_by_directive() { + let request = Request { + url: Url::parse("https://www.notriddle.com/script.js").unwrap(), + origin: Origin::Tuple("https".to_string(), url::Host::Domain("notriddle.com".to_owned()), 443), + redirect_count: 0, + destination: Destination::Script, + initiator: Initiator::Prefetch, + nonce: String::new(), + integrity_metadata: String::new(), + parser_metadata: ParserMetadata::None, + }; + + let p = Policy::parse("default-src 'none'; child-src 'self'", PolicySource::Header, PolicyDisposition::Enforce); + + let violation_result = p.does_request_violate_policy(&request); + + assert!(violation_result == Violates::DoesNotViolate); + } }