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 {
}
url(relative) {
if (relative.startsWith('http://') || relative.startsWith('https://'))
return relative;
return this._baseURL + relative;
}
......
......@@ -70,6 +70,9 @@ class CORE_EXPORT Settings {
void SetTextAutosizingEnabled(bool);
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
// true.
void SetTextAutosizingWindowSizeOverride(const IntSize&);
......@@ -105,6 +108,7 @@ class CORE_EXPORT Settings {
// use counter via the shadow page. Once blink side use counter is removed,
// this flag is no longer needed (crbug.com/811948).
bool is_shadow_page_;
bool bypass_csp_ = false;
SETTINGS_MEMBER_VARIABLES
......
......@@ -87,6 +87,7 @@ static const char kPageAgentScriptsToEvaluateOnLoad[] =
"pageAgentScriptsToEvaluateOnLoad";
static const char kScreencastEnabled[] = "screencastEnabled";
static const char kLifecycleEventsEnabled[] = "lifecycleEventsEnabled";
static const char kBypassCSPEnabled[] = "bypassCSPEnabled";
}
namespace {
......@@ -458,6 +459,8 @@ InspectorPageAgent::InspectorPageAgent(
void InspectorPageAgent::Restore() {
if (state_->booleanProperty(PageAgentState::kPageAgentEnabled, false))
enable();
if (state_->booleanProperty(PageAgentState::kBypassCSPEnabled, false))
setBypassCSP(true);
}
Response InspectorPageAgent::enable() {
......@@ -751,6 +754,13 @@ void InspectorPageAgent::searchInResource(
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,
const String& html) {
LocalFrame* frame =
......
......@@ -135,6 +135,8 @@ class CORE_EXPORT InspectorPageAgent final
std::unique_ptr<SearchInResourceCallback>) override;
protocol::Response setDocumentContent(const String& frame_id,
const String& html) override;
protocol::Response setBypassCSP(bool enabled) override;
protocol::Response startScreencast(Maybe<String> format,
Maybe<int> quality,
Maybe<int> max_width,
......
......@@ -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",
"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
# Whether to block ads.
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,
# window.innerWidth, window.innerHeight, and "device-width"/"device-height"-related CSS media
# query results).
......
......@@ -601,14 +601,17 @@ void DocumentLoader::ResponseReceived(
content_security_policy_ = ContentSecurityPolicy::Create();
content_security_policy_->SetOverrideURLForSelf(response.Url());
content_security_policy_->DidReceiveHeaders(
ContentSecurityPolicyResponseHeaders(response));
if (!frame_->GetSettings()->BypassCSP()) {
content_security_policy_->DidReceiveHeaders(
ContentSecurityPolicyResponseHeaders(response));
}
if (!content_security_policy_->AllowAncestors(frame_, response.Url())) {
CancelLoadAfterCSPDenied(response);
return;
}
if (RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() &&
if (!frame_->GetSettings()->BypassCSP() &&
RuntimeEnabledFeatures::EmbedderCSPEnforcementEnabled() &&
!GetFrameLoader().RequiredCSP().IsEmpty()) {
const SecurityOrigin* parent_security_origin =
frame_->Tree().Parent()->GetSecurityContext()->GetSecurityOrigin();
......
......@@ -9,6 +9,7 @@
#include "core/dom/ScriptableDocumentParser.h"
#include "core/frame/Deprecation.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/frame/UseCounter.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "core/inspector/ConsoleMessage.h"
......@@ -67,6 +68,8 @@ void HttpEquiv::ProcessHttpEquivContentSecurityPolicy(
const AtomicString& content) {
if (document.ImportLoader())
return;
if (document.GetSettings() && document.GetSettings()->BypassCSP())
return;
if (EqualIgnoringASCIICase(equiv, "content-security-policy")) {
document.GetContentSecurityPolicy()->DidReceiveHeader(
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