mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Check all ancestor navigable trustworthiness for mixed content (#36157)
Propagate through documents a flag that represents if any of the ancestor navigables has a potentially trustworthy origin. The "potentially trustworthy origin" concept appears to have gotten confused in a couple of places and we were instead testing if a URL had "potentially trustworthy" properties. The main test for the ancestor navigables is [mixed-content/nested-iframes](https://github.com/web-platform-tests/wpt/blob/master/mixed-content/nested-iframes.window.js) --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #36108 <!-- Either: --> - [X] There are tests for these changes --------- Signed-off-by: Sebastian C <sebsebmc@gmail.com>
This commit is contained in:
parent
478e876f6d
commit
76edcff202
84 changed files with 384 additions and 525 deletions
|
@ -34,7 +34,7 @@ use net_traits::{
|
|||
use rustls_pki_types::CertificateDer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use servo_url::{Host, ServoUrl};
|
||||
use servo_url::{Host, ImmutableOrigin, ServoUrl};
|
||||
use tokio::sync::mpsc::{UnboundedReceiver as TokioReceiver, UnboundedSender as TokioSender};
|
||||
|
||||
use super::fetch_params::FetchParams;
|
||||
|
@ -278,7 +278,6 @@ pub async fn main_fetch(
|
|||
// Step 7. If should request be blocked due to a bad port, should fetching request be blocked
|
||||
// as mixed content, or should request be blocked by Content Security Policy returns blocked,
|
||||
// then set response to a network error.
|
||||
// TODO: check "should fetching request be blocked as mixed content"
|
||||
if should_request_be_blocked_by_csp(request, &policy_container) == csp::CheckResult::Blocked {
|
||||
warn!("Request blocked by CSP");
|
||||
response = Some(Response::network_error(NetworkError::Internal(
|
||||
|
@ -290,6 +289,11 @@ pub async fn main_fetch(
|
|||
"Request attempted on bad port".into(),
|
||||
)));
|
||||
}
|
||||
if should_request_be_blocked_as_mixed_content(request) {
|
||||
response = Some(Response::network_error(NetworkError::Internal(
|
||||
"Blocked as mixed content".into(),
|
||||
)));
|
||||
}
|
||||
|
||||
// Step 8: If request’s referrer policy is the empty string, then set request’s referrer policy
|
||||
// to request’s policy container’s referrer policy.
|
||||
|
@ -480,6 +484,8 @@ pub async fn main_fetch(
|
|||
should_be_blocked_due_to_nosniff(request.destination, &response.headers);
|
||||
let should_replace_with_mime_type_error = !response_is_network_error &&
|
||||
should_be_blocked_due_to_mime_type(request.destination, &response.headers);
|
||||
let should_replace_with_mixed_content = !response_is_network_error &&
|
||||
should_response_be_blocked_as_mixed_content(request, &response);
|
||||
|
||||
// Step 15.
|
||||
let mut network_error_response = response
|
||||
|
@ -502,7 +508,7 @@ pub async fn main_fetch(
|
|||
}
|
||||
|
||||
// Step 19. If response is not a network error and any of the following returns blocked
|
||||
// TODO: * should internalResponse to request be blocked as mixed content
|
||||
// * should internalResponse to request be blocked as mixed content
|
||||
// TODO: * should internalResponse to request be blocked by Content Security Policy
|
||||
// * should internalResponse to request be blocked due to its MIME type
|
||||
// * should internalResponse to request be blocked due to nosniff
|
||||
|
@ -518,6 +524,10 @@ pub async fn main_fetch(
|
|||
blocked_error_response =
|
||||
Response::network_error(NetworkError::Internal("Blocked by mime type".into()));
|
||||
&blocked_error_response
|
||||
} else if should_replace_with_mixed_content {
|
||||
blocked_error_response =
|
||||
Response::network_error(NetworkError::Internal("Blocked as mixed content".into()));
|
||||
&blocked_error_response
|
||||
} else {
|
||||
internal_response
|
||||
};
|
||||
|
@ -525,7 +535,10 @@ pub async fn main_fetch(
|
|||
// Step 20. If response’s type is "opaque", internalResponse’s status is 206, internalResponse’s
|
||||
// range-requested flag is set, and request’s header list does not contain `Range`, then set
|
||||
// response and internalResponse to a network error.
|
||||
let internal_response = if response_type == ResponseType::Opaque &&
|
||||
// Also checking if internal response is a network error to prevent crash from attemtping to
|
||||
// read status of a network error if we blocked the request above.
|
||||
let internal_response = if !internal_response.is_network_error() &&
|
||||
response_type == ResponseType::Opaque &&
|
||||
internal_response.status.code() == StatusCode::PARTIAL_CONTENT &&
|
||||
internal_response.range_requested &&
|
||||
!request.headers.contains_key(RANGE)
|
||||
|
@ -914,6 +927,66 @@ pub fn should_request_be_blocked_due_to_a_bad_port(url: &ServoUrl) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-fetch>
|
||||
pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
|
||||
// Step 1. Return allowed if one or more of the following conditions are met:
|
||||
// 1.1. Does settings prohibit mixed security contexts?
|
||||
// returns "Does Not Restrict Mixed Security Contexts" when applied to request’s client.
|
||||
if do_settings_prohibit_mixed_security_contexts(request) ==
|
||||
MixedSecurityProhibited::NotProhibited
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.2. request’s URL is a potentially trustworthy URL.
|
||||
if request.url().is_potentially_trustworthy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.3. The user agent has been instructed to allow mixed content.
|
||||
|
||||
// 1.4. request’s destination is "document", and request’s target browsing context has
|
||||
// no parent browsing context.
|
||||
if request.destination == Destination::Document {
|
||||
// TODO: request's target browsing context has no parent browsing context
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-response>
|
||||
pub fn should_response_be_blocked_as_mixed_content(request: &Request, response: &Response) -> bool {
|
||||
// Step 1. Return allowed if one or more of the following conditions are met:
|
||||
// 1.1. Does settings prohibit mixed security contexts? returns Does Not Restrict Mixed Content
|
||||
// when applied to request’s client.
|
||||
if do_settings_prohibit_mixed_security_contexts(request) ==
|
||||
MixedSecurityProhibited::NotProhibited
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.2. response’s url is a potentially trustworthy URL.
|
||||
if response
|
||||
.actual_response()
|
||||
.url()
|
||||
.is_some_and(|response_url| response_url.is_potentially_trustworthy())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.3. TODO: The user agent has been instructed to allow mixed content.
|
||||
|
||||
// 1.4. request’s destination is "document", and request’s target browsing context
|
||||
// has no parent browsing context.
|
||||
if request.destination == Destination::Document {
|
||||
// TODO: if requests target browsing context has no parent browsing context
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// <https://fetch.spec.whatwg.org/#bad-port>
|
||||
fn is_bad_port(port: u16) -> bool {
|
||||
static BAD_PORTS: [u16; 78] = [
|
||||
|
@ -983,14 +1056,36 @@ fn should_upgrade_request_to_potentially_trustworty(
|
|||
request.insecure_requests_policy == InsecureRequestsPolicy::Upgrade
|
||||
}
|
||||
|
||||
// TODO : Needs to revisit
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MixedSecurityProhibited {
|
||||
Prohibited,
|
||||
NotProhibited,
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#categorize-settings-object>
|
||||
fn does_settings_prohibit_mixed_security_contexts(url: &ServoUrl) -> bool {
|
||||
if url.is_origin_trustworthy() {
|
||||
return true;
|
||||
fn do_settings_prohibit_mixed_security_contexts(request: &Request) -> MixedSecurityProhibited {
|
||||
if let Origin::Origin(ref origin) = request.origin {
|
||||
// Workers created from a data: url are secure if they were created from secure contexts
|
||||
let is_origin_data_url_worker = matches!(
|
||||
*origin,
|
||||
ImmutableOrigin::Opaque(servo_url::OpaqueOrigin::SecureWorkerFromDataUrl(_))
|
||||
);
|
||||
|
||||
// Step 1. If settings’ origin is a potentially trustworthy origin,
|
||||
// then return "Prohibits Mixed Security Contexts".
|
||||
if origin.is_potentially_trustworthy() || is_origin_data_url_worker {
|
||||
return MixedSecurityProhibited::Prohibited;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
// Step 2.2. For each navigable navigable in document’s ancestor navigables:
|
||||
// Step 2.2.1. If navigable’s active document's origin is a potentially trustworthy origin,
|
||||
// then return "Prohibits Mixed Security Contexts".
|
||||
if request.has_trustworthy_ancestor_origin {
|
||||
return MixedSecurityProhibited::Prohibited;
|
||||
}
|
||||
|
||||
MixedSecurityProhibited::NotProhibited
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#upgrade-algorithm>
|
||||
|
@ -1008,12 +1103,14 @@ fn should_upgrade_mixed_content_request(request: &Request) -> bool {
|
|||
}
|
||||
|
||||
// Step 1.3
|
||||
if !does_settings_prohibit_mixed_security_contexts(&url) {
|
||||
if do_settings_prohibit_mixed_security_contexts(request) ==
|
||||
MixedSecurityProhibited::NotProhibited
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 1.4 : request’s destination is not "image", "audio", or "video".
|
||||
if matches!(
|
||||
if !matches!(
|
||||
request.destination,
|
||||
Destination::Audio | Destination::Image | Destination::Video
|
||||
) {
|
||||
|
|
|
@ -1010,7 +1010,7 @@ pub async fn http_redirect_fetch(
|
|||
// Step 8: Increase request’s redirect count by 1.
|
||||
request.redirect_count += 1;
|
||||
|
||||
// Step 7
|
||||
// Step 9
|
||||
let same_origin = match request.origin {
|
||||
Origin::Origin(ref origin) => *origin == location_url.origin(),
|
||||
Origin::Client => panic!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue