Commit f400ffb7 authored by Andrey Lushnikov's avatar Andrey Lushnikov Committed by Commit Bot

DevTools: implement Page.setBypassCSP method

This patch implements a new method Page.setBypassCSP
that allows disabling content security policy for the given page.

R=dgozman, pfeldman

Change-Id: I29d55aa593c50a24c12fd8b98a8315387dff30b0
Reviewed-on: https://chromium-review.googlesource.com/996905
Commit-Queue: Andrey Lushnikov <lushnikov@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548598}
parent 3a73f86e
Tests that Page.setBypassCSP works for main frame.
Verify CSP works when set with <meta>
CSP bypassed: false
Verify CSP works when set with header
CSP bypassed: false
>> ENABLING CSP BYPASS <<
Verify CSP is bypassed when set with <meta>
CSP bypassed: true
Verify CSP is bypassed when set with header
CSP bypassed: true
Check bypass after cross-origin navigation
CSP bypassed: true
(async function(testRunner) {
const {page, session, dp} = await testRunner.startBlank(
`Tests that Page.setBypassCSP works for main frame.`);
await dp.Page.enable();
await dp.Runtime.enable();
testRunner.log('Verify CSP works when set with <meta>');
await page.navigate('./resources/csp.html');
await dumpCSPEnabled();
testRunner.log('Verify CSP works when set with header');
await page.navigate('./resources/csp.php');
await dumpCSPEnabled();
testRunner.log('\n>> ENABLING CSP BYPASS <<\n');
await dp.Page.setBypassCSP({ enabled: true });
testRunner.log('Verify CSP is bypassed when set with <meta>');
await page.navigate('./resources/csp.html');
await dumpCSPEnabled();
testRunner.log('Verify CSP is bypassed when set with header');
await page.navigate('./resources/csp.php');
await dumpCSPEnabled();
testRunner.log('Check bypass after cross-origin navigation');
await page.navigate('http://127.0.0.1:8000/inspector-protocol/page/resources/csp.php');
await page.navigate('https://127.0.0.1:8443/inspector-protocol/page/resources/csp.php');
await dumpCSPEnabled();
testRunner.completeTest();
async function dumpCSPEnabled() {
const message = await dp.Runtime.evaluate({ expression: 'window.__injected' });
testRunner.log(' CSP bypassed: ' + (message.result.result.value === 42));
}
})
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
<script type="text/javascript">window.__injected = 42;</script>
<?php
ob_start();
header("Content-Security-Policy: default-src 'self'");
echo "<script type='text/javascript'>window.__injected = 42;</script>";
...@@ -77,6 +77,8 @@ var TestRunner = class { ...@@ -77,6 +77,8 @@ var TestRunner = class {
} }
url(relative) { url(relative) {
if (relative.startsWith('http://') || relative.startsWith('https://'))
return relative;
return this._baseURL + relative; return this._baseURL + relative;
} }
......
...@@ -70,6 +70,9 @@ class CORE_EXPORT Settings { ...@@ -70,6 +70,9 @@ class CORE_EXPORT Settings {
void SetTextAutosizingEnabled(bool); void SetTextAutosizingEnabled(bool);
bool TextAutosizingEnabled() const { return text_autosizing_enabled_; } bool TextAutosizingEnabled() const { return text_autosizing_enabled_; }
void SetBypassCSP(bool enabled) { bypass_csp_ = enabled; }
bool BypassCSP() const { return bypass_csp_; }
// Only set by Layout Tests, and only used if textAutosizingEnabled() returns // Only set by Layout Tests, and only used if textAutosizingEnabled() returns
// true. // true.
void SetTextAutosizingWindowSizeOverride(const IntSize&); void SetTextAutosizingWindowSizeOverride(const IntSize&);
...@@ -105,6 +108,7 @@ class CORE_EXPORT Settings { ...@@ -105,6 +108,7 @@ class CORE_EXPORT Settings {
// use counter via the shadow page. Once blink side use counter is removed, // use counter via the shadow page. Once blink side use counter is removed,
// this flag is no longer needed (crbug.com/811948). // this flag is no longer needed (crbug.com/811948).
bool is_shadow_page_; bool is_shadow_page_;
bool bypass_csp_ = false;
SETTINGS_MEMBER_VARIABLES SETTINGS_MEMBER_VARIABLES
......
...@@ -87,6 +87,7 @@ static const char kPageAgentScriptsToEvaluateOnLoad[] = ...@@ -87,6 +87,7 @@ static const char kPageAgentScriptsToEvaluateOnLoad[] =
"pageAgentScriptsToEvaluateOnLoad"; "pageAgentScriptsToEvaluateOnLoad";
static const char kScreencastEnabled[] = "screencastEnabled"; static const char kScreencastEnabled[] = "screencastEnabled";
static const char kLifecycleEventsEnabled[] = "lifecycleEventsEnabled"; static const char kLifecycleEventsEnabled[] = "lifecycleEventsEnabled";
static const char kBypassCSPEnabled[] = "bypassCSPEnabled";
} }
namespace { namespace {
...@@ -458,6 +459,8 @@ InspectorPageAgent::InspectorPageAgent( ...@@ -458,6 +459,8 @@ InspectorPageAgent::InspectorPageAgent(
void InspectorPageAgent::Restore() { void InspectorPageAgent::Restore() {
if (state_->booleanProperty(PageAgentState::kPageAgentEnabled, false)) if (state_->booleanProperty(PageAgentState::kPageAgentEnabled, false))
enable(); enable();
if (state_->booleanProperty(PageAgentState::kBypassCSPEnabled, false))
setBypassCSP(true);
} }
Response InspectorPageAgent::enable() { Response InspectorPageAgent::enable() {
...@@ -751,6 +754,13 @@ void InspectorPageAgent::searchInResource( ...@@ -751,6 +754,13 @@ void InspectorPageAgent::searchInResource(
WTF::Passed(std::move(callback)))); WTF::Passed(std::move(callback))));
} }
Response InspectorPageAgent::setBypassCSP(bool enabled) {
LocalFrame* frame = inspected_frames_->Root();
frame->GetSettings()->SetBypassCSP(enabled);
state_->setBoolean(PageAgentState::kBypassCSPEnabled, enabled);
return Response::OK();
}
Response InspectorPageAgent::setDocumentContent(const String& frame_id, Response InspectorPageAgent::setDocumentContent(const String& frame_id,
const String& html) { const String& html) {
LocalFrame* frame = LocalFrame* frame =
......
...@@ -135,6 +135,8 @@ class CORE_EXPORT InspectorPageAgent final ...@@ -135,6 +135,8 @@ class CORE_EXPORT InspectorPageAgent final
std::unique_ptr<SearchInResourceCallback>) override; std::unique_ptr<SearchInResourceCallback>) override;
protocol::Response setDocumentContent(const String& frame_id, protocol::Response setDocumentContent(const String& frame_id,
const String& html) override; const String& html) override;
protocol::Response setBypassCSP(bool enabled) override;
protocol::Response startScreencast(Maybe<String> format, protocol::Response startScreencast(Maybe<String> format,
Maybe<int> quality, Maybe<int> quality,
Maybe<int> max_width, Maybe<int> max_width,
......
...@@ -10380,6 +10380,18 @@ ...@@ -10380,6 +10380,18 @@
} }
] ]
}, },
{
"name": "setBypassCSP",
"description": "Enable page Content Security Policy by-passing.",
"experimental": true,
"parameters": [
{
"name": "enabled",
"description": "Whether to bypass page CSP.",
"type": "boolean"
}
]
},
{ {
"name": "setDeviceMetricsOverride", "name": "setDeviceMetricsOverride",
"description": "Overrides the values of device screen dimensions (window.screen.width, window.screen.height,\nwindow.innerWidth, window.innerHeight, and \"device-width\"/\"device-height\"-related CSS media\nquery results).", "description": "Overrides the values of device screen dimensions (window.screen.width, window.screen.height,\nwindow.innerWidth, window.innerHeight, and \"device-width\"/\"device-height\"-related CSS media\nquery results).",
......
...@@ -4751,6 +4751,12 @@ domain Page ...@@ -4751,6 +4751,12 @@ domain Page
# Whether to block ads. # Whether to block ads.
boolean enabled boolean enabled
# Enable page Content Security Policy by-passing.
experimental command setBypassCSP
parameters
# Whether to bypass page CSP.
boolean enabled
# Overrides the values of device screen dimensions (window.screen.width, window.screen.height, # Overrides the values of device screen dimensions (window.screen.width, window.screen.height,
# window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media # window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media
# query results). # query results).
......
...@@ -601,14 +601,17 @@ void DocumentLoader::ResponseReceived( ...@@ -601,14 +601,17 @@ void DocumentLoader::ResponseReceived(
content_security_policy_ = ContentSecurityPolicy::Create(); content_security_policy_ = ContentSecurityPolicy::Create();
content_security_policy_->SetOverrideURLForSelf(response.Url()); content_security_policy_->SetOverrideURLForSelf(response.Url());
if (!frame_->GetSettings()->BypassCSP()) {
content_security_policy_->DidReceiveHeaders( content_security_policy_->DidReceiveHeaders(
ContentSecurityPolicyResponseHeaders(response)); ContentSecurityPolicyResponseHeaders(response));
}
if (!content_security_policy_->AllowAncestors(frame_, response.Url())) { if (!content_security_policy_->AllowAncestors(frame_, response.Url())) {
CancelLoadAfterCSPDenied(response); CancelLoadAfterCSPDenied(response);
return; return;
} }
if (RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() && if (!frame_->GetSettings()->BypassCSP() &&
RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() &&
!GetFrameLoader().RequiredCSP().IsEmpty()) { !GetFrameLoader().RequiredCSP().IsEmpty()) {
const SecurityOrigin* parent_security_origin = const SecurityOrigin* parent_security_origin =
frame_->Tree().Parent()->GetSecurityContext()->GetSecurityOrigin(); frame_->Tree().Parent()->GetSecurityContext()->GetSecurityOrigin();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "core/dom/ScriptableDocumentParser.h" #include "core/dom/ScriptableDocumentParser.h"
#include "core/frame/Deprecation.h" #include "core/frame/Deprecation.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/frame/UseCounter.h" #include "core/frame/UseCounter.h"
#include "core/frame/csp/ContentSecurityPolicy.h" #include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/inspector/ConsoleMessage.h" #include "core/inspector/ConsoleMessage.h"
...@@ -67,6 +68,8 @@ void HttpEquiv::ProcessHttpEquivContentSecurityPolicy( ...@@ -67,6 +68,8 @@ void HttpEquiv::ProcessHttpEquivContentSecurityPolicy(
const AtomicString& content) { const AtomicString& content) {
if (document.ImportLoader()) if (document.ImportLoader())
return; return;
if (document.GetSettings() && document.GetSettings()->BypassCSP())
return;
if (EqualIgnoringASCIICase(equiv, "content-security-policy")) { if (EqualIgnoringASCIICase(equiv, "content-security-policy")) {
document.GetContentSecurityPolicy()->DidReceiveHeader( document.GetContentSecurityPolicy()->DidReceiveHeader(
content, kContentSecurityPolicyHeaderTypeEnforce, content, kContentSecurityPolicyHeaderTypeEnforce,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment