Skip to content

Commit

Permalink
Merge #18 #19
Browse files Browse the repository at this point in the history
18: Add test cases for child-src r=notriddle a=notriddle

Fixes #8

19: Implement response check r=notriddle a=notriddle

Fixes #6

Co-authored-by: Michael Howell <[email protected]>
  • Loading branch information
bors[bot] and notriddle committed Feb 21, 2019
3 parents 68e2b30 + d7aaf5f + e9a2c03 commit c91b403
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repository = "https://github.com/notriddle/rust-content-security-policy"
url = "1.7"
regex = "1.1"
lazy_static = "1.2"
bitflags = "1.0.4"

[dev-dependencies]
version-sync = "0.7"
88 changes: 85 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ extern crate regex;
use regex::Regex;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
pub use url::{Origin, Url, percent_encoding};
use std::borrow::{Borrow, Cow};

Expand Down Expand Up @@ -519,9 +521,29 @@ impl Directive {
use CheckResult::*;
Allowed
}
pub fn response_check(&self, _request: &Request, _response: &Response, _policy: &Policy) -> CheckResult {
pub fn response_check(&self, request: &Request, _response: &Response, policy: &Policy) -> CheckResult {
use CheckResult::*;
Allowed
use Destination::*;
use PolicyDisposition::*;
match &self.name[..] {
"sandbox" => {
if policy.disposition != Enforce {
return Allowed;
}
match request.destination {
ServiceWorker | SharedWorker | Worker => {
let sandboxing = parse_a_sandboxing_directive(&self.value[..]);
if sandboxing.contains(SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG) || sandboxing.contains(SandboxingFlagSet::SANDBOXED_ORIGIN_BROWSING_CONTEXT_FLAG) {
Blocked
} else {
Allowed
}
},
_ => Allowed,
}
},
_ => Allowed,
}
}
pub fn inline_check(&self, element: &Element, type_: InlineCheckType, policy: &Policy, source: &str) -> CheckResult {
use CheckResult::*;
Expand Down Expand Up @@ -695,7 +717,7 @@ fn get_fetch_directive_fallback_list(directive_name: &str) -> &'static [&'static
"manifest-src" => &["manifest-src", "default-src"],
"prefetch-src" => &["prefetch-src", "default-src"],
"object-src" => &["object-src", "default-src"],
"frame-src" => &["frame-src", "default-src"],
"frame-src" => &["frame-src", "child-src", "default-src"],
"media-src" => &["media-src", "default-src"],
"font-src" => &["font-src", "default-src"],
"img-src" => &["img-src", "default-src"],
Expand Down Expand Up @@ -733,6 +755,7 @@ pub enum MatchResult {
}
use MatchResult::Matches;
use MatchResult::DoesNotMatch;
use ::PolicyDisposition::Enforce;

lazy_static!{
static ref NONCE_SOURCE_GRAMMAR: Regex =
Expand Down Expand Up @@ -1146,3 +1169,62 @@ pub fn parse_subresource_integrity_metadata(string: &str) -> SubresourceIntegrit
SubresourceIntegrityMetadata::IntegritySources(result)
}
}

bitflags!{
pub struct SandboxingFlagSet: u32 {
const SANDBOXED_NAVIGATION_BROWSING_CONTEXT_FLAG = 0x00000001;
const SANDBOXED_AUXILIARY_NAVIGATION_BROWSING_CONTEXT_FLAG = 0x00000002;
const SANDBOXED_TOP_LEVEL_NAVIGATION_WITHOUT_USER_ACTIVATION_BROWSING_CONTEXT_FLAG
= 0x00000004;
const SANDBOXED_TOP_LEVEL_NAVIGATION_WITH_USER_ACTIVATION_BROWSING_CONTEXT_FLAG
= 0x00000008;
const SANDBOXED_PLUGINS_BROWSING_CONTEXT_FLAG = 0x00000010;
const SANDBOXED_ORIGIN_BROWSING_CONTEXT_FLAG = 0x00000020;
const SANDBOXED_FORMS_BROWSING_CONTEXT_FLAG = 0x00000040;
const SANDBOXED_POINTER_LOCK_BROWSING_CONTEXT_FLAG = 0x00000080;
const SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG = 0x00000100;
const SANDBOXED_AUTOMATIC_FEATURES_BROWSING_CONTEXT_FLAG = 0x00000200;
const SANDBOXED_STORAGE_AREA_URLS_FLAG = 0x00000400;
const SANDBOXED_DOCUMENT_DOMAIN_BROWSING_CONTEXT_FLAG = 0x00000800;
const SANDBOX_PROPOGATES_TO_AUXILIARY_BROWSING_CONTEXTS_FLAG = 0x00001000;
const SANDBOXED_MODALS_FLAG = 0x00002000;
const SANDBOXED_ORIENTATION_LOCK_BROWSING_CONTEXT_FLAG = 0x00004000;
const SANDBOXED_PRESENTATION_BROWSING_CONTEXT_FLAG = 0x00008000;
}
}

pub fn parse_a_sandboxing_directive(tokens: &[String]) -> SandboxingFlagSet {
let mut output = SandboxingFlagSet::all();
for token in tokens {
let remove = match &token[..] {
"allow-popups" =>
SandboxingFlagSet::SANDBOXED_AUXILIARY_NAVIGATION_BROWSING_CONTEXT_FLAG,
"allow-top-navigation" =>
SandboxingFlagSet::SANDBOXED_TOP_LEVEL_NAVIGATION_WITHOUT_USER_ACTIVATION_BROWSING_CONTEXT_FLAG,
"allow-top-navigation-by-user-activation" | "allow-top-navigation" =>
SandboxingFlagSet::SANDBOXED_TOP_LEVEL_NAVIGATION_WITH_USER_ACTIVATION_BROWSING_CONTEXT_FLAG,
"allow-same-origin" =>
SandboxingFlagSet::SANDBOXED_ORIGIN_BROWSING_CONTEXT_FLAG,
"allow-forms" =>
SandboxingFlagSet::SANDBOXED_FORMS_BROWSING_CONTEXT_FLAG,
"allow-pointer-lock" =>
SandboxingFlagSet::SANDBOXED_POINTER_LOCK_BROWSING_CONTEXT_FLAG,
"allow-scripts" =>
SandboxingFlagSet::SANDBOXED_SCRIPTS_BROWSING_CONTEXT_FLAG,
"allow-scripts" =>
SandboxingFlagSet::SANDBOXED_AUTOMATIC_FEATURES_BROWSING_CONTEXT_FLAG,
"allow-popups-to-escape-sandbox" =>
SandboxingFlagSet::SANDBOX_PROPOGATES_TO_AUXILIARY_BROWSING_CONTEXTS_FLAG,
"allow-modals" =>
SandboxingFlagSet::SANDBOXED_MODALS_FLAG,
"allow-orientation-lock" =>
SandboxingFlagSet::SANDBOXED_ORIENTATION_LOCK_BROWSING_CONTEXT_FLAG,
"allow-presentation" =>
SandboxingFlagSet::SANDBOXED_PRESENTATION_BROWSING_CONTEXT_FLAG,
_ =>
SandboxingFlagSet::empty(),
};
output.remove(remove);
}
output
}
96 changes: 96 additions & 0 deletions tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,102 @@ test_should_request_be_blocked!{
policy: "default-src www.notriddle2.com",
dest: Xslt,
result: Blocked),
( name: pre_request_child_src_worker_allow,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Worker,
result: Allowed),
( name: pre_request_child_src_worker_block,
url: "https://www.evil.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Worker,
result: Blocked),
( name: pre_request_child_src_worker_data_block,
url: "data:application/javascript,xssattack",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Worker,
result: Blocked),
( name: pre_request_child_src_worker_none_block,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src 'none'",
dest: Worker,
result: Blocked),
( name: pre_request_child_src_serviceworker_allow,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: ServiceWorker,
result: Allowed),
( name: pre_request_child_src_serviceworker_block,
url: "https://www.evil.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: ServiceWorker,
result: Blocked),
( name: pre_request_child_src_serviceworker_data_block,
url: "data:application/javascript,xssattack",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: ServiceWorker,
result: Blocked),
( name: pre_request_child_src_serviceworker_none_block,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src 'none'",
dest: ServiceWorker,
result: Blocked),
( name: pre_request_child_src_sharedworker_allow,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: SharedWorker,
result: Allowed),
( name: pre_request_child_src_sharedworker_block,
url: "https://www.evil.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: SharedWorker,
result: Blocked),
( name: pre_request_child_src_sharedworker_data_block,
url: "data:application/javascript,xssattack",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: SharedWorker,
result: Blocked),
( name: pre_request_child_src_sharedworker_none_block,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src 'none'",
dest: SharedWorker,
result: Blocked),
( name: pre_request_child_src_document_allow,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Document,
result: Allowed),
( name: pre_request_child_src_document_block,
url: "https://www.evil.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Document,
result: Blocked),
( name: pre_request_child_src_document_data_block,
url: "data:application/javascript,xssattack",
origin: "https://www.notriddle.com",
policy: "child-src https://www.notriddle.com/",
dest: Document,
result: Blocked),
( name: pre_request_child_src_document_none_block,
url: "https://www.notriddle.com/worker.js",
origin: "https://www.notriddle.com",
policy: "child-src 'none'",
dest: Document,
result: Blocked),
}

macro_rules! test_should_elements_inline_type_behavior_be_blocked {
Expand Down
83 changes: 83 additions & 0 deletions tests/sandbox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
extern crate content_security_policy;
use content_security_policy::*;
#[test]
fn sandbox_test_block() {
let csp_list = CspList::parse("sandbox", PolicySource::Header, PolicyDisposition::Enforce);
let (check_result, _) = csp_list.should_response_to_request_be_blocked(
&Request {
url: Url::parse("https://www.notriddle.com").unwrap(),
origin: Url::parse("https://www.notriddle.com").unwrap().origin(),
redirect_count: 0,
destination: Destination::Worker,
initiator: Initiator::None,
nonce: String::new(),
integrity_metadata: String::new(),
parser_metadata: ParserMetadata::None,
},
&Response {
csp_list: csp_list.clone(),
}
);
assert_eq!(check_result, CheckResult::Blocked);
}
#[test]
fn sandbox_test_block_with_allow_popups() {
let csp_list = CspList::parse("sandbox allow-popups", PolicySource::Header, PolicyDisposition::Enforce);
let (check_result, _) = csp_list.should_response_to_request_be_blocked(
&Request {
url: Url::parse("https://www.notriddle.com").unwrap(),
origin: Url::parse("https://www.notriddle.com").unwrap().origin(),
redirect_count: 0,
destination: Destination::Worker,
initiator: Initiator::None,
nonce: String::new(),
integrity_metadata: String::new(),
parser_metadata: ParserMetadata::None,
},
&Response {
csp_list: csp_list.clone(),
}
);
assert_eq!(check_result, CheckResult::Blocked);
}
#[test]
fn sandbox_test_allow_with_no_directive() {
let csp_list = CspList::parse("", PolicySource::Header, PolicyDisposition::Enforce);
let (check_result, _) = csp_list.should_response_to_request_be_blocked(
&Request {
url: Url::parse("https://www.notriddle.com").unwrap(),
origin: Url::parse("https://www.notriddle.com").unwrap().origin(),
redirect_count: 0,
destination: Destination::Worker,
initiator: Initiator::None,
nonce: String::new(),
integrity_metadata: String::new(),
parser_metadata: ParserMetadata::None,
},
&Response {
csp_list: csp_list.clone(),
}
);
assert_eq!(check_result, CheckResult::Allowed);
}

#[test]
fn sandbox_test_allow_images() {
let csp_list = CspList::parse("sandbox", PolicySource::Header, PolicyDisposition::Enforce);
let (check_result, _) = csp_list.should_response_to_request_be_blocked(
&Request {
url: Url::parse("https://www.notriddle.com").unwrap(),
origin: Url::parse("https://www.notriddle.com").unwrap().origin(),
redirect_count: 0,
destination: Destination::Image,
initiator: Initiator::None,
nonce: String::new(),
integrity_metadata: String::new(),
parser_metadata: ParserMetadata::None,
},
&Response {
csp_list: csp_list.clone(),
}
);
assert_eq!(check_result, CheckResult::Allowed);
}

0 comments on commit c91b403

Please sign in to comment.