Commit cf0425fc authored by Yifan Luo's avatar Yifan Luo Committed by Chromium LUCI CQ

[Trusted Types] Add warnings to require-trusted-types-for directive

Add warnings for empty/invalid require-trusted-types-for keywords in
CSP parser.

Bug: 1149293
Change-Id: I97d2daddba8ebad7eb34ffcbe8467e1e7d7bb9c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2575305
Commit-Queue: Yifan Luo <lyf@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarYifan Luo <lyf@chromium.org>
Reviewed-by: default avatarDaniel Vogelheim <vogelheim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836083}
parent 47281893
...@@ -732,17 +732,34 @@ std::vector<std::string> ParsePluginTypes( ...@@ -732,17 +732,34 @@ std::vector<std::string> ParsePluginTypes(
// Parse the 'required-trusted-types-for' directive. // Parse the 'required-trusted-types-for' directive.
// https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-csp-directive // https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-csp-directive
//
// TODO(https://crbug.com/1149293): Add a warning when parsing invalid values.
network::mojom::CSPRequireTrustedTypesFor ParseRequireTrustedTypesFor( network::mojom::CSPRequireTrustedTypesFor ParseRequireTrustedTypesFor(
base::StringPiece value) { base::StringPiece value,
std::vector<std::string>& parsing_errors) {
network::mojom::CSPRequireTrustedTypesFor out =
network::mojom::CSPRequireTrustedTypesFor::None;
for (const auto expression : base::SplitStringPiece( for (const auto expression : base::SplitStringPiece(
value, base::kWhitespaceASCII, base::TRIM_WHITESPACE, value, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) { base::SPLIT_WANT_NONEMPTY)) {
if (expression == "'script'") if (expression == "'script'") {
return network::mojom::CSPRequireTrustedTypesFor::Script; out = network::mojom::CSPRequireTrustedTypesFor::Script;
} else {
const char* hint = nullptr;
if (expression == "script" || expression == "scripts" ||
expression == "'scripts'") {
hint = " Did you mean 'script'?";
}
parsing_errors.emplace_back(base::StringPrintf(
"Invalid expression in 'require-trusted-types-for' "
"Content Security Policy directive: %s.%s\n",
expression.as_string().c_str(), hint));
}
} }
return network::mojom::CSPRequireTrustedTypesFor::None; if (out == network::mojom::CSPRequireTrustedTypesFor::None)
parsing_errors.emplace_back(base::StringPrintf(
"'require-trusted-types-for' Content Security Policy "
"directive is empty; The directive has no effect.\n"));
return out;
} }
// This implements tt-policy-name from // This implements tt-policy-name from
...@@ -968,7 +985,7 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header, ...@@ -968,7 +985,7 @@ void AddContentSecurityPolicyFromHeader(base::StringPiece header,
case CSPDirectiveName::RequireTrustedTypesFor: case CSPDirectiveName::RequireTrustedTypesFor:
out->require_trusted_types_for = out->require_trusted_types_for =
ParseRequireTrustedTypesFor(directive.second); ParseRequireTrustedTypesFor(directive.second, out->parsing_errors);
break; break;
case CSPDirectiveName::TrustedTypes: case CSPDirectiveName::TrustedTypes:
......
...@@ -697,26 +697,32 @@ TEST(ContentSecurityPolicy, ParsePluginTypes) { ...@@ -697,26 +697,32 @@ TEST(ContentSecurityPolicy, ParsePluginTypes) {
TEST(ContentSecurityPolicy, ParseRequireTrustedTypesFor) { TEST(ContentSecurityPolicy, ParseRequireTrustedTypesFor) {
struct { struct {
const char* input; const char* input;
const unsigned long errors;
network::mojom::CSPRequireTrustedTypesFor expected; network::mojom::CSPRequireTrustedTypesFor expected;
} cases[]{ } cases[]{
{ {
"", "",
1u,
network::mojom::CSPRequireTrustedTypesFor::None, network::mojom::CSPRequireTrustedTypesFor::None,
}, },
{ {
"'script'", "'script'",
0u,
network::mojom::CSPRequireTrustedTypesFor::Script, network::mojom::CSPRequireTrustedTypesFor::Script,
}, },
{ {
"'wasm' 'script'", "'wasm' 'script'",
1u,
network::mojom::CSPRequireTrustedTypesFor::Script, network::mojom::CSPRequireTrustedTypesFor::Script,
}, },
{ {
"'script' 'wasm' 'script'", "'script' 'wasm' 'script'",
1u,
network::mojom::CSPRequireTrustedTypesFor::Script, network::mojom::CSPRequireTrustedTypesFor::Script,
}, },
{ {
"'wasm'", "'wasm'",
2u,
network::mojom::CSPRequireTrustedTypesFor::None, network::mojom::CSPRequireTrustedTypesFor::None,
}, },
}; };
...@@ -729,7 +735,7 @@ TEST(ContentSecurityPolicy, ParseRequireTrustedTypesFor) { ...@@ -729,7 +735,7 @@ TEST(ContentSecurityPolicy, ParseRequireTrustedTypesFor) {
->raw_directives[mojom::CSPDirectiveName::RequireTrustedTypesFor], ->raw_directives[mojom::CSPDirectiveName::RequireTrustedTypesFor],
testCase.input); testCase.input);
EXPECT_EQ(policies[0]->directives.size(), 0u); EXPECT_EQ(policies[0]->directives.size(), 0u);
EXPECT_EQ(policies[0]->parsing_errors.size(), 0u); EXPECT_EQ(policies[0]->parsing_errors.size(), testCase.errors);
EXPECT_EQ(policies[0]->require_trusted_types_for, testCase.expected); EXPECT_EQ(policies[0]->require_trusted_types_for, testCase.expected);
} }
} }
......
...@@ -1312,6 +1312,29 @@ void ContentSecurityPolicy::ReportInvalidPluginTypes( ...@@ -1312,6 +1312,29 @@ void ContentSecurityPolicy::ReportInvalidPluginTypes(
LogToConsole(message); LogToConsole(message);
} }
void ContentSecurityPolicy::ReportInvalidRequireTrustedTypesFor(
const String& require_trusted_types_for) {
String message;
if (require_trusted_types_for.IsNull()) {
message =
"'require-trusted-types-for' Content Security Policy directive is "
"empty; The directive has no effect.\n";
} else {
const char* hint = "";
if (require_trusted_types_for == "script" ||
require_trusted_types_for == "scripts" ||
require_trusted_types_for == "'scripts'") {
hint = " Did you mean 'script'?";
}
message =
"Invalid expression in 'require-trusted-types-for' "
"Content Security Policy directive: " +
require_trusted_types_for + "." + hint + "\n";
}
LogToConsole(message, mojom::ConsoleMessageLevel::kWarning);
}
void ContentSecurityPolicy::ReportInvalidSandboxFlags( void ContentSecurityPolicy::ReportInvalidSandboxFlags(
const String& invalid_flags) { const String& invalid_flags) {
LogToConsole( LogToConsole(
......
...@@ -375,6 +375,7 @@ class CORE_EXPORT ContentSecurityPolicy final ...@@ -375,6 +375,7 @@ class CORE_EXPORT ContentSecurityPolicy final
const String& value, const String& value,
const char); const char);
void ReportInvalidPluginTypes(const String&); void ReportInvalidPluginTypes(const String&);
void ReportInvalidRequireTrustedTypesFor(const String&);
void ReportInvalidSandboxFlags(const String&); void ReportInvalidSandboxFlags(const String&);
void ReportInvalidSourceExpression(const String& directive_name, void ReportInvalidSourceExpression(const String& directive_name,
const String& source); const String& source);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "require_trusted_types_for_directive.h" #include "require_trusted_types_for_directive.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
namespace blink { namespace blink {
RequireTrustedTypesForDirective::RequireTrustedTypesForDirective( RequireTrustedTypesForDirective::RequireTrustedTypesForDirective(
...@@ -20,9 +22,13 @@ RequireTrustedTypesForDirective::RequireTrustedTypesForDirective( ...@@ -20,9 +22,13 @@ RequireTrustedTypesForDirective::RequireTrustedTypesForDirective(
// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-sink-group // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-sink-group
if (v == "'script'") { if (v == "'script'") {
require_trusted_types_for_script_ = true; require_trusted_types_for_script_ = true;
break; } else {
policy->ReportInvalidRequireTrustedTypesFor(v);
} }
} }
if (!require_trusted_types_for_script_) {
policy->ReportInvalidRequireTrustedTypesFor(String());
}
} }
bool RequireTrustedTypesForDirective::require() const { bool RequireTrustedTypesForDirective::require() const {
......
...@@ -21,8 +21,9 @@ TEST(RequireTrustedTypesForDirectiveTest, TestSinks) { ...@@ -21,8 +21,9 @@ TEST(RequireTrustedTypesForDirectiveTest, TestSinks) {
{"'script' 'script'", true}}; {"'script' 'script'", true}};
for (const auto& test_case : test_cases) { for (const auto& test_case : test_cases) {
RequireTrustedTypesForDirective directive("require-trusted-types-for", RequireTrustedTypesForDirective directive(
test_case.directive, nullptr); "require-trusted-types-for", test_case.directive,
MakeGarbageCollected<ContentSecurityPolicy>());
SCOPED_TRACE(testing::Message() << " require-trusted-types-for " SCOPED_TRACE(testing::Message() << " require-trusted-types-for "
<< test_case.directive << ";"); << test_case.directive << ";");
EXPECT_EQ(directive.require(), test_case.result); EXPECT_EQ(directive.require(), test_case.result);
......
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