Commit 0b4e8879 authored by Michael van Ouwerkerk's avatar Michael van Ouwerkerk Committed by Commit Bot

Check image url against allowlist from feature param.

Bug: 1018138
Change-Id: Ia6ede078dc04cc80fcc21450b22e0513c6da249f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1919139
Commit-Queue: Michael van Ouwerkerk <mvanouwerkerk@chromium.org>
Reviewed-by: default avatarRichard Knoll <knollr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715707}
parent 2cea560e
...@@ -14,5 +14,8 @@ const base::Feature kSharedClipboardUI{"SharedClipboardUI", ...@@ -14,5 +14,8 @@ const base::Feature kSharedClipboardUI{"SharedClipboardUI",
defined(OS_CHROMEOS) defined(OS_CHROMEOS)
const base::Feature kRemoteCopyReceiver{"RemoteCopyReceiver", const base::Feature kRemoteCopyReceiver{"RemoteCopyReceiver",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
const base::FeatureParam<std::string> kRemoteCopyAllowedOrigins = {
&kRemoteCopyReceiver, "RemoteCopyAllowedOrigins", ""};
#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || #endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS) // defined(OS_CHROMEOS)
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
#ifndef CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_FEATURE_FLAGS_H_ #ifndef CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_FEATURE_FLAGS_H_
#define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_FEATURE_FLAGS_H_ #define CHROME_BROWSER_SHARING_SHARED_CLIPBOARD_FEATURE_FLAGS_H_
#include <string>
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "build/build_config.h" #include "build/build_config.h"
// Feature to allow devices to receive the shared clipboard message. // Feature to allow devices to receive the shared clipboard message.
...@@ -18,6 +21,9 @@ extern const base::Feature kSharedClipboardUI; ...@@ -18,6 +21,9 @@ extern const base::Feature kSharedClipboardUI;
defined(OS_CHROMEOS) defined(OS_CHROMEOS)
// Feature to enable handling remote copy messages. // Feature to enable handling remote copy messages.
extern const base::Feature kRemoteCopyReceiver; extern const base::Feature kRemoteCopyReceiver;
// List of allowed origins to fetch images from, comma separated.
extern const base::FeatureParam<std::string> kRemoteCopyAllowedOrigins;
#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || #endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS) // defined(OS_CHROMEOS)
......
...@@ -66,14 +66,6 @@ class RemoteCopyBrowserTestBase : public InProcessBrowserTest { ...@@ -66,14 +66,6 @@ class RemoteCopyBrowserTestBase : public InProcessBrowserTest {
ui::Clipboard::DestroyClipboardForCurrentThread(); ui::Clipboard::DestroyClipboardForCurrentThread();
} }
GURL StartServerAndGetURL(const std::string& relative_url) {
server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTP);
server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
EXPECT_TRUE(server_->Start());
return server_->GetURL(relative_url);
}
gcm::IncomingMessage CreateMessage(const std::string& device_name, gcm::IncomingMessage CreateMessage(const std::string& device_name,
base::Optional<std::string> text, base::Optional<std::string> text,
base::Optional<GURL> image_url) { base::Optional<GURL> image_url) {
...@@ -174,7 +166,15 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyDisabledBrowserTest, FeatureDisabled) { ...@@ -174,7 +166,15 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyDisabledBrowserTest, FeatureDisabled) {
class RemoteCopyBrowserTest : public RemoteCopyBrowserTestBase { class RemoteCopyBrowserTest : public RemoteCopyBrowserTestBase {
public: public:
RemoteCopyBrowserTest() { RemoteCopyBrowserTest() {
feature_list_.InitAndEnableFeature(kRemoteCopyReceiver); server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTP);
server_->ServeFilesFromSourceDirectory(GetChromeTestDataDir());
EXPECT_TRUE(server_->Start());
url::Origin allowlist_origin = url::Origin::Create(server_->base_url());
feature_list_.InitAndEnableFeatureWithParameters(
kRemoteCopyReceiver,
{{kRemoteCopyAllowedOrigins.name, allowlist_origin.Serialize()}});
} }
}; };
...@@ -201,8 +201,7 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyBrowserTest, ImageUrl) { ...@@ -201,8 +201,7 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyBrowserTest, ImageUrl) {
ASSERT_TRUE(GetAvailableClipboardTypes().empty()); ASSERT_TRUE(GetAvailableClipboardTypes().empty());
// Send a message with an image url. // Send a message with an image url.
SendImageMessage(kDeviceName, SendImageMessage(kDeviceName, server_->GetURL("/image_decoding/droids.jpg"));
StartServerAndGetURL("/image_decoding/droids.jpg"));
// The image is in the clipboard and a notification is shown. // The image is in the clipboard and a notification is shown.
std::vector<base::string16> types = GetAvailableClipboardTypes(); std::vector<base::string16> types = GetAvailableClipboardTypes();
...@@ -232,8 +231,7 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyBrowserTest, TextThenImageUrl) { ...@@ -232,8 +231,7 @@ IN_PROC_BROWSER_TEST_F(RemoteCopyBrowserTest, TextThenImageUrl) {
ASSERT_EQ(kText, ReadClipboardText()); ASSERT_EQ(kText, ReadClipboardText());
// Send a message with an image url. // Send a message with an image url.
SendImageMessage(kDeviceName, SendImageMessage(kDeviceName, server_->GetURL("/image_decoding/droids.jpg"));
StartServerAndGetURL("/image_decoding/droids.jpg"));
// The image is in the clipboard and the text has been cleared. // The image is in the clipboard and the text has been cleared.
types = GetAvailableClipboardTypes(); types = GetAvailableClipboardTypes();
......
...@@ -4,15 +4,17 @@ ...@@ -4,15 +4,17 @@
#include "chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h" #include "chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h"
#include <memory> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/guid.h" #include "base/guid.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/notifications/notification_display_service.h" #include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_display_service_factory.h" #include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/sync/protocol/sharing_message.pb.h" #include "components/sync/protocol/sharing_message.pb.h"
#include "components/sync/protocol/sharing_remote_copy_message.pb.h" #include "components/sync/protocol/sharing_remote_copy_message.pb.h"
...@@ -29,7 +31,7 @@ ...@@ -29,7 +31,7 @@
#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/public/cpp/notification_types.h"
#include "ui/message_center/public/cpp/notifier_id.h" #include "ui/message_center/public/cpp/notifier_id.h"
#include "url/gurl.h" #include "url/origin.h"
namespace { namespace {
const net::NetworkTrafficAnnotationTag kTrafficAnnotation = const net::NetworkTrafficAnnotationTag kTrafficAnnotation =
...@@ -100,12 +102,17 @@ void RemoteCopyMessageHandler::HandleText(const std::string& text) { ...@@ -100,12 +102,17 @@ void RemoteCopyMessageHandler::HandleText(const std::string& text) {
void RemoteCopyMessageHandler::HandleImage(const std::string& image_url) { void RemoteCopyMessageHandler::HandleImage(const std::string& image_url) {
GURL url(image_url); GURL url(image_url);
// TODO(mvanouwerkerk): Whitelist check.
if (!network::IsUrlPotentiallyTrustworthy(url)) { if (!network::IsUrlPotentiallyTrustworthy(url)) {
Finish(); Finish();
return; return;
} }
if (!IsOriginAllowed(url)) {
Finish();
return;
}
auto request = std::make_unique<network::ResourceRequest>(); auto request = std::make_unique<network::ResourceRequest>();
request->url = url; request->url = url;
// This request should be unauthenticated (no cookies), and shouldn't be // This request should be unauthenticated (no cookies), and shouldn't be
...@@ -124,6 +131,19 @@ void RemoteCopyMessageHandler::HandleImage(const std::string& image_url) { ...@@ -124,6 +131,19 @@ void RemoteCopyMessageHandler::HandleImage(const std::string& image_url) {
network::SimpleURLLoader::kMaxBoundedStringDownloadSize); network::SimpleURLLoader::kMaxBoundedStringDownloadSize);
} }
bool RemoteCopyMessageHandler::IsOriginAllowed(const GURL& image_url) {
url::Origin image_origin = url::Origin::Create(image_url);
std::vector<std::string> parts =
base::SplitString(kRemoteCopyAllowedOrigins.Get(), ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (const auto& part : parts) {
url::Origin allowed_origin = url::Origin::Create(GURL(part));
if (image_origin.IsSameOriginWith(allowed_origin))
return true;
}
return false;
}
void RemoteCopyMessageHandler::OnURLLoadComplete( void RemoteCopyMessageHandler::OnURLLoadComplete(
std::unique_ptr<std::string> content) { std::unique_ptr<std::string> content) {
url_loader_.reset(); url_loader_.reset();
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/image_decoder.h" #include "chrome/browser/image_decoder.h"
#include "chrome/browser/sharing/sharing_message_handler.h" #include "chrome/browser/sharing/sharing_message_handler.h"
#include "url/gurl.h"
class Profile; class Profile;
...@@ -33,6 +34,8 @@ class RemoteCopyMessageHandler : public SharingMessageHandler, ...@@ -33,6 +34,8 @@ class RemoteCopyMessageHandler : public SharingMessageHandler,
void OnImageDecoded(const SkBitmap& decoded_image) override; void OnImageDecoded(const SkBitmap& decoded_image) override;
void OnDecodeImageFailed() override; void OnDecodeImageFailed() override;
bool IsOriginAllowed(const GURL& image_url);
private: private:
void HandleText(const std::string& text); void HandleText(const std::string& text);
void HandleImage(const std::string& image_url); void HandleImage(const std::string& image_url);
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/guid.h" #include "base/guid.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_test_base.h" #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_test_base.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
...@@ -42,6 +44,14 @@ class RemoteCopyMessageHandlerTest : public SharedClipboardTestBase { ...@@ -42,6 +44,14 @@ class RemoteCopyMessageHandlerTest : public SharedClipboardTestBase {
return message; return message;
} }
bool IsOriginAllowed(const std::string& image_url,
const std::string& param_value) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeatureWithParameters(
kRemoteCopyReceiver, {{kRemoteCopyAllowedOrigins.name, param_value}});
return message_handler_->IsOriginAllowed(GURL(image_url));
}
protected: protected:
std::unique_ptr<RemoteCopyMessageHandler> message_handler_; std::unique_ptr<RemoteCopyMessageHandler> message_handler_;
...@@ -71,3 +81,16 @@ TEST_F(RemoteCopyMessageHandlerTest, NotificationWithDeviceName) { ...@@ -71,3 +81,16 @@ TEST_F(RemoteCopyMessageHandlerTest, NotificationWithDeviceName) {
base::ASCIIToUTF16(kDeviceNameInMessage)), base::ASCIIToUTF16(kDeviceNameInMessage)),
GetNotification().title()); GetNotification().title());
} }
TEST_F(RemoteCopyMessageHandlerTest, IsOriginAllowed) {
std::string image_url = "https://foo.com/image.png";
std::string image_url_with_subdomain = "https://www.foo.com/image.png";
std::string image_origin = "https://foo.com";
EXPECT_TRUE(IsOriginAllowed(image_url, image_origin));
EXPECT_FALSE(IsOriginAllowed(image_url_with_subdomain, image_origin));
EXPECT_FALSE(IsOriginAllowed(image_url, ""));
EXPECT_FALSE(IsOriginAllowed(image_url, "foo][#';/.,"));
EXPECT_FALSE(IsOriginAllowed(image_url, "https://bar.com"));
EXPECT_TRUE(IsOriginAllowed(image_url, image_origin + ",https://bar.com"));
EXPECT_TRUE(IsOriginAllowed(image_url, "https://bar.com," + image_origin));
}
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