Skip to content

Commit

Permalink
Merge pull request #45 from chocolate-pie/support-js-wasm-unsafe-eval
Browse files Browse the repository at this point in the history
Add support for `unsafe-eval` and `wasm-unsafe-eval`
  • Loading branch information
notriddle authored Jul 24, 2024
2 parents 38b74f2 + 0ebb47a commit 5635525
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 7 deletions.
83 changes: 76 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,32 @@ impl CspList {
})
.next()
}
/// https://www.w3.org/TR/CSP/#can-compile-strings
pub fn is_js_evaluation_allowed(&self) -> CheckResult {
let mut allowed = CheckResult::Allowed;
for policy in &self.0 {
for directive in &policy.directive_set {
if matches!(allowed, CheckResult::Allowed) {
allowed = directive.is_js_evaluation_allowed(&policy);
if matches!(allowed, CheckResult::Blocked) { return CheckResult::Blocked };
}
}
}
CheckResult::Allowed
}
/// https://www.w3.org/TR/CSP/#can-compile-wasm-bytes
pub fn is_wasm_evaluation_allowed(&self) -> CheckResult {
let mut allowed = CheckResult::Allowed;
for policy in &self.0 {
for directive in &policy.directive_set {
if matches!(allowed, CheckResult::Allowed) {
allowed = directive.is_wasm_evaluation_allowed(&policy);
if matches!(allowed, CheckResult::Blocked) { return CheckResult::Blocked };
}
}
}
CheckResult::Allowed
}
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -438,7 +464,7 @@ impl Destination {
}

/**
response to be validated
response to be validated
https://fetch.spec.whatwg.org/#concept-response
*/
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -964,6 +990,28 @@ impl Directive {
_ => None,
}
}
/// https://www.w3.org/TR/CSP/#can-compile-strings
pub fn is_js_evaluation_allowed(&self, policy: &Policy) -> CheckResult {
let source_list = SourceList(&self.value);
match &self.name[..] {
"script-src" | "default-src" => match source_list.does_a_source_list_allow_js_evaluation(&policy.disposition) {
AllowResult::Allows => CheckResult::Allowed,
AllowResult::DoesNotAllow => CheckResult::Blocked,
},
_ => CheckResult::Blocked
}
}
/// https://www.w3.org/TR/CSP/#can-compile-wasm-bytes
pub fn is_wasm_evaluation_allowed(&self, policy: &Policy) -> CheckResult {
let source_list = SourceList(&self.value);
match &self.name[..] {
"script-src" | "default-src" => match source_list.does_a_source_list_allow_wasm_evaluation(&policy.disposition) {
AllowResult::Allows => CheckResult::Allowed,
AllowResult::DoesNotAllow => CheckResult::Blocked
},
_ => CheckResult::Blocked
}
}
}

/// https://www.w3.org/TR/CSP/#effective-directive-for-inline-check
Expand Down Expand Up @@ -1258,6 +1306,27 @@ impl<'a, U: 'a + ?Sized + Borrow<str>, I: Clone + IntoIterator<Item=&'a U>> Sour
response.redirect_count,
)
}
/// https://www.w3.org/TR/CSP/#can-compile-strings
fn does_a_source_list_allow_js_evaluation(&self, disposition: &PolicyDisposition) -> AllowResult {
if matches!(disposition, PolicyDisposition::Report) { return AllowResult::Allows };
for expression in self.0.clone().into_iter().map(Borrow::borrow) {
if ascii_case_insensitive_match(expression, "'unsafe-eval'") {
return AllowResult::Allows;
}
}
AllowResult::DoesNotAllow
}
/// https://www.w3.org/TR/CSP/#can-compile-wasm-bytes
fn does_a_source_list_allow_wasm_evaluation(&self, disposition: &PolicyDisposition) -> AllowResult {
if matches!(disposition, PolicyDisposition::Report) { return AllowResult::Allows };
for expression in self.0.clone().into_iter().map(Borrow::borrow) {
if ascii_case_insensitive_match(expression, "'unsafe-eval'") ||
ascii_case_insensitive_match(expression, "'wasm-unsafe-eval'") {
return AllowResult::Allows;
}
}
AllowResult::DoesNotAllow
}
}

/// https://www.w3.org/TR/CSP/#allow-all-inline
Expand Down Expand Up @@ -1619,7 +1688,7 @@ mod test {
};

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);
Expand All @@ -1639,12 +1708,12 @@ mod test {
};

let p = Policy::parse("default-src 'none'; script-src 'self' ", PolicySource::Header, PolicyDisposition::Enforce);

let violation_result = p.does_request_violate_policy(&request);

let expected_result = Violates::Directive(Directive { name: String::from("script-src"), value: vec![String::from("'self'")] });

assert!(violation_result == expected_result);
assert!(violation_result == expected_result);
}

#[test]
Expand All @@ -1661,9 +1730,9 @@ mod test {
};

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);
}
assert!(violation_result == Violates::DoesNotViolate);
}
}
83 changes: 83 additions & 0 deletions tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,86 @@ test_should_elements_inline_type_behavior_be_blocked!{
source: "",
result: Allowed),
}

macro_rules! test_should_js_wasm_evaluation_be_blocked {
($((name: $name:ident, policy: $policy:expr, disposition: $disposition:tt, kind: $kind:ident, result: $result:tt)),*$(,)*) => {
$(
#[test]
fn $name() {
let csp_list = CspList::parse($policy, PolicySource::Header, PolicyDisposition::$disposition);
let check_result = csp_list.$kind();
assert_eq!(check_result, CheckResult::$result);
}
)*
}
}

// all tests should have a name starting with eval_
test_should_js_wasm_evaluation_be_blocked!{
( name: eval_webassembly_with_no_directive,
policy: "script-src",
disposition: Enforce,
kind: is_wasm_evaluation_allowed,
result: Blocked
),
( name: eval_javascript_with_no_directive,
policy: "script-src",
disposition: Enforce,
kind: is_js_evaluation_allowed,
result: Blocked
),
( name: eval_webassembly_with_unsafe_eval,
policy: "script-src 'unsafe-eval'",
disposition: Enforce,
kind: is_wasm_evaluation_allowed,
result: Allowed
),
( name: eval_webassembly_with_wasm_unsafe_eval,
policy: "script-src 'wasm-unsafe-eval'",
disposition: Enforce,
kind: is_wasm_evaluation_allowed,
result: Allowed
),
( name: eval_webassembly_with_uppercase_directive,
policy: "script-src 'UNSAFE-EvaL'",
disposition: Enforce,
kind: is_wasm_evaluation_allowed,
result: Allowed
),
( name: eval_webassembly_works_with_default_src,
policy: "default-src 'unsafe-eval'",
disposition: Enforce,
kind: is_wasm_evaluation_allowed,
result: Allowed
),
( name: eval_javascript_works_with_default_src,
policy: "default-src 'unsafe-eval'",
disposition: Enforce,
kind: is_js_evaluation_allowed,
result: Allowed
),
( name: eval_javascript_works_with_script_src,
policy: "script-src 'unsafe-eval'",
disposition: Enforce,
kind: is_js_evaluation_allowed,
result: Allowed
),
( name: eval_javascript_works_with_uppercase_directive,
policy: "script-src 'UnSAfe-EvAL'",
disposition: Enforce,
kind: is_js_evaluation_allowed,
result: Allowed
),
( name: eval_javascript_works_if_report_only,
policy: "script-src",
disposition: Report,
kind: is_js_evaluation_allowed,
result: Allowed
),
( name: eval_webassembly_works_if_report_only,
policy: "script-src",
disposition: Report,
kind: is_wasm_evaluation_allowed,
result: Allowed
)
}

0 comments on commit 5635525

Please sign in to comment.