mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Initial support for marking custom protocol secure (#36656)
Add initial support for marking custom protocol as secure, this makes it possible to `fetch` a custom protocol inside secure contexts (e.g. http://localhost) Some additional contexts: - [#embedding > Custom protocol secure context](https://servo.zulipchat.com/#narrow/channel/437943-embedding/topic/Custom.20protocol.20secure.20context) - https://github.com/versotile-org/tauri-runtime-verso/issues/6#issuecomment-2820776128 Testing: use `fetch('urlinfo://abc').then(async (response) => console.log(await response.text())).catch(console.log)` in servoshell with in a secure context (e.g. https://servo.org), and see the response should not be an error --------- Signed-off-by: Tony <legendmastertony@gmail.com> Signed-off-by: Tony <68118705+Legend-Master@users.noreply.github.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
cf59aa1948
commit
894fbd003d
3 changed files with 56 additions and 16 deletions
|
@ -42,7 +42,7 @@ use crate::fetch::cors_cache::CorsCache;
|
|||
use crate::fetch::headers::determine_nosniff;
|
||||
use crate::filemanager_thread::FileManager;
|
||||
use crate::http_loader::{HttpState, determine_requests_referrer, http_fetch, set_default_accept};
|
||||
use crate::protocols::ProtocolRegistry;
|
||||
use crate::protocols::{ProtocolRegistry, is_url_potentially_trustworthy};
|
||||
use crate::request_interceptor::RequestInterceptor;
|
||||
use crate::subresource_integrity::is_response_integrity_valid;
|
||||
|
||||
|
@ -247,7 +247,7 @@ pub async fn main_fetch(
|
|||
|
||||
// Step 4. Upgrade request to a potentially trustworthy URL, if appropriate.
|
||||
if should_upgrade_request_to_potentially_trustworty(request, context) ||
|
||||
should_upgrade_mixed_content_request(request)
|
||||
should_upgrade_mixed_content_request(request, &context.protocols)
|
||||
{
|
||||
trace!(
|
||||
"upgrading {} targeting {:?}",
|
||||
|
@ -294,7 +294,7 @@ pub async fn main_fetch(
|
|||
"Request attempted on bad port".into(),
|
||||
)));
|
||||
}
|
||||
if should_request_be_blocked_as_mixed_content(request) {
|
||||
if should_request_be_blocked_as_mixed_content(request, &context.protocols) {
|
||||
response = Some(Response::network_error(NetworkError::Internal(
|
||||
"Blocked as mixed content".into(),
|
||||
)));
|
||||
|
@ -359,13 +359,16 @@ pub async fn main_fetch(
|
|||
if (same_origin && request.response_tainting == ResponseTainting::Basic) ||
|
||||
// request's current URL's scheme is "data"
|
||||
current_scheme == "data" ||
|
||||
// Note: Although it is not part of the specification, we make an exception here
|
||||
// for custom protocols that are explicitly marked as active for fetch.
|
||||
context.protocols.is_fetchable(current_scheme) ||
|
||||
// request's mode is "navigate" or "websocket"
|
||||
matches!(
|
||||
request.mode,
|
||||
RequestMode::Navigate | RequestMode::WebSocket { .. }
|
||||
)
|
||||
{
|
||||
// Substep 1. Set request’s response tainting to "basic".
|
||||
// Substep 1. Set request's response tainting to "basic".
|
||||
request.response_tainting = ResponseTainting::Basic;
|
||||
|
||||
// Substep 2. Return the result of running scheme fetch given fetchParams.
|
||||
|
@ -373,13 +376,13 @@ pub async fn main_fetch(
|
|||
} else if request.mode == RequestMode::SameOrigin {
|
||||
Response::network_error(NetworkError::Internal("Cross-origin response".into()))
|
||||
} else if request.mode == RequestMode::NoCors {
|
||||
// Substep 1. If request’s redirect mode is not "follow", then return a network error.
|
||||
// Substep 1. If request's redirect mode is not "follow", then return a network error.
|
||||
if request.redirect_mode != RedirectMode::Follow {
|
||||
Response::network_error(NetworkError::Internal(
|
||||
"NoCors requests must follow redirects".into(),
|
||||
))
|
||||
} else {
|
||||
// Substep 2. Set request’s response tainting to "opaque".
|
||||
// Substep 2. Set request's response tainting to "opaque".
|
||||
request.response_tainting = ResponseTainting::Opaque;
|
||||
|
||||
// Substep 3. Return the result of running scheme fetch given fetchParams.
|
||||
|
@ -490,7 +493,7 @@ pub async fn main_fetch(
|
|||
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);
|
||||
should_response_be_blocked_as_mixed_content(request, &response, &context.protocols);
|
||||
|
||||
// Step 15.
|
||||
let mut network_error_response = response
|
||||
|
@ -933,7 +936,10 @@ pub fn should_request_be_blocked_due_to_a_bad_port(url: &ServoUrl) -> bool {
|
|||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-fetch>
|
||||
pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
|
||||
pub fn should_request_be_blocked_as_mixed_content(
|
||||
request: &Request,
|
||||
protocol_registry: &ProtocolRegistry,
|
||||
) -> 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.
|
||||
|
@ -944,7 +950,7 @@ pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
|
|||
}
|
||||
|
||||
// 1.2. request’s URL is a potentially trustworthy URL.
|
||||
if request.url().is_potentially_trustworthy() {
|
||||
if is_url_potentially_trustworthy(protocol_registry, &request.url()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -961,7 +967,11 @@ pub fn should_request_be_blocked_as_mixed_content(request: &Request) -> bool {
|
|||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#should-block-response>
|
||||
pub fn should_response_be_blocked_as_mixed_content(request: &Request, response: &Response) -> bool {
|
||||
pub fn should_response_be_blocked_as_mixed_content(
|
||||
request: &Request,
|
||||
response: &Response,
|
||||
protocol_registry: &ProtocolRegistry,
|
||||
) -> 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.
|
||||
|
@ -975,7 +985,7 @@ pub fn should_response_be_blocked_as_mixed_content(request: &Request, response:
|
|||
if response
|
||||
.actual_response()
|
||||
.url()
|
||||
.is_some_and(|response_url| response_url.is_potentially_trustworthy())
|
||||
.is_some_and(|response_url| is_url_potentially_trustworthy(protocol_registry, response_url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1041,7 +1051,7 @@ fn should_upgrade_request_to_potentially_trustworty(
|
|||
// request’s header list if any of the following criteria are met:
|
||||
// * request’s URL is not a potentially trustworthy URL
|
||||
// * request’s URL's host is not a preloadable HSTS host
|
||||
if !request.current_url().is_potentially_trustworthy() ||
|
||||
if !is_url_potentially_trustworthy(&context.protocols, &request.current_url()) ||
|
||||
!request.current_url().host_str().is_some_and(|host| {
|
||||
!context.state.hsts_list.read().unwrap().is_host_secure(host)
|
||||
})
|
||||
|
@ -1094,10 +1104,13 @@ fn do_settings_prohibit_mixed_security_contexts(request: &Request) -> MixedSecur
|
|||
}
|
||||
|
||||
/// <https://w3c.github.io/webappsec-mixed-content/#upgrade-algorithm>
|
||||
fn should_upgrade_mixed_content_request(request: &Request) -> bool {
|
||||
fn should_upgrade_mixed_content_request(
|
||||
request: &Request,
|
||||
protocol_registry: &ProtocolRegistry,
|
||||
) -> bool {
|
||||
let url = request.url();
|
||||
// Step 1.1 : request’s URL is a potentially trustworthy URL.
|
||||
if url.is_potentially_trustworthy() {
|
||||
if is_url_potentially_trustworthy(protocol_registry, &url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use log::error;
|
|||
use net_traits::filemanager_thread::RelativePos;
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::Response;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
use crate::fetch::methods::{DoneChannel, FetchContext, RangeRequestBounds};
|
||||
|
||||
|
@ -47,6 +48,15 @@ pub trait ProtocolHandler: Send + Sync {
|
|||
fn is_fetchable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Specify if this custom protocol can be used in a [secure context]
|
||||
///
|
||||
/// Note: this only works for bypassing mixed content checks right now
|
||||
///
|
||||
/// [secure context]: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts
|
||||
fn is_secure(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -114,9 +124,22 @@ impl ProtocolRegistry {
|
|||
pub fn is_fetchable(&self, scheme: &str) -> bool {
|
||||
self.handlers
|
||||
.get(scheme)
|
||||
.map(|handler| handler.is_fetchable())
|
||||
.unwrap_or(false)
|
||||
.is_some_and(|handler| handler.is_fetchable())
|
||||
}
|
||||
|
||||
pub fn is_secure(&self, scheme: &str) -> bool {
|
||||
self.handlers
|
||||
.get(scheme)
|
||||
.is_some_and(|handler| handler.is_secure())
|
||||
}
|
||||
}
|
||||
|
||||
/// Test if the URL is potentially trustworthy or the custom protocol is registered as secure
|
||||
pub fn is_url_potentially_trustworthy(
|
||||
protocol_registry: &ProtocolRegistry,
|
||||
url: &ServoUrl,
|
||||
) -> bool {
|
||||
url.is_potentially_trustworthy() || protocol_registry.is_secure(url.scheme())
|
||||
}
|
||||
|
||||
pub fn range_not_satisfiable_error(response: &mut Response) {
|
||||
|
|
|
@ -46,4 +46,8 @@ impl ProtocolHandler for UrlInfoProtocolHander {
|
|||
fn is_fetchable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_secure(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue